summaryrefslogtreecommitdiffstats
path: root/binutils-2.25/gold
diff options
context:
space:
mode:
authorAndrew Hsieh <andrewhsieh@google.com>2014-06-13 12:38:00 -0700
committerAndrew Hsieh <andrewhsieh@google.com>2014-06-13 12:38:00 -0700
commit54f1b3cf509cd889905287cb8ce6c5ae33911a21 (patch)
treee39b1a7fa04db86a8215b7f9d4656d74e394aec0 /binutils-2.25/gold
parent2a6558a8ecfb81d75215b4ec7dc61113e12cfd5f (diff)
downloadtoolchain_binutils-54f1b3cf509cd889905287cb8ce6c5ae33911a21.tar.gz
toolchain_binutils-54f1b3cf509cd889905287cb8ce6c5ae33911a21.tar.bz2
toolchain_binutils-54f1b3cf509cd889905287cb8ce6c5ae33911a21.zip
Add upstream binutils-2.25 snapshot 4/4 2014
For MIPS -mmsa support Change-Id: I08c4f002fa7b33dec85ed75956e6ab551bb03c96
Diffstat (limited to 'binutils-2.25/gold')
-rw-r--r--binutils-2.25/gold/ChangeLog15224
-rw-r--r--binutils-2.25/gold/Makefile.am363
-rw-r--r--binutils-2.25/gold/Makefile.in1385
-rw-r--r--binutils-2.25/gold/NEWS11
-rw-r--r--binutils-2.25/gold/README69
-rw-r--r--binutils-2.25/gold/TODO26
-rw-r--r--binutils-2.25/gold/aclocal.m4992
-rw-r--r--binutils-2.25/gold/archive.cc1313
-rw-r--r--binutils-2.25/gold/archive.h571
-rw-r--r--binutils-2.25/gold/arm-reloc-property.cc333
-rw-r--r--binutils-2.25/gold/arm-reloc-property.h386
-rw-r--r--binutils-2.25/gold/arm-reloc.def194
-rw-r--r--binutils-2.25/gold/arm.cc12387
-rw-r--r--binutils-2.25/gold/attributes.cc458
-rw-r--r--binutils-2.25/gold/attributes.h406
-rw-r--r--binutils-2.25/gold/binary.cc363
-rw-r--r--binutils-2.25/gold/binary.h116
-rw-r--r--binutils-2.25/gold/common.cc365
-rw-r--r--binutils-2.25/gold/common.h67
-rw-r--r--binutils-2.25/gold/compressed_output.cc247
-rw-r--r--binutils-2.25/gold/compressed_output.h86
-rw-r--r--binutils-2.25/gold/config.in277
-rwxr-xr-xbinutils-2.25/gold/configure9195
-rw-r--r--binutils-2.25/gold/configure.ac619
-rw-r--r--binutils-2.25/gold/configure.tgt150
-rw-r--r--binutils-2.25/gold/copy-relocs.cc258
-rw-r--r--binutils-2.25/gold/copy-relocs.h156
-rw-r--r--binutils-2.25/gold/cref.cc407
-rw-r--r--binutils-2.25/gold/cref.h79
-rw-r--r--binutils-2.25/gold/debug.h80
-rw-r--r--binutils-2.25/gold/defstd.cc274
-rw-r--r--binutils-2.25/gold/defstd.h36
-rw-r--r--binutils-2.25/gold/descriptors.cc280
-rw-r--r--binutils-2.25/gold/descriptors.h117
-rw-r--r--binutils-2.25/gold/dirsearch.cc305
-rw-r--r--binutils-2.25/gold/dirsearch.h90
-rw-r--r--binutils-2.25/gold/dwarf_reader.cc2373
-rw-r--r--binutils-2.25/gold/dwarf_reader.h1117
-rw-r--r--binutils-2.25/gold/dwp.cc2224
-rw-r--r--binutils-2.25/gold/dwp.h120
-rw-r--r--binutils-2.25/gold/dynobj.cc1970
-rw-r--r--binutils-2.25/gold/dynobj.h672
-rw-r--r--binutils-2.25/gold/ehframe.cc1263
-rw-r--r--binutils-2.25/gold/ehframe.h517
-rw-r--r--binutils-2.25/gold/errors.cc420
-rw-r--r--binutils-2.25/gold/errors.h138
-rw-r--r--binutils-2.25/gold/expression.cc1273
-rw-r--r--binutils-2.25/gold/ffsll.c48
-rw-r--r--binutils-2.25/gold/fileread.cc1140
-rw-r--r--binutils-2.25/gold/fileread.h611
-rw-r--r--binutils-2.25/gold/freebsd.h103
-rw-r--r--binutils-2.25/gold/ftruncate.c111
-rw-r--r--binutils-2.25/gold/gc.cc74
-rw-r--r--binutils-2.25/gold/gc.h383
-rw-r--r--binutils-2.25/gold/gdb-index.cc1343
-rw-r--r--binutils-2.25/gold/gdb-index.h263
-rw-r--r--binutils-2.25/gold/gold-threads.cc450
-rw-r--r--binutils-2.25/gold/gold-threads.h267
-rw-r--r--binutils-2.25/gold/gold.cc888
-rw-r--r--binutils-2.25/gold/gold.h313
-rw-r--r--binutils-2.25/gold/i386.cc4168
-rw-r--r--binutils-2.25/gold/icf.cc849
-rw-r--r--binutils-2.25/gold/icf.h179
-rw-r--r--binutils-2.25/gold/incremental-dump.cc518
-rw-r--r--binutils-2.25/gold/incremental.cc3123
-rw-r--r--binutils-2.25/gold/incremental.h2255
-rw-r--r--binutils-2.25/gold/int_encoding.cc134
-rw-r--r--binutils-2.25/gold/int_encoding.h158
-rw-r--r--binutils-2.25/gold/layout.cc5909
-rw-r--r--binutils-2.25/gold/layout.h1629
-rw-r--r--binutils-2.25/gold/main.cc332
-rw-r--r--binutils-2.25/gold/mapfile.cc404
-rw-r--r--binutils-2.25/gold/mapfile.h118
-rw-r--r--binutils-2.25/gold/merge.cc762
-rw-r--r--binutils-2.25/gold/merge.h574
-rw-r--r--binutils-2.25/gold/mremap.c87
-rw-r--r--binutils-2.25/gold/nacl.cc47
-rw-r--r--binutils-2.25/gold/nacl.h243
-rw-r--r--binutils-2.25/gold/object.cc3331
-rw-r--r--binutils-2.25/gold/object.h2918
-rw-r--r--binutils-2.25/gold/options.cc1499
-rw-r--r--binutils-2.25/gold/options.h2117
-rw-r--r--binutils-2.25/gold/output.cc5568
-rw-r--r--binutils-2.25/gold/output.h4866
-rw-r--r--binutils-2.25/gold/parameters.cc389
-rw-r--r--binutils-2.25/gold/parameters.h246
-rw-r--r--binutils-2.25/gold/plugin.cc1862
-rw-r--r--binutils-2.25/gold/plugin.h594
-rw-r--r--binutils-2.25/gold/po/Make-in258
-rw-r--r--binutils-2.25/gold/po/POTFILES.in102
-rw-r--r--binutils-2.25/gold/po/es.po2286
-rw-r--r--binutils-2.25/gold/po/fi.po2284
-rw-r--r--binutils-2.25/gold/po/gold.pot2263
-rw-r--r--binutils-2.25/gold/po/id.po1867
-rw-r--r--binutils-2.25/gold/po/it.po2247
-rw-r--r--binutils-2.25/gold/po/vi.po2267
-rw-r--r--binutils-2.25/gold/powerpc.cc7754
-rw-r--r--binutils-2.25/gold/pread.c42
-rw-r--r--binutils-2.25/gold/readsyms.cc946
-rw-r--r--binutils-2.25/gold/readsyms.h492
-rw-r--r--binutils-2.25/gold/reduced_debug_output.cc376
-rw-r--r--binutils-2.25/gold/reduced_debug_output.h140
-rw-r--r--binutils-2.25/gold/reloc-types.h92
-rw-r--r--binutils-2.25/gold/reloc.cc1849
-rw-r--r--binutils-2.25/gold/reloc.h899
-rw-r--r--binutils-2.25/gold/resolve.cc1085
-rw-r--r--binutils-2.25/gold/script-c.h566
-rw-r--r--binutils-2.25/gold/script-sections.cc4372
-rw-r--r--binutils-2.25/gold/script-sections.h337
-rw-r--r--binutils-2.25/gold/script.cc3409
-rw-r--r--binutils-2.25/gold/script.h594
-rw-r--r--binutils-2.25/gold/sparc.cc4395
-rw-r--r--binutils-2.25/gold/stringpool.cc529
-rw-r--r--binutils-2.25/gold/stringpool.h421
-rw-r--r--binutils-2.25/gold/symtab.cc3657
-rw-r--r--binutils-2.25/gold/symtab.h1927
-rw-r--r--binutils-2.25/gold/system.h158
-rw-r--r--binutils-2.25/gold/target-reloc.h835
-rw-r--r--binutils-2.25/gold/target-select.cc220
-rw-r--r--binutils-2.25/gold/target-select.h279
-rw-r--r--binutils-2.25/gold/target.cc260
-rw-r--r--binutils-2.25/gold/target.h1037
-rw-r--r--binutils-2.25/gold/testsuite/Makefile.am2901
-rw-r--r--binutils-2.25/gold/testsuite/Makefile.in5892
-rw-r--r--binutils-2.25/gold/testsuite/arm_abs_global.s31
-rwxr-xr-xbinutils-2.25/gold/testsuite/arm_abs_global.sh57
-rw-r--r--binutils-2.25/gold/testsuite/arm_abs_lib.s37
-rwxr-xr-xbinutils-2.25/gold/testsuite/arm_attr_merge.sh44
-rw-r--r--binutils-2.25/gold/testsuite/arm_attr_merge_6a.s4
-rw-r--r--binutils-2.25/gold/testsuite/arm_attr_merge_6b.s3
-rw-r--r--binutils-2.25/gold/testsuite/arm_attr_merge_7a.s4
-rw-r--r--binutils-2.25/gold/testsuite/arm_attr_merge_7b.s4
-rw-r--r--binutils-2.25/gold/testsuite/arm_bl_in_range.s45
-rw-r--r--binutils-2.25/gold/testsuite/arm_bl_out_of_range.s46
-rwxr-xr-xbinutils-2.25/gold/testsuite/arm_branch_in_range.sh73
-rwxr-xr-xbinutils-2.25/gold/testsuite/arm_branch_out_of_range.sh123
-rw-r--r--binutils-2.25/gold/testsuite/arm_branch_range.t36
-rwxr-xr-xbinutils-2.25/gold/testsuite/arm_cortex_a8.sh65
-rw-r--r--binutils-2.25/gold/testsuite/arm_cortex_a8_b.s30
-rw-r--r--binutils-2.25/gold/testsuite/arm_cortex_a8_b_cond.s30
-rw-r--r--binutils-2.25/gold/testsuite/arm_cortex_a8_b_local.s52
-rw-r--r--binutils-2.25/gold/testsuite/arm_cortex_a8_bl.s30
-rw-r--r--binutils-2.25/gold/testsuite/arm_cortex_a8_blx.s33
-rw-r--r--binutils-2.25/gold/testsuite/arm_cortex_a8_local.s29
-rw-r--r--binutils-2.25/gold/testsuite/arm_cortex_a8_local_reloc.s31
-rw-r--r--binutils-2.25/gold/testsuite/arm_exidx_test.s31
-rwxr-xr-xbinutils-2.25/gold/testsuite/arm_exidx_test.sh60
-rw-r--r--binutils-2.25/gold/testsuite/arm_farcall_arm_arm.s20
-rwxr-xr-xbinutils-2.25/gold/testsuite/arm_farcall_arm_arm.sh44
-rw-r--r--binutils-2.25/gold/testsuite/arm_farcall_arm_thumb.s20
-rwxr-xr-xbinutils-2.25/gold/testsuite/arm_farcall_arm_thumb.sh50
-rw-r--r--binutils-2.25/gold/testsuite/arm_farcall_thumb_arm.s27
-rwxr-xr-xbinutils-2.25/gold/testsuite/arm_farcall_thumb_arm.sh56
-rw-r--r--binutils-2.25/gold/testsuite/arm_farcall_thumb_thumb.s19
-rwxr-xr-xbinutils-2.25/gold/testsuite/arm_farcall_thumb_thumb.sh74
-rw-r--r--binutils-2.25/gold/testsuite/arm_fix_1176.s15
-rwxr-xr-xbinutils-2.25/gold/testsuite/arm_fix_1176.sh61
-rw-r--r--binutils-2.25/gold/testsuite/arm_fix_v4bx.s15
-rwxr-xr-xbinutils-2.25/gold/testsuite/arm_fix_v4bx.sh56
-rw-r--r--binutils-2.25/gold/testsuite/arm_thm_jump11.s57
-rw-r--r--binutils-2.25/gold/testsuite/arm_thm_jump11.t36
-rw-r--r--binutils-2.25/gold/testsuite/arm_thm_jump8.s57
-rw-r--r--binutils-2.25/gold/testsuite/arm_thm_jump8.t36
-rw-r--r--binutils-2.25/gold/testsuite/arm_unaligned_reloc.s44
-rwxr-xr-xbinutils-2.25/gold/testsuite/arm_unaligned_reloc.sh57
-rw-r--r--binutils-2.25/gold/testsuite/basic_test.cc318
-rw-r--r--binutils-2.25/gold/testsuite/binary.in1
-rw-r--r--binutils-2.25/gold/testsuite/binary_test.cc46
-rw-r--r--binutils-2.25/gold/testsuite/binary_unittest.cc184
-rw-r--r--binutils-2.25/gold/testsuite/common_test_1.c75
-rw-r--r--binutils-2.25/gold/testsuite/common_test_1_v1.c79
-rw-r--r--binutils-2.25/gold/testsuite/common_test_1_v2.c77
-rw-r--r--binutils-2.25/gold/testsuite/common_test_2.c33
-rw-r--r--binutils-2.25/gold/testsuite/common_test_3.c32
-rw-r--r--binutils-2.25/gold/testsuite/constructor_test.cc90
-rw-r--r--binutils-2.25/gold/testsuite/copy_test.cc43
-rw-r--r--binutils-2.25/gold/testsuite/copy_test_1.cc23
-rw-r--r--binutils-2.25/gold/testsuite/copy_test_2.cc23
-rw-r--r--binutils-2.25/gold/testsuite/copy_test_v1.cc47
-rw-r--r--binutils-2.25/gold/testsuite/debug_msg.cc96
-rwxr-xr-xbinutils-2.25/gold/testsuite/debug_msg.sh145
-rw-r--r--binutils-2.25/gold/testsuite/discard_locals_relocatable_test.c52
-rw-r--r--binutils-2.25/gold/testsuite/discard_locals_test.c40
-rwxr-xr-xbinutils-2.25/gold/testsuite/discard_locals_test.sh63
-rw-r--r--binutils-2.25/gold/testsuite/dwp_test.h87
-rw-r--r--binutils-2.25/gold/testsuite/dwp_test_1.cc210
-rw-r--r--binutils-2.25/gold/testsuite/dwp_test_1.s2660
-rwxr-xr-xbinutils-2.25/gold/testsuite/dwp_test_1.sh63
-rw-r--r--binutils-2.25/gold/testsuite/dwp_test_1b.cc35
-rw-r--r--binutils-2.25/gold/testsuite/dwp_test_1b.s549
-rw-r--r--binutils-2.25/gold/testsuite/dwp_test_2.cc144
-rw-r--r--binutils-2.25/gold/testsuite/dwp_test_2.s1714
-rwxr-xr-xbinutils-2.25/gold/testsuite/dwp_test_2.sh63
-rw-r--r--binutils-2.25/gold/testsuite/dwp_test_main.cc59
-rw-r--r--binutils-2.25/gold/testsuite/dwp_test_main.s1399
-rwxr-xr-xbinutils-2.25/gold/testsuite/dyn_weak_ref.sh42
-rw-r--r--binutils-2.25/gold/testsuite/dyn_weak_ref_1.c39
-rw-r--r--binutils-2.25/gold/testsuite/dyn_weak_ref_2.c32
-rwxr-xr-xbinutils-2.25/gold/testsuite/dynamic_list.sh50
-rw-r--r--binutils-2.25/gold/testsuite/dynamic_list.t11
-rw-r--r--binutils-2.25/gold/testsuite/exception_test.h27
-rw-r--r--binutils-2.25/gold/testsuite/exception_test_1.cc52
-rw-r--r--binutils-2.25/gold/testsuite/exception_test_2.cc31
-rw-r--r--binutils-2.25/gold/testsuite/exception_test_main.cc35
-rw-r--r--binutils-2.25/gold/testsuite/exclude_libs_test.c14
-rwxr-xr-xbinutils-2.25/gold/testsuite/exclude_libs_test.sh63
-rw-r--r--binutils-2.25/gold/testsuite/exclude_libs_test_1.c32
-rw-r--r--binutils-2.25/gold/testsuite/exclude_libs_test_2.c24
-rw-r--r--binutils-2.25/gold/testsuite/exclude_libs_test_3.c24
-rw-r--r--binutils-2.25/gold/testsuite/final_layout.cc48
-rwxr-xr-xbinutils-2.25/gold/testsuite/final_layout.sh61
-rwxr-xr-xbinutils-2.25/gold/testsuite/gc_comdat_test.sh42
-rw-r--r--binutils-2.25/gold/testsuite/gc_comdat_test_1.cc42
-rw-r--r--binutils-2.25/gold/testsuite/gc_comdat_test_2.cc35
-rw-r--r--binutils-2.25/gold/testsuite/gc_orphan_section_test.cc36
-rwxr-xr-xbinutils-2.25/gold/testsuite/gc_orphan_section_test.sh46
-rw-r--r--binutils-2.25/gold/testsuite/gc_tls_test.cc32
-rwxr-xr-xbinutils-2.25/gold/testsuite/gc_tls_test.sh39
-rw-r--r--binutils-2.25/gold/testsuite/gdb_index_test.cc149
-rwxr-xr-xbinutils-2.25/gold/testsuite/gdb_index_test_1.sh25
-rwxr-xr-xbinutils-2.25/gold/testsuite/gdb_index_test_2.sh25
-rw-r--r--binutils-2.25/gold/testsuite/gdb_index_test_3.c39
-rwxr-xr-xbinutils-2.25/gold/testsuite/gdb_index_test_3.sh49
-rwxr-xr-xbinutils-2.25/gold/testsuite/gdb_index_test_4.sh25
-rwxr-xr-xbinutils-2.25/gold/testsuite/gdb_index_test_comm.sh85
-rwxr-xr-xbinutils-2.25/gold/testsuite/hidden_test.sh66
-rw-r--r--binutils-2.25/gold/testsuite/hidden_test_1.c41
-rw-r--r--binutils-2.25/gold/testsuite/hidden_test_main.c61
-rw-r--r--binutils-2.25/gold/testsuite/icf_keep_unique_test.cc39
-rwxr-xr-xbinutils-2.25/gold/testsuite/icf_keep_unique_test.sh39
-rw-r--r--binutils-2.25/gold/testsuite/icf_preemptible_functions_test.cc47
-rwxr-xr-xbinutils-2.25/gold/testsuite/icf_preemptible_functions_test.sh37
-rw-r--r--binutils-2.25/gold/testsuite/icf_safe_so_test.cc74
-rwxr-xr-xbinutils-2.25/gold/testsuite/icf_safe_so_test.sh102
-rw-r--r--binutils-2.25/gold/testsuite/icf_safe_test.cc63
-rwxr-xr-xbinutils-2.25/gold/testsuite/icf_safe_test.sh73
-rwxr-xr-xbinutils-2.25/gold/testsuite/icf_sht_rel_addend_test.sh37
-rw-r--r--binutils-2.25/gold/testsuite/icf_sht_rel_addend_test_1.cc44
-rw-r--r--binutils-2.25/gold/testsuite/icf_sht_rel_addend_test_2.cc39
-rw-r--r--binutils-2.25/gold/testsuite/icf_string_merge_test.cc50
-rwxr-xr-xbinutils-2.25/gold/testsuite/icf_string_merge_test.sh39
-rw-r--r--binutils-2.25/gold/testsuite/icf_test.cc51
-rwxr-xr-xbinutils-2.25/gold/testsuite/icf_test.sh46
-rw-r--r--binutils-2.25/gold/testsuite/icf_virtual_function_folding_test.cc71
-rw-r--r--binutils-2.25/gold/testsuite/ifunc-sel.h92
-rw-r--r--binutils-2.25/gold/testsuite/ifuncdep2.c50
-rw-r--r--binutils-2.25/gold/testsuite/ifuncmain1.c64
-rw-r--r--binutils-2.25/gold/testsuite/ifuncmain1vis.c89
-rw-r--r--binutils-2.25/gold/testsuite/ifuncmain2.c14
-rw-r--r--binutils-2.25/gold/testsuite/ifuncmain3.c133
-rw-r--r--binutils-2.25/gold/testsuite/ifuncmain4.c4
-rw-r--r--binutils-2.25/gold/testsuite/ifuncmain5.c41
-rw-r--r--binutils-2.25/gold/testsuite/ifuncmain6pie.c64
-rw-r--r--binutils-2.25/gold/testsuite/ifuncmain7.c74
-rw-r--r--binutils-2.25/gold/testsuite/ifuncmod1.c95
-rw-r--r--binutils-2.25/gold/testsuite/ifuncmod3.c7
-rw-r--r--binutils-2.25/gold/testsuite/ifuncmod5.c55
-rw-r--r--binutils-2.25/gold/testsuite/ifuncmod6.c22
-rw-r--r--binutils-2.25/gold/testsuite/ifuncvar1.c20
-rw-r--r--binutils-2.25/gold/testsuite/ifuncvar2.c12
-rw-r--r--binutils-2.25/gold/testsuite/ifuncvar3.c14
-rw-r--r--binutils-2.25/gold/testsuite/incr_comdat_test_1.cc68
-rw-r--r--binutils-2.25/gold/testsuite/incr_comdat_test_2_v1.cc44
-rw-r--r--binutils-2.25/gold/testsuite/incr_comdat_test_2_v2.cc44
-rw-r--r--binutils-2.25/gold/testsuite/incr_comdat_test_2_v3.cc44
-rwxr-xr-xbinutils-2.25/gold/testsuite/incremental_test.sh89
-rw-r--r--binutils-2.25/gold/testsuite/incremental_test_1.c28
-rw-r--r--binutils-2.25/gold/testsuite/incremental_test_2.c29
-rw-r--r--binutils-2.25/gold/testsuite/initpri1.c105
-rw-r--r--binutils-2.25/gold/testsuite/initpri2.c118
-rw-r--r--binutils-2.25/gold/testsuite/initpri3.c80
-rw-r--r--binutils-2.25/gold/testsuite/justsyms.t31
-rw-r--r--binutils-2.25/gold/testsuite/justsyms_1.cc54
-rw-r--r--binutils-2.25/gold/testsuite/justsyms_2.cc27
-rw-r--r--binutils-2.25/gold/testsuite/justsyms_exec.c56
-rw-r--r--binutils-2.25/gold/testsuite/justsyms_lib.c35
-rw-r--r--binutils-2.25/gold/testsuite/large.c59
-rw-r--r--binutils-2.25/gold/testsuite/large_symbol_alignment.cc49
-rw-r--r--binutils-2.25/gold/testsuite/leb128_unittest.cc88
-rw-r--r--binutils-2.25/gold/testsuite/many_sections_test.cc51
-rw-r--r--binutils-2.25/gold/testsuite/memory_test.s14
-rwxr-xr-xbinutils-2.25/gold/testsuite/memory_test.sh57
-rw-r--r--binutils-2.25/gold/testsuite/memory_test.t26
-rwxr-xr-xbinutils-2.25/gold/testsuite/merge_string_literals.sh41
-rw-r--r--binutils-2.25/gold/testsuite/merge_string_literals_1.cc31
-rw-r--r--binutils-2.25/gold/testsuite/merge_string_literals_2.cc31
-rw-r--r--binutils-2.25/gold/testsuite/missing_key_func.cc46
-rwxr-xr-xbinutils-2.25/gold/testsuite/missing_key_func.sh58
-rw-r--r--binutils-2.25/gold/testsuite/no_version_test.c32
-rwxr-xr-xbinutils-2.25/gold/testsuite/no_version_test.sh45
-rw-r--r--binutils-2.25/gold/testsuite/object_unittest.cc105
-rw-r--r--binutils-2.25/gold/testsuite/odr_header1.h6
-rw-r--r--binutils-2.25/gold/testsuite/odr_header2.h4
-rw-r--r--binutils-2.25/gold/testsuite/odr_violation1.cc23
-rw-r--r--binutils-2.25/gold/testsuite/odr_violation2.cc34
-rw-r--r--binutils-2.25/gold/testsuite/plugin_common_test_1.c48
-rw-r--r--binutils-2.25/gold/testsuite/plugin_common_test_2.c45
-rw-r--r--binutils-2.25/gold/testsuite/plugin_final_layout.cc47
-rwxr-xr-xbinutils-2.25/gold/testsuite/plugin_final_layout.sh90
-rw-r--r--binutils-2.25/gold/testsuite/plugin_section_order.c188
-rw-r--r--binutils-2.25/gold/testsuite/plugin_test.c600
-rwxr-xr-xbinutils-2.25/gold/testsuite/plugin_test_1.sh59
-rwxr-xr-xbinutils-2.25/gold/testsuite/plugin_test_2.sh56
-rwxr-xr-xbinutils-2.25/gold/testsuite/plugin_test_3.sh59
-rwxr-xr-xbinutils-2.25/gold/testsuite/plugin_test_4.sh58
-rwxr-xr-xbinutils-2.25/gold/testsuite/plugin_test_6.sh58
-rwxr-xr-xbinutils-2.25/gold/testsuite/plugin_test_7.sh56
-rw-r--r--binutils-2.25/gold/testsuite/plugin_test_7_1.c43
-rw-r--r--binutils-2.25/gold/testsuite/plugin_test_7_2.c33
-rwxr-xr-xbinutils-2.25/gold/testsuite/plugin_test_tls.sh60
-rwxr-xr-xbinutils-2.25/gold/testsuite/pr12826.sh44
-rw-r--r--binutils-2.25/gold/testsuite/pr12826_1.s13
-rw-r--r--binutils-2.25/gold/testsuite/pr12826_2.s13
-rw-r--r--binutils-2.25/gold/testsuite/pr14265.c20
-rwxr-xr-xbinutils-2.25/gold/testsuite/pr14265.sh40
-rw-r--r--binutils-2.25/gold/testsuite/pr14265.t25
-rw-r--r--binutils-2.25/gold/testsuite/protected_1.cc58
-rw-r--r--binutils-2.25/gold/testsuite/protected_2.cc31
-rw-r--r--binutils-2.25/gold/testsuite/protected_3.cc33
-rw-r--r--binutils-2.25/gold/testsuite/protected_4.cc32
-rw-r--r--binutils-2.25/gold/testsuite/protected_main_1.cc40
-rw-r--r--binutils-2.25/gold/testsuite/protected_main_2.cc29
-rw-r--r--binutils-2.25/gold/testsuite/protected_main_3.cc31
-rw-r--r--binutils-2.25/gold/testsuite/relro_script_test.t54
-rw-r--r--binutils-2.25/gold/testsuite/relro_test.cc160
-rwxr-xr-xbinutils-2.25/gold/testsuite/relro_test.sh74
-rw-r--r--binutils-2.25/gold/testsuite/relro_test_main.cc33
-rwxr-xr-xbinutils-2.25/gold/testsuite/retain_symbols_file_test.sh54
-rw-r--r--binutils-2.25/gold/testsuite/script_test_1.cc47
-rw-r--r--binutils-2.25/gold/testsuite/script_test_1.t29
-rw-r--r--binutils-2.25/gold/testsuite/script_test_10.s14
-rwxr-xr-xbinutils-2.25/gold/testsuite/script_test_10.sh46
-rw-r--r--binutils-2.25/gold/testsuite/script_test_10.t34
-rw-r--r--binutils-2.25/gold/testsuite/script_test_11.c16
-rw-r--r--binutils-2.25/gold/testsuite/script_test_11.t8
-rw-r--r--binutils-2.25/gold/testsuite/script_test_2.cc74
-rw-r--r--binutils-2.25/gold/testsuite/script_test_2.t69
-rw-r--r--binutils-2.25/gold/testsuite/script_test_2a.cc24
-rw-r--r--binutils-2.25/gold/testsuite/script_test_2b.cc24
-rwxr-xr-xbinutils-2.25/gold/testsuite/script_test_3.sh102
-rw-r--r--binutils-2.25/gold/testsuite/script_test_3.t55
-rwxr-xr-xbinutils-2.25/gold/testsuite/script_test_4.sh41
-rw-r--r--binutils-2.25/gold/testsuite/script_test_4.t45
-rw-r--r--binutils-2.25/gold/testsuite/script_test_5.cc45
-rwxr-xr-xbinutils-2.25/gold/testsuite/script_test_5.sh43
-rw-r--r--binutils-2.25/gold/testsuite/script_test_5.t44
-rwxr-xr-xbinutils-2.25/gold/testsuite/script_test_6.sh43
-rw-r--r--binutils-2.25/gold/testsuite/script_test_6.t45
-rwxr-xr-xbinutils-2.25/gold/testsuite/script_test_7.sh43
-rw-r--r--binutils-2.25/gold/testsuite/script_test_7.t45
-rwxr-xr-xbinutils-2.25/gold/testsuite/script_test_8.sh44
-rw-r--r--binutils-2.25/gold/testsuite/script_test_9.cc29
-rwxr-xr-xbinutils-2.25/gold/testsuite/script_test_9.sh42
-rw-r--r--binutils-2.25/gold/testsuite/script_test_9.t28
-rw-r--r--binutils-2.25/gold/testsuite/searched_file_test.cc36
-rw-r--r--binutils-2.25/gold/testsuite/searched_file_test_lib.cc27
-rw-r--r--binutils-2.25/gold/testsuite/section_sorting_name.cc59
-rwxr-xr-xbinutils-2.25/gold/testsuite/section_sorting_name.sh66
-rwxr-xr-xbinutils-2.25/gold/testsuite/split_i386.sh54
-rw-r--r--binutils-2.25/gold/testsuite/split_i386_1.s33
-rw-r--r--binutils-2.25/gold/testsuite/split_i386_2.s33
-rw-r--r--binutils-2.25/gold/testsuite/split_i386_3.s22
-rw-r--r--binutils-2.25/gold/testsuite/split_i386_4.s23
-rw-r--r--binutils-2.25/gold/testsuite/split_i386_n.s12
-rwxr-xr-xbinutils-2.25/gold/testsuite/split_x86_64.sh54
-rw-r--r--binutils-2.25/gold/testsuite/split_x86_64_1.s33
-rw-r--r--binutils-2.25/gold/testsuite/split_x86_64_2.s33
-rw-r--r--binutils-2.25/gold/testsuite/split_x86_64_3.s22
-rw-r--r--binutils-2.25/gold/testsuite/split_x86_64_4.s23
-rw-r--r--binutils-2.25/gold/testsuite/split_x86_64_n.s12
-rw-r--r--binutils-2.25/gold/testsuite/start_lib_test_1.c32
-rw-r--r--binutils-2.25/gold/testsuite/start_lib_test_2.c30
-rw-r--r--binutils-2.25/gold/testsuite/start_lib_test_3.c25
-rw-r--r--binutils-2.25/gold/testsuite/start_lib_test_main.c33
-rwxr-xr-xbinutils-2.25/gold/testsuite/strong_ref_weak_def.sh42
-rw-r--r--binutils-2.25/gold/testsuite/strong_ref_weak_def_1.c39
-rw-r--r--binutils-2.25/gold/testsuite/strong_ref_weak_def_2.c37
-rw-r--r--binutils-2.25/gold/testsuite/test.cc107
-rw-r--r--binutils-2.25/gold/testsuite/test.h145
-rw-r--r--binutils-2.25/gold/testsuite/testfile.cc949
-rw-r--r--binutils-2.25/gold/testsuite/testfile.h49
-rw-r--r--binutils-2.25/gold/testsuite/testmain.cc40
-rw-r--r--binutils-2.25/gold/testsuite/text_section_grouping.cc72
-rwxr-xr-xbinutils-2.25/gold/testsuite/text_section_grouping.sh73
-rw-r--r--binutils-2.25/gold/testsuite/thin_archive_main.cc39
-rw-r--r--binutils-2.25/gold/testsuite/thin_archive_test_1.cc37
-rw-r--r--binutils-2.25/gold/testsuite/thin_archive_test_2.cc37
-rw-r--r--binutils-2.25/gold/testsuite/thin_archive_test_3.cc37
-rw-r--r--binutils-2.25/gold/testsuite/thin_archive_test_4.cc35
-rw-r--r--binutils-2.25/gold/testsuite/thumb2_branch_range.t36
-rw-r--r--binutils-2.25/gold/testsuite/thumb_bl_in_range.s56
-rw-r--r--binutils-2.25/gold/testsuite/thumb_bl_out_of_range.s62
-rw-r--r--binutils-2.25/gold/testsuite/thumb_bl_out_of_range_local.s61
-rw-r--r--binutils-2.25/gold/testsuite/thumb_blx_in_range.s64
-rw-r--r--binutils-2.25/gold/testsuite/thumb_blx_out_of_range.s66
-rw-r--r--binutils-2.25/gold/testsuite/thumb_branch_range.t36
-rw-r--r--binutils-2.25/gold/testsuite/tls_test.cc224
-rw-r--r--binutils-2.25/gold/testsuite/tls_test.h56
-rw-r--r--binutils-2.25/gold/testsuite/tls_test_c.c65
-rw-r--r--binutils-2.25/gold/testsuite/tls_test_file2.cc30
-rw-r--r--binutils-2.25/gold/testsuite/tls_test_main.cc173
-rwxr-xr-xbinutils-2.25/gold/testsuite/two_file_shared.sh30
-rw-r--r--binutils-2.25/gold/testsuite/two_file_test.h78
-rw-r--r--binutils-2.25/gold/testsuite/two_file_test_1.cc238
-rw-r--r--binutils-2.25/gold/testsuite/two_file_test_1_v1.cc236
-rw-r--r--binutils-2.25/gold/testsuite/two_file_test_1b.cc41
-rw-r--r--binutils-2.25/gold/testsuite/two_file_test_1b_v1.cc46
-rw-r--r--binutils-2.25/gold/testsuite/two_file_test_2.cc145
-rw-r--r--binutils-2.25/gold/testsuite/two_file_test_2_tls.cc147
-rw-r--r--binutils-2.25/gold/testsuite/two_file_test_2_v1.cc150
-rw-r--r--binutils-2.25/gold/testsuite/two_file_test_main.cc57
-rw-r--r--binutils-2.25/gold/testsuite/two_file_test_tls.cc60
-rw-r--r--binutils-2.25/gold/testsuite/undef_symbol.cc40
-rwxr-xr-xbinutils-2.25/gold/testsuite/undef_symbol.sh45
-rw-r--r--binutils-2.25/gold/testsuite/undef_symbol_main.cc29
-rw-r--r--binutils-2.25/gold/testsuite/ver_matching_def.cc73
-rwxr-xr-xbinutils-2.25/gold/testsuite/ver_matching_test.sh88
-rw-r--r--binutils-2.25/gold/testsuite/ver_test.h43
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_1.cc33
-rwxr-xr-xbinutils-2.25/gold/testsuite/ver_test_1.sh30
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_10.script30
-rwxr-xr-xbinutils-2.25/gold/testsuite/ver_test_10.sh44
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_2.cc40
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_2.script31
-rwxr-xr-xbinutils-2.25/gold/testsuite/ver_test_2.sh45
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_3.cc33
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_4.cc64
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_4.script35
-rwxr-xr-xbinutils-2.25/gold/testsuite/ver_test_4.sh44
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_5.cc29
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_5.script31
-rwxr-xr-xbinutils-2.25/gold/testsuite/ver_test_5.sh44
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_6.c35
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_7.cc37
-rwxr-xr-xbinutils-2.25/gold/testsuite/ver_test_7.sh44
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_8.script26
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_9.cc50
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_main.cc74
-rw-r--r--binutils-2.25/gold/testsuite/ver_test_main_2.cc32
-rw-r--r--binutils-2.25/gold/testsuite/version_script.map34
-rw-r--r--binutils-2.25/gold/testsuite/weak_alias_test.script8
-rw-r--r--binutils-2.25/gold/testsuite/weak_alias_test_1.cc52
-rw-r--r--binutils-2.25/gold/testsuite/weak_alias_test_2.cc41
-rw-r--r--binutils-2.25/gold/testsuite/weak_alias_test_3.cc26
-rw-r--r--binutils-2.25/gold/testsuite/weak_alias_test_4.cc68
-rw-r--r--binutils-2.25/gold/testsuite/weak_alias_test_5.cc39
-rw-r--r--binutils-2.25/gold/testsuite/weak_alias_test_main.cc80
-rwxr-xr-xbinutils-2.25/gold/testsuite/weak_plt.sh28
-rw-r--r--binutils-2.25/gold/testsuite/weak_plt_main.cc33
-rw-r--r--binutils-2.25/gold/testsuite/weak_plt_shared.cc29
-rw-r--r--binutils-2.25/gold/testsuite/weak_test.cc47
-rw-r--r--binutils-2.25/gold/testsuite/weak_undef.h25
-rw-r--r--binutils-2.25/gold/testsuite/weak_undef_file1.cc75
-rw-r--r--binutils-2.25/gold/testsuite/weak_undef_file2.cc70
-rw-r--r--binutils-2.25/gold/testsuite/weak_undef_test.cc106
-rw-r--r--binutils-2.25/gold/tilegx.cc4924
-rw-r--r--binutils-2.25/gold/timer.cc133
-rw-r--r--binutils-2.25/gold/timer.h80
-rw-r--r--binutils-2.25/gold/tls.h81
-rw-r--r--binutils-2.25/gold/token.h335
-rw-r--r--binutils-2.25/gold/version.cc82
-rw-r--r--binutils-2.25/gold/workqueue-internal.h109
-rw-r--r--binutils-2.25/gold/workqueue-threads.cc199
-rw-r--r--binutils-2.25/gold/workqueue.cc521
-rw-r--r--binutils-2.25/gold/workqueue.h295
-rw-r--r--binutils-2.25/gold/x86_64.cc4836
-rw-r--r--binutils-2.25/gold/yyscript.y1133
467 files changed, 207108 insertions, 0 deletions
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 <amodra@gmail.com>
+
+ * 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 <mcgrathr@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ 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 <pavel.v.chupin@intel.com>
+
+ PR gold/15927
+ * x86_64.cc (Target_x86_64<size>::Scan::global): Use relative
+ relocation for R_X86_64_32 on x32.
+
+2013-08-27 Roland McGrath <mcgrathr@google.com>
+
+ * 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 <yurchor@ukr.net>
+
+ PR binutils/15834
+ * object.h: Fix typos.
+
+2013-08-16 Roland McGrath <mcgrathr@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ Revert support for v2 DWP files:
+
+ 2013-03-01 Cary Coutant <ccoutant@google.com>
+
+ 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+ Sasa Stankovic <Sasa.Stankovic@imgtec.com>
+
+ * 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 <saugustine@google.com>
+
+ * 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 <mcgrathr@google.com>
+
+ * 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 <shawnlandden@gmail.com>
+
+ 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 <ccoutant@google.com>
+
+ * powerpc.cc (Target_powerpc::write_branch_lookup_table): Use
+ correct BRLT entry size.
+
+2013-07-03 Alan Modra <amodra@gmail.com>
+
+ * powerpc.cc (Target_powerpc::Relocate::relocate): Update self-call
+ comment.
+
+2013-07-01 Cary Coutant <ccoutant@google.com>
+
+ * 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 <jingyu@google.com>
+
+ 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 <ccoutant@google.com>
+
+ * powerpc.cc (Target_powerpc::symval_for_branch): Don't assert
+ on garbage collected .opd section.
+
+2013-06-27 Alan Modra <amodra@gmail.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <alexander.ivchenko@intel.com>
+
+ * 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 <alexander.ivchenko@intel.com>
+ Sriraman Tallam <tmsriram@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <mcgrathr@google.com>
+
+ * 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 <mcgrathr@google.com>
+
+ * options.h (General_options): Remove leading space from help
+ messages for -nostdlib and --rosegment.
+
+2013-05-03 Maciej W. Rozycki <macro@codesourcery.com>
+
+ PR ld/15365
+ * layout.cc (Layout::finalize): Make __ehdr_start STV_HIDDEN.
+
+2013-05-03 Alan Modra <amodra@gmail.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ * merge.cc (Output_merge_string<Char_type>::do_add_input_section):
+ Restore empty string handling.
+
+2013-05-01 Cary Coutant <ccoutant@google.com>
+
+ * stringpool.cc (Stringpool_template::new_key_offset): Fix
+ uninitialized warning.
+
+2013-04-29 Alexander Ivchenko <alexander.ivchenko@intel.com>
+
+ * 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<Char_type>::do_add_input_section): Count
+ only not-null strings. Check the alignment of strings.
+ * stringpool.h
+ (Stringpool_template<Stringpool_char>::Stringpool_template): Add
+ alignment as the argument.
+ (Stringpool_template<Stringpool_char>::addralign_): New class member.
+ * stringpool.cc (Stringpool_template<Stringpool_char>::new_key_offset):
+ Align non-zero length strings according to the addralign_.
+ (Stringpool_template<Stringpool_char>::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 <iant@google.com>
+
+ * 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 <gpike@chromium.org>
+
+ * 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 <amodra@gmail.com>
+
+ * configure.tgt: Add powerpcle and powerpc64le.
+
+2013-04-22 Alan Modra <amodra@gmail.com>
+
+ PR gold/15355
+ * layout.cc (Layout::segment_precedes): Allow more than one
+ segment with the same type and flags.
+
+2013-04-15 Cary Coutant <ccoutant@google.com>
+
+ * layout.cc (Layout::set_relocatable_section_offsets): Don't
+ allocate space in file for BSS sections.
+
+2013-04-15 Cary Coutant <ccoutant@google.com>
+
+ * script-sections.cc (Orphan_output_section): Reset address
+ to zero after each orphaned section for relocatable links.
+
+2013-04-15 Cary Coutant <ccoutant@google.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ 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 <iant@google.com>
+
+ 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 <tmsriram@google.com>
+
+ * 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 <amodra@gmail.com>
+
+ * layout.cc (Layout::set_segment_offsets): Accept writable .text
+ segment when omagic.
+
+2013-03-21 Alan Modra <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <iant@google.com>
+
+ * options.cc (General_options::string_to_object_format): Accept
+ "default".
+
+2013-03-08 Alan Modra <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * testsuite/discard_locals_relocatable_test.c: Add a powerpc
+ relocation referencing .LC0.
+ * testsuite/discard_locals_test.sh: Remove FIXMEs.
+
+2013-03-07 Alan Modra <amodra@gmail.com>
+
+ * testsuite/ifunc-sel.h (ifunc_sel, ifunc_one): Mark
+ always_inline. Add assembly for powerpc to avoid GOT.
+
+2013-03-07 Alan Modra <amodra@gmail.com>
+
+ * testsuite/script_test_10.sh: Don't test .bss section
+ header number.
+
+2013-03-06 Alan Modra <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * testsuite/Makefile.am (final_layout_script.lds): Add .sbss.
+ * testsuite/Makefile.in: Regenerate.
+
+2013-03-01 Cary Coutant <ccoutant@google.com>
+
+ 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 <ccoutant@google.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <iant@google.com>
+
+ * options.h (DEFINE_uint64_alias): Define.
+ (class General_options): Add -Ttext-segment as an alias for
+ -Ttext.
+
+2013-02-15 Alan Modra <amodra@gmail.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <amodra@gmail.com>
+
+ * README: Update coding style link.
+
+2013-01-28 Cary Coutant <ccoutant@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <vapier@gentoo.org>
+
+ * options.h (General_options): Change default to true for new_dtags.
+
+2013-01-18 Mike Frysinger <vapier@gentoo.org>
+
+ * 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 <serge.v.pavlov@gmail.com>
+
+ * 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 <tmsriram@google.com>
+
+ * testsuite/plugin_final_layout.cc: Fix comment.
+
+2013-01-16 Sriraman Tallam <tmsriram@google.com>
+
+ * 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 <amodra@gmail.com>
+
+ * powerpc.cc (Target_powerpc::do_relax): Default shared libs to
+ plt-thread-safe.
+
+2013-01-15 Alan Modra <amodra@gmail.com>
+
+ * testsuite/Makefile.am (final_layout_script.lds): Handle .got section.
+ * testsuite/Makefile.in: Regenerate.
+
+2013-01-14 Alan Modra <amodra@gmail.com>
+
+ * testsuite/Makefile.am (MOSTLYCLEANFILES): Add various output files.
+ * testsuite/Makefile.in: Regenerate.
+
+2013-01-11 Pavel Chupin <pavel.v.chupin@intel.com>
+
+ 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 <tmsriram@google.com>
+
+ * 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 <bccheng@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ 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 <hongjiu.lu@intel.com>
+ Ian Lance Taylor <iant@google.com>
+
+ 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 <hongjiu.lu@intel.com>
+
+ * options.h (General_options): Add -fuse-ld= for GCC linker
+ option compatibility.
+
+2013-01-04 Cary Coutant <ccoutant@google.com>
+
+ * configure.ac: Fix typo restoring CXXFLAGS.
+ * configure: Regenerate.
+
+2013-01-04 Cary Coutant <ccoutant@google.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ * version.cc (print_version): Update copyright year to 2013.
+
+2012-12-20 Ian Lance Taylor <iant@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <nickc@redhat.com>
+
+ * Makefile.am: Add copyright notice.
+ * NEWS: Likewise.
+ * README: Likewise.
+ * configure.ac: Likewise.
+ * ftruncate.c: Likewise.
+ * Makefile.in: Regenerate.
+
+2012-12-14 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <mcgrathr@google.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <mcgrathr@google.com>
+
+ * testsuite/binary_unittest.cc (Sized_binary_test):
+ Use open_descriptor rather than ::open.
+
+2012-12-07 Alan Modra <amodra@gmail.com>
+
+ * 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 <mcgrathr@google.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * powerpc.cc (Powerpc_relobj::do_scan_relocs): Delete.
+ (Target_powerpc::do_define_standard_symbols): New function.
+
+2012-12-03 Alan Modra <amodra@gmail.com>
+
+ * output.h: Formatting, whitespace.
+
+2012-12-03 Alan Modra <amodra@gmail.com>
+
+ * 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 <absolute 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ PR gold/14858
+ * x86_64.cc (Relocate::tls_ld_to_le): Support x32.
+
+2012-11-14 Roland McGrath <mcgrathr@google.com>
+
+ * arm.cc (Output_data_plt_arm_nacl::first_plt_entry): Use bic rather
+ than bfc instruction for data sandboxing.
+
+2012-11-08 Alan Modra <amodra@gmail.com>
+
+ * po/POTFILES.in: Regenerate.
+
+2012-11-05 Alan Modra <amodra@gmail.com>
+
+ * configure.ac: Apply 2012-09-10 change to config.in here.
+ * configure: Regenerate.
+
+2012-11-05 Alan Modra <amodra@gmail.com>
+
+ * 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 <mcgrathr@google.com>
+
+ * i386.cc (Target_i386::relocate_relocs): Remove extraneous typename
+ from last change.
+
+2012-11-01 Roland McGrath <mcgrathr@google.com>
+
+ * 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 <clocale> to after <libintl.h> 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 <steve.mcintyre@linaro.org>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ * testsuite/Makefile.am (MOSTLYCLEANFILES): Add
+ final_layout_sequence.txt.
+ * testsuite/Makefile.in: Regenerated.
+
+2012-10-25 H.J. Lu <hongjiu.lu@intel.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ * dwp.cc (Dwo_file::record_target_info): Issue a fatal error
+ on bad fwrite return.
+
+2012-10-25 H.J. Lu <hongjiu.lu@intel.com>
+
+ * dwp.cc (Dwo_file::remap_str_offset): Use section_offset_type
+ on val.
+
+2012-10-23 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * fileread.cc (Input_file::Input_file): New constructor.
+ * fileread.h (class Input_file): Add new constructor.
+
+2012-10-18 Alan Modra <amodra@gmail.com>
+
+ PR gold/14727
+ * object.cc (Relobj::is_section_name_included): Also match
+ .sdata personality section.
+
+2012-10-18 Alan Modra <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ PR gold/14726
+ * gold.cc (queue_middle_tasks): Call gc_mark_symbol on _init and _fini.
+
+2012-10-16 Sriraman Tallam <tmsriram@google.com>
+
+ * layout.cc (Layout::include_section): Keep sections marked
+ SHF_EXCLUDE when doing relocatable links.
+
+2012-10-16 Alan Modra <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <jiwang@tilera.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <jiwang@tilera.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <iant@google.com>
+
+ 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 <amodra@gmail.com>
+
+ 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 <amodra@gmail.com>
+
+ * 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 <doko@ubuntu.com>
+
+ * config.in: Disable sanity check for kfreebsd.
+
+2012-09-10 Sterling Augustine <saugustine@google.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ * testsuite/script_test_3.t: Add .got.plt output section
+ statement.
+ * testsuite/script_test_4.t: Likewise.
+
+2012-09-05 Alan Modra <amodra@gmail.com>
+
+ * powerpc.cc (Powerpc_relocate_functions): Upcase enum values,
+ update all uses and lose "enum" when using type.
+
+2012-09-05 Alan Modra <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <schwab@linux-m68k.org>
+
+ * powerpc.cc (do_make_elf_object): Allow ET_EXEC files with
+ --just-symbols.
+
+2012-08-31 Alan Modra <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * output.h (Output_reloc::Output_reloc <output section>): Add
+ is_relative param. Adjust calls.
+ (Output_reloc::add_output_section_relative): New functions.
+ * output.cc (Output_reloc::Output_reloc <output section>): Handle
+ is_relative.
+ (Output_reloc::symbol_value): Handle SECTION_CODE.
+
+2012-08-24 Sriraman Tallam <tmsriram@google.com>
+
+ * 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<size, big_endian>::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 <ccoutant@google.com>
+
+ * layout.cc (Layout::include_section): Don't assert on GROUP
+ sections with --emit-relocs.
+
+2012-08-21 Cary Coutant <ccoutant@google.com>
+
+ * symtab.cc (Symbol_table::gc_mark_undef_symbols): Don't assert
+ if --export-dynamic-symbol names an undef symbol.
+
+2012-08-18 Alan Modra <amodra@gmail.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <nickc@redhat.com>
+
+ 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <amodra@gmail.com>
+
+ * 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 <nickc@redhat.com>
+
+ * po/vi.po: Updated Vietnamese translation.
+
+2012-08-07 Ian Lance Taylor <iant@google.com>
+
+ * 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 <nickc@redhat.com>
+
+ * po/gold.pot: Updated template.
+ * po/es.po: Updated Spanish translation.
+
+2012-07-18 Cary Coutant <ccoutant@google.com>
+
+ 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 <tmsriram@google.com>
+
+ * gold.cc (queue_middle_tasks): Update function order only after
+ deferred objects due to plugins are processed.
+
+2012-07-11 Ian Lance Taylor <iant@google.com>
+
+ * 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 <dodji@redhat.com>
+ Ian Lance Taylor <iant@google.com>
+
+ PR gold/14309
+ * configure.ac: Test whether std::tr1::hash<off_t> works.
+ * gold.h: Add a specialization for std::tr1::hash<off_t> if
+ needed.
+ * output.h (class Output_fill): Add virtual destructor.
+ * configure, config.in: Rebuild.
+
+2012-06-22 Roland McGrath <mcgrathr@google.com>
+
+ * layout.cc (finalize): Define __ehdr_start symbol if applicable.
+
+2012-06-12 Rafael Ávila de Espíndola <respindola@mozilla.com>
+
+ * plugin.cc (Plugin::load): Handle position independent executables.
+
+2012-06-06 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <jingyu@google.com>
+
+ * gold.h (textdomain): Add do {} to empty while(0).
+ (bindtextdomain): Likewise.
+
+2012-06-04 Cary Coutant <ccoutant@google.com>
+
+ * dynobj.cc (Sized_dynobj::do_get_global_symbol_counts): Call
+ has_dynsym_index.
+
+2012-05-25 Sriraman Tallam <tmsriram@google.com>
+
+ * symtab.cc (Symbol_table::define_special_symbol):
+ Initialize *poldsym to prevent uninitialized variable errors.
+
+2012-05-23 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * layout.cc (Layout::section_name_mapping): Match .data.rel.ro.*
+ more carefully.
+
+2012-05-22 Cary Coutant <ccoutant@google.com>
+
+ * symtab.cc (Symbol::should_add_dynsym_entry): Check for relocatable
+ object before exporting symbol.
+
+2012-05-21 H.J. Lu <hongjiu.lu@intel.com>
+
+ * testsuite/tls_test.cc: Include "config.h" first.
+ * testsuite/tls_test_c.c: Likewise.
+
+2012-05-17 Daniel Richard G. <skunk@iskunk.org>
+ Nick Clifton <nickc@redhat.com>
+
+ 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 <ccoutant@google.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ 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 <ccoutant@google.com>
+
+ * layout.cc (gdb_sections): Update GDB version, add .debug_addr.
+ (lines_only_debug_sections): Likewise.
+
+2012-05-02 Roland McGrath <mcgrathr@google.com>
+
+ * nacl.cc: New file.
+ * nacl.h: New file.
+ * Makefile.am (CCFILES, HFILES): Add them.
+ * Makefile.in: Regenerate.
+ * i386.cc (Output_data_plt_i386_nacl): New class.
+ (Output_data_plt_i386_nacl_exec): New class.
+ (Output_data_plt_i386_nacl_dyn): New class.
+ (Target_i386_nacl): New class.
+ (Target_selector_i386_nacl): New class.
+ (target_selector_i386): Use it instead of Target_selector_i386.
+ * x86_64.cc (Output_data_plt_x86_64_nacl): New class.
+ (Target_x86_64_nacl): New class.
+ (Target_selector_x86_64_nacl): New class.
+ (target_selector_x86_64, target_selector_x32): Use it instead of
+ Target_selector_x86_64.
+ * arm.cc (Output_data_plt_arm_nacl): New class.
+ (Target_arm_nacl): New class.
+ (Target_selector_arm_nacl): New class.
+ (target_selector_arm, target_selector_armbe): Use it instead of
+ Target_selector_arm.
+
+ * target-select.cc (select_target): Take new Input_file* and off_t
+ arguments, pass them on to recognize method of selector.
+ * object.cc (make_elf_sized_object): Update caller.
+ * parameters.cc (parameters_force_valid_target): Likewise.
+ * incremental.cc (make_sized_incremental_binary): Likewise.
+ * target-select.h: Update decl.
+ (Target_selector::recognize): Take new Input_file* argument,
+ pass it on to do_recognize.
+ (Target_selector::do_recognize): Take new Input_file* argument.
+ * freebsd.h (Target_selector_freebsd::do_recognize): Likewise.
+ * powerpc.cc (Target_selector_powerpc::do_recognize): Likewise.
+ * sparc.cc (Target_selector_sparc::do_recognize): Likewise.
+ * testsuite/testfile.cc (Target_selector::do_recognize): Likewise.
+
+ * target.h (Target::Target_info): New members isolate_execinstr
+ and rosegment_gap.
+ (Target::isolate_execinstr, Target::rosegment_gap): New methods.
+ * arm.cc (Target_arm::arm_info): Update initializer.
+ * i386.cc (Target_i386::i386_info): Likewise.
+ * powerpc.cc (Target_powerpc::powerpc_info): Likewise.
+ * sparc.cc (Target_sparc::sparc_info): Likewise.
+ * x86_64.cc (Target_x86_64::x86_64_info): Likewise.
+ * testsuite/testfile.cc (Target_test::test_target_info): Likewise.
+ * layout.cc (Layout::attach_allocated_section_to_segment):
+ Take new const Target* argument. If target->isolate_execinstr(), act
+ like --rosegment.
+ (Layout::find_first_load_seg): Take new const Target* argument;
+ if target->isolate_execinstr(), reject PF_X segments.
+ (Layout::relaxation_loop_body): Update caller.
+ (Layout::set_segment_offsets): If target->isolate_execinstr(),
+ reset file offset to zero when we hit LOAD_SEG, and then do a second
+ loop over the segments before LOAD_SEG to reassign offsets after
+ addresses have been determined. Handle target->rosegment_gap().
+ (Layout::attach_section_to_segment): Take new const Target* argument;
+ pass it to attach_allocated_section_to_segment.
+ (Layout::make_output_section): Update caller.
+ (Layout::attach_sections_to_segments): Take new const Target* argument;
+ pass it to attach_section_to_segment.
+ * gold.cc (queue_middle_tasks): Update caller.
+ * layout.h (Layout): Update method decls with new arguments.
+
+ * arm.cc (Target_arm::Target_arm): Take optional argument for the
+ Target_info pointer to use.
+ (Target_arm::do_make_data_plt): New virtual method.
+ (Target_arm::make_data_plt): New method that calls it.
+ (Target_arm::make_plt_entry): Use it.
+ (Output_data_plt_arm::Output_data_plt_arm): Take additional argument
+ for the section alignment.
+ (Output_data_plt_arm::do_first_plt_entry_offset): New abstract virtual
+ method.
+ (Output_data_plt_arm::first_plt_entry_offset): Call it.
+ (Output_data_plt_arm::do_get_plt_entry_size): New abstract virtual
+ method.
+ (Output_data_plt_arm::get_plt_entry_size): Call it.
+ (Output_data_plt_arm::do_fill_plt_entry): New abstract virtual method.
+ (Output_data_plt_arm::fill_plt_entry): New method that calls it.
+ (Output_data_plt_arm::do_fill_first_plt_entry): New abstract virtual
+ method.
+ (Output_data_plt_arm::fill_first_plt_entry): New method that calls it.
+ (Output_data_plt_arm::set_final_data_size): Use get_plt_entry_size
+ method instead of sizeof(plt_entry).
+ (Output_data_plt_arm::add_entry): Likewise.
+ Use first_plt_entry_offset method instead of sizeof(first_plt_entry).
+ (Target_arm::first_plt_entry_offset): Call method on this->plt_ rather
+ than static method.
+ (Target_arm::plt_entry_size): Likewise.
+ (Output_data_plt_arm::first_plt_entry, Output_data_plt_arm::plt_entry):
+ Move to ...
+ (Output_data_plt_arm_standard): ... here, new class.
+ (Output_data_plt_arm::do_write): Move guts of PLT filling to...
+ (Output_data_plt_arm_standard::do_fill_first_plt_entry): ... here ...
+ (Output_data_plt_arm_standard::do_fill_plt_entry): ... and here.
+
+ * x86_64.cc (Output_data_plt_x86_64::Output_data_plt_x86_64):
+ Take additional argument for the PLT entry size.
+ (Output_data_plt_x86_64::get_tlsdesc_plt_offset):
+ Use get_plt_entry_size method rather than plt_entry_size variable.
+ (Output_data_plt_x86_64::reserve_slot): Likewise.
+ (Output_data_plt_x86_64::do_adjust_output_section): Likewise.
+ (Output_data_plt_x86_64::add_entry): Likewise.
+ (Output_data_plt_x86_64::add_local_ifunc_entry): Likewise.
+ (Output_data_plt_x86_64::address_for_global): Likewise.
+ (Output_data_plt_x86_64::address_for_local): Likewise.
+ (Output_data_plt_x86_64::set_final_data_size): Likewise.
+ (Output_data_plt_x86_64::first_plt_entry_offset): Likewise.
+ Make method non-static.
+ (Output_data_plt_x86_64::do_get_plt_entry_size): New abstract virtual
+ method.
+ (Output_data_plt_x86_64::get_plt_entry_size): Just call that.
+ (Output_data_plt_x86_64::do_add_eh_frame): New abstract virtual method.
+ (Output_data_plt_x86_64::add_eh_frame): New method to call it.
+ (Output_data_plt_x86_64::do_fill_first_plt_entry): New abstract
+ virtual method.
+ (Output_data_plt_x86_64::fill_first_plt_entry): New method to call it.
+ (Output_data_plt_x86_64::do_fill_plt_entry): New abstract
+ virtual method.
+ (Output_data_plt_x86_64::fill_plt_entry): New method to call it.
+ (Output_data_plt_x86_64::do_fill_tlsdesc_entry): New abstract
+ virtual method.
+ (Output_data_plt_x86_64::fill_tlsdesc_entry): New method to call it.
+ (Output_data_plt_x86_64::plt_entry_size)
+ (Output_data_plt_x86_64::first_plt_entry)
+ (Output_data_plt_x86_64::plt_entry)
+ (Output_data_plt_x86_64::tlsdesc_plt_entry)
+ (Output_data_plt_x86_64::plt_eh_frame_fde_size)
+ (Output_data_plt_x86_64::plt_eh_frame_fde): Move to ...
+ (Output_data_plt_x86_64_standard): ... here, new class.
+ (Target_x86_64::Target_x86_64): Take optional argument for the
+ Target_info pointer to use.
+ (Target_x86_64::do_make_data_plt): New virtual method.
+ (Target_x86_64::make_data_plt): New method to call it.
+ (Target_x86_64::init_got_plt_for_update): Use that.
+ Call this->plt_->add_eh_frame method here.
+ (Output_data_plt_x86_64::init): Don't do add_eh_frame_for_plt here.
+ (Target_x86_64::first_plt_entry_offset): Call method on this->plt_
+ rather than static method.
+ (Target_x86_64::plt_entry_size): Likewise.
+ (Output_data_plt_x86_64::do_write): Use get_plt_entry_size method
+ rather than plt_entry_size variable. Move guts of PLT filling to...
+ (Output_data_plt_x86_64_standard::do_fill_first_plt_entry): ... here ...
+ (Output_data_plt_x86_64_standard::do_fill_plt_entry): ... and here ...
+ (Output_data_plt_x86_64_standard::do_fill_tlsdesc_entry): ... and here.
+
+ * i386.cc (Output_data_plt_i386::Output_data_plt_i386): Take
+ additional argument for the section alignment.
+ Don't do add_eh_frame_for_plt here.
+ (Output_data_plt_i386::first_plt_entry_offset): Make the method
+ non-static. Use get_plt_entry_size method rather than plt_entry_size
+ variable.
+ (Output_data_plt_i386::do_get_plt_entry_size): New abstract virtual
+ method.
+ (Output_data_plt_i386::get_plt_entry_size): Call it.
+ (Output_data_plt_i386::do_add_eh_frame): New abstract virtual method.
+ (Output_data_plt_i386::add_eh_frame): New method to call it.
+ (Output_data_plt_i386::do_fill_first_plt_entry): New abstract virtual
+ method.
+ (Output_data_plt_i386::fill_first_plt_entry): New method to call it.
+ (Output_data_plt_i386::do_fill_plt_entry): New abstract virtual
+ method.
+ (Output_data_plt_i386::fill_plt_entry): New method to call it.
+ (Output_data_plt_i386::set_final_data_size): Use get_plt_entry_size
+ method instead of plt_entry_size.
+ (Output_data_plt_i386::plt_entry_size)
+ (Output_data_plt_i386::plt_eh_frame_fde_size)
+ (Output_data_plt_i386::plt_eh_frame_fde): Move to ...
+ (Output_data_plt_i386_standard): ... here, new class.
+ (Output_data_plt_i386_exec): New class.
+ (Output_data_plt_i386::exec_first_plt_entry): Move to ...
+ (Output_data_plt_i386_exec::first_plt_entry): ... here.
+ (Output_data_plt_i386::exec_plt_entry): Move to ...
+ (Output_data_plt_i386_exec::plt_entry): ... here.
+ (Output_data_plt_i386_dyn): New class.
+ (Output_data_plt_i386::first_plt_entry): Move to ...
+ (Output_data_plt_i386_dyn::first_plt_entry): ... here.
+ (Output_data_plt_i386::dyn_plt_entry): Move to ...
+ (Output_data_plt_i386_dyn::plt_entry): ... here.
+ (Target_i386::Target_i386): Take optional argument for the Target_info
+ pointer to use.
+ (Target_i386::do_make_data_plt): New virtual method.
+ (Target_i386::make_data_plt): New method to call it.
+ (Target_i386::make_plt_section): Use that.
+ Call this->plt_->add_eh_frame method here.
+ (Output_data_plt_i386::add_entry): Use get_plt_entry_size method
+ rather than plt_entry_size variable.
+ (Output_data_plt_i386::add_local_ifunc_entry): Likewise.
+ (Output_data_plt_i386::address_for_local): Likewise.
+ (Output_data_plt_i386::do_write): Likewise.
+ Move guts of PLT filling to...
+ (Output_data_plt_i386_exec::do_fill_first_plt_entry): ... here ...
+ (Output_data_plt_i386_exec::do_fill_plt_entry): ... and here ...
+ (Output_data_plt_i386_dyn::do_fill_first_plt_entry): ... and here ...
+ (Output_data_plt_i386_dyn::do_fill_plt_entry): ... and here.
+
+2012-05-01 Cary Coutant <ccoutant@google.com>
+
+ * dwarf_reader.cc (Dwarf_die::read_attributes)
+ (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 <mjw@redhat.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <davem@davemloft.net>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <davem@davemloft.net>
+
+ * 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 <ccoutant@google.com>
+
+ * gdb-index.cc (Gdb_index::do_write): Use Swap_aligned32 for writing
+ CU range table of gdb index.
+
+2012-04-20 David S. Miller <davem@davemloft.net>
+
+ * target.cc (Sized_target::do_adjust_elf_header): Use big_endian
+ instead of false.
+
+2012-04-16 David S. Miller <davem@davemloft.net>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <davem@davemloft.net>
+
+ * 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 <ccoutant@google.com>
+
+ * gdb-index.cc (Gdb_index_info_reader::record_cu_ranges): Allow
+ low_pc == 0.
+
+2012-04-06 Ian Lance Taylor <iant@google.com>
+
+ * timer.cc: #include <unistd.h>.
+
+2012-04-06 Roland McGrath <mcgrathr@google.com>
+
+ * configure.in (AC_CHECK_HEADERS): Add locale.h.
+ * config.in: Regenerate.
+ * configure: Regenerate.
+
+2012-04-05 Nick Clifton <nickc@redhat.com>
+
+ * configure.ac (AC_CHECK_FUNCS): Add setlocale.
+ (AM_LC_MESSAGES): Add.
+ * aclocal.m4: Regenerate.
+ * config.in: Regenerate.
+ * configure: Regenerate.
+
+2012-03-21 Cary Coutant <ccoutant@google.com>
+
+ * 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 <sys/types.h>.
+ (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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * testsuite/Makefile.am: Disable test initpri3b.
+ * testsuite/Makefile.in: Regenerate.
+
+2012-03-15 Doug Kwan <dougkwan@google.com>
+
+ * arm.cc (Target_arm::got_section): Make .got section read-only
+ if -z now is given.
+
+2012-03-15 Ian Lance Taylor <iant@google.com>
+
+ PR gold/13850
+ * layout.cc (Layout::make_output_section): Correctly mark
+ SHT_INIT_ARRAY, et. al., as relro.
+
+2012-03-14 Doug Kwan <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * resolve.cc (Symbol_table::resolve): When merging common symbols,
+ keep the larger alignment.
+
+2012-03-12 Cary Coutant <ccoutant@google.com>
+
+ * dwarf_reader.cc (Sized_dwarf_line_info::process_one_opcode): Fix
+ handling of DW_LNE_define_file.
+
+2012-03-12 Cary Coutant <ccoutant@google.com>
+
+ * reduced_debug_output.cc
+ (Output_reduced_debug_info_section::get_die_end): Add new FORM
+ codes to switch.
+
+2012-02-29 Cary Coutant <ccoutant@google.com>
+
+ * object.cc (need_decompressed_section): Add #ifdef ENABLE_THREADS.
+
+2012-02-29 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * testsuite/Makefile.am (initpri2): Add --ctors-in-init-array option.
+ * testsuite/Makefile.in: Regenerate.
+
+2012-02-14 Cary Coutant <ccoutant@google.com>
+
+ * options.cc (General_options::finalize): Disallow -pie and -static.
+
+2012-02-03 Doug Kwan <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ * configure.ac: Check if -fpic -mtls-dialect=gnu2 works.
+ * configure: Regenerated.
+
+2012-01-27 Ian Lance Taylor <iant@google.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ * incremental.cc (write_info_blocks): Correct relocation offset.
+
+2012-01-27 H.J. Lu <hongjiu.lu@intel.com>
+
+ * x86_64.cc (Relocate::tls_gd_to_ie): Support x32.
+ (Relocate::tls_gd_to_le): Likewise.
+
+2012-01-27 H.J. Lu <hongjiu.lu@intel.com>
+
+ * x86_64.cc (Scan::global): Support x32 IFUNC function pointer.
+
+2012-01-27 H.J. Lu <hongjiu.lu@intel.com>
+
+ * configure.ac: Check if -mcmodel=medium works.
+ * configure: Regenerated.
+
+2012-01-24 Cary Coutant <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <hongjiu.lu@intel.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ * x86_64.cc: Initial support for x32.
+
+2012-01-03 Cary Coutant <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ PR gold/13505
+ * target-reloc.h (apply_relocation): Replace <64, false> with
+ <size, big_endian>.
+
+2011-11-25 Nick Clifton <nickc@redhat.com>
+
+ * po/it.po: New Italian translation.
+
+2011-11-17 Sterling Augustine <saugustine@google.com>
+
+ * 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 <saugustine@google.com>
+
+ * yyscript.y (section_cmd): Add support for INCLUDE directive.
+ (file_or_sections_cmd): Likewise.
+
+2011-11-11 Doug Kwan <dougkwan@google.com>
+
+ * arm.cc (Target_arm::do_make_elf_object): Allow executable also
+ if --just-symbols is given.
+
+2011-11-10 Doug Kwan <dougkwan@google.com>
+
+ 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 <dougkwan@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <matthew.gretton-dann@arm.com>
+
+ * 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 <matthew.gretton-dann@arm.com>
+
+ * 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 <ccoutant@google.com>
+
+ 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ 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 <tmsriram@google.com>
+
+ * 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 <iant@google.com>
+
+ PR gold/13163
+ * script-sections.cc
+ (Output_section_element_dot_assignment::needs_output_section): New
+ function.
+
+2011-10-19 Ian Lance Taylor <iant@google.com>
+
+ 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 <davem@davemloft.net>
+
+ 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * readsyms.cc (Read_symbols::run): Don't queue an unblocker
+ task for members of lib groups.
+
+2011-10-17 Cary Coutant <ccoutant@google.com>
+
+ 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 <ccoutant@google.com>
+
+ * output.cc (Output_file::open_base_file): Handle case where
+ ::read returns less than requested size.
+
+2011-10-10 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ 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 <nickc@redhat.com>
+
+ * po/es.po: Updated Spanish translation.
+ * po/fi.po: Updated Finnish translation.
+
+2011-10-03 Diego Novillo <dnovillo@google.com>
+
+ * options.cc (parse_uint): Fix dereference of RETVAL.
+
+2011-09-29 Sriraman Tallam <tmsriram@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+ Ian Lance Taylor <iant@google.com>
+
+ * symtab.cc (Symbol_table::define_special_symbol): Always
+ canonicalize version string.
+
+2011-09-26 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ 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 <simonb@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * plugin.h (should_defer_layout): Modify to check for any_claimed_.
+
+2011-09-19 Cary Coutant <ccoutant@google.com>
+
+ * incremental.cc (can_incremental_update): Fix typo in comment.
+ * incremental.h (can_incremental_update): Likewise.
+
+2011-09-18 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * object.cc (Sized_relobj_file::do_layout): Remove unused local
+ variable external_symbols_offset.
+
+2011-09-12 Ian Lance Taylor <iant@google.com>
+
+ * object.cc (Sized_relobj_file::do_layout): Remove assertion which
+ triggered if object has no symbols.
+
+2011-09-09 David S. Miller <davem@davemloft.net>
+
+ * output.cc (Output_fill_debug_info::do_write): Use Swap_unaligned.
+ (Output_fill_debug_line::do_write): Likewise.
+
+2011-08-29 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <nickc@redhat.com>
+
+ * po/es.po: Updated Spanish translation.
+
+2011-08-01 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <iant@google.com>
+
+ * options.h (class General_options): Add --print-output-format.
+ Move -EL next to -EB, for better --help output.
+ * target-select.cc: Include <cstdio>, "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 <iant@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * testsuite/odr_violation2.cc (Ordering::operator()): Make
+ expression more complex.
+
+2011-07-08 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * gold/incremental.cc
+ (Output_section_incremental_inputs::write_info_blocks): Check for
+ hidden and internal symbols.
+
+2011-07-06 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * incremental.cc (Sized_incremental_binary::do_check_inputs): Add
+ debug output when command lines differ.
+
+2011-07-06 Cary Coutant <ccoutant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * object.cc (Sized_relobj_file::include_section_group): Add
+ information to comment about signature location.
+
+2011-07-02 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * dirsearch.cc (Dir_cache::read_files): Ignore ENOTDIR errors.
+
+2011-07-01 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * layout.cc (Layout::finish_dynamic_section): Don't create
+ DT_FLAGS entry if not needed.
+
+2011-06-18 Ian Lance Taylor <iant@google.com>
+
+ PR gold/12745
+ * layout.cc (Layout::layout_eh_frame): Correct handling of
+ writable .eh_frame section.
+
+2011-06-17 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * object.cc (Sized_relobj_file::do_layout): Keep warning sections
+ when making a shared library.
+
+2011-06-17 Ian Lance Taylor <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * symtab.cc (Warnings::issue_warning): Don't warn if relocation
+ occurs in same object.
+
+2011-06-14 Alan Modra <amodra@gmail.com>
+
+ * po/POTFILES.in: Regenerate.
+
+2011-06-09 Ian Lance Taylor <iant@google.com>
+
+ * script-sections.cc
+ (Orphan_output_section::set_section_addresses): For a relocatable
+ link set address to 0.
+
+2011-06-09 Cary Coutant <ccoutant@google.com>
+
+ 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 <ccoutant@google.com>
+
+ PR gold/12804
+ * testsuite/two_file_test_2_v1.cc: Change initialization of
+ v2 to keep it in .data.
+
+2011-06-07 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ 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 <nickc@redhat.com>
+
+ * dynobj.h: Fix spelling mistake in comment.
+ * output.cc: Likewise.
+
+2011-05-31 Doug Kwan <dougkwan@google.com>
+ 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 <iant@google.com>
+
+ * reloc.cc (Sized_relobj_file::do_read_relocs): Ignore empty reloc
+ sections.
+
+2011-05-29 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * binary.cc (Binary_to_elf::sized_convert): Don't crash if the
+ binary input file is empty.
+
+2011-05-27 Ian Lance Taylor <iant@google.com>
+
+ * testsuite/Makefile.am (ver_test_2.so): Use -Wl,-R,.
+ (ver_test_9.so): Likewise.
+ * testsuite/Makefile.in: Rebuild.
+
+2011-05-26 Cary Coutant <ccoutant@google.com>
+
+ * 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 <pdox@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * options.h (class General_options): Make -i a synonym for -r.
+
+2011-05-16 Ian Lance Taylor <iant@google.com>
+
+ * testsuite/tls_test_main.cc: Use semaphores instead of mutexes.
+
+2011-05-10 Cary Coutant <ccoutant@google.com>
+
+ * object.cc (Sized_relobj::do_count_local_symbols): Check for
+ strip_all (-s).
+
+2011-05-06 Ian Lance Taylor <iant@google.com>
+
+ * layout.cc (Layout::layout): If the output section flags change,
+ update the ordering.
+
+2011-04-25 Cary Coutant <ccoutant@google.com>
+
+ * 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 <sv@sw.ru>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ PR gold/12689
+ * archive.h (Incremental_archive_entry::Archive_member):
+ Initialize arg_serial_ (second constructor).
+
+2011-04-17 Ian Lance Taylor <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <sys/mman.h> 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 <sys/mman.h> 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 <errno.h>. Only #include <sys/mman.h> 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 <iant@google.com>
+
+ * incremental.cc (Sized_incr_relobj::do_add_symbols): Always
+ initialize local variable v.
+
+2011-04-11 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ppluzhnikov@google.com>
+
+ PR gold/12640
+ * dwarf_reader.cc (Sized_dwarf_line_info): Fix vector bounds
+ violation.
+
+2011-03-30 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * archive.cc (Archive::interpret_header): Return -1 if something
+ goes wrong. Change callers accordingly.
+
+2011-03-25 Cary Coutant <ccoutant@google.com>
+
+ * testsuite/Makefile.am (final_layout.stdout): Use -n option with nm.
+ * testsuite/Makefile.in: Regenerate.
+
+2011-03-23 Rafael Ávila de Espíndola <respindola@mozilla.com>
+
+ * plugin.cc (get_view): New.
+ (Plugin::load): Pass get_view to the plugin.
+ (Plugin_manager::get_view): New.
+
+2011-03-21 Ian Lance Taylor <iant@google.com>
+
+ * testsuite/final_layout.sh: Rewrite to not use dc.
+ * testsuite/relro_test.sh: Fail if dc is not present.
+
+2011-03-21 Sriraman Tallam <tmsriram@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <jyasskin@google.com>
+
+ 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 <jyasskin@google.com>
+
+ * 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 <iant@google.com>
+
+ * fileread.cc (File_read::clear_views): Don't delete the whole
+ file view.
+
+2011-03-08 Ian Lance Taylor <iant@google.com>
+
+ PR gold/12525
+ * fileread.cc: #include <climits>.
+ (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 <iant@google.com>
+
+ PR gold/12525
+ * options.h (class General_options): Add -dy and -dn.
+
+2011-03-02 Cary Coutant <ccoutant@google.com>
+
+ * testsuite/script_test_9.t: Add TLS segment.
+
+2011-03-02 Simon Baldwin <simonb@google.com>
+
+ * configure.ac: Add check for gnu_indirect_function support in
+ the toolchain building binutils.
+ * configure: Rebuild.
+
+2011-02-18 Rafael Ávila de Espíndola <respindola@mozilla.com>
+
+ * 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 <tmsriram@google.com>
+
+ * output.cc (Output_section::add_input_section): Delay fill
+ generation for section ordering.
+
+2011-02-09 Ian Lance Taylor <iant@google.com>
+
+ 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 <respindola@mozilla.com>
+
+ * plugin.cc (is_visible_from_outside): Return true for symbols
+ in the -u option.
+
+2011-02-04 Jeffrey Yasskin <jyasskin@google.com>
+
+ * symtab.cc (Odr_violation_compare::operator()): Sort by just the
+ filename.
+
+2011-02-02 Sriraman Tallam <tmsriram@google.com>
+
+ * 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 <iant@google.com>
+
+ * script.cc (script_add_extern): Rewrite to use
+ add_symbol_reference.
+
+2011-01-25 Doug Kwan <dougkwan@google.com>
+
+ * icf.cc (get_section_contents): Always lock section's object.
+
+2011-01-24 Ian Lance Taylor <iant@google.com>
+
+ * options.h (class General_options): Accept
+ --no-detect-odr-violations.
+
+2011-01-24 Ian Lance Taylor <iant@google.com>
+
+ * version.cc (version_string): Bump to 1.11.
+
+2011-01-24 Ian Lance Taylor <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * script-sections.cc (Sort_output_sections::operator()): Sort TLS
+ sections before NOBITS sections.
+
+2011-01-01 H.J. Lu <hongjiu.lu@intel.com>
+
+ * version.cc (print_version): Update copyright to 2011.
+
+2010-12-23 Cary Coutant <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * dwarf_reader.cc (Sized_dwarf_line_info::read_lines): Only keep
+ second of two consecutive entries with same offset.
+
+2010-12-16 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * 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 <iant@google.com>
+
+ 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 <Ralf.Wildenhues@gmx.de>
+
+ * 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 <Ralf.Wildenhues@gmx.de>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * arm.cc (Target_arm::Scan::get_reference_flags): Treat R_ARM_PREL31
+ like function call relocations.
+
+2010-12-07 Ian Lance Taylor <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * testsuite/icf_virtual_function_folding_test.cc (class Bar): Add
+ virtual destructor.
+
+2010-12-01 Ian Lance Taylor <iant@google.com>
+
+ * README: Update compilers known to work and fail.
+
+2010-11-23 Matthias Klose <doko@ubuntu.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ PR gold/12220
+ * dwarf_reader.cc (Sized_dwarf_line_info::Sized_dwarf_line_info):
+ Check for ".zdebug_line".
+
+2010-11-16 Doug Kwan <dougkwan@google.com>
+ Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ 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 <richard.sandiford@linaro.org>
+
+ * 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 <dougkwan@google.com>
+ Cary Coutant <ccoutant@google.com>
+
+ * 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<big_endian>::init): Copy contents of original
+ input section.
+ (Arm_input_section<big_endian>::do_write): Use saved contents of
+ original input section instead of calling Object::section_contents
+ without locking.
+ (Arm_exidx_cantunwind::do_fixed_endian_write): Find out text section
+ 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 <ccoutant@google.com>
+
+ 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 <nickc@redhat.com>
+
+ 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 <rmansfield@qnx.com>
+
+ * script-sections.cc (Script_sections::find_memory_region): Check
+ for a NULL output section pointer.
+
+2010-10-29 Doug Kwan <dougkwan@google.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * testsuite/Makefile.am: Move gcctestdir/ld rule to
+ NATIVE_OR_CROSS_LINKER.
+ * testsuite/Makefile.in: Regenerate.
+
+2010-10-20 Doug Kwan <dougkwan@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * gold/arm.cc (Target_arm::got_section): Use correct order and set
+ GOT output section to be writable.
+
+2010-10-14 Cary Coutant <ccoutant@google.com>
+
+ * debug.h (DEBUG_INCREMENTAL): New flag.
+ (debug_string_to_enum): Add DEBUG_INCREMENTAL).
+ * gold.cc (queue_initial_tasks): Check parameters for incremental link
+ mode.
+ * incremental.cc (report_command_line): Ignore all forms of
+ --incremental.
+ * layout.cc (Layout::Layout): Check parameters for incremental link
+ mode.
+ * options.cc (General_options::parse_incremental): New function.
+ (General_options::parse_no_incremental): New function.
+ (General_options::parse_incremental_full): New function.
+ (General_options::parse_incremental_update): New function.
+ (General_options::incremental_mode_): New data member.
+ (General_options::finalize): Check incremental_mode_.
+ * options.h (General_options): Update help text for --incremental.
+ Add --no-incremental, --incremental-full, --incremental-update.
+ (General_options::Incremental_mode): New enum type.
+ (General_options::incremental_mode): New function.
+ (General_options::incremental_mode_): New data member.
+ * parameters.cc (Parameters::incremental_mode_): New data member.
+ (Parameters::set_options): Set incremental_mode_.
+ (Parameters::set_incremental_full): New function.
+ (Parameters::incremental): New function.
+ (Parameters::incremental_update): New function.
+ (set_parameters_incremental_full): New function.
+ * parameters.h (Parameters::set_incremental_full): New function.
+ (Parameters::incremental): New function.
+ (Parameters::incremental_update): New function.
+ (Parameters::incremental_mode_): New data member.
+ (set_parameters_incremental_full): New function.
+ * plugin.cc (Plugin_manager::add_input_file): Check parameters for
+ incremental link mode.
+ * reloc.cc (Sized_relobj::do_read_relocs): Likewise.
+ (Sized_relobj::do_relocate_sections): Likewise.
+ * testsuite/Makefile.am (incremental_test): Use --incremental-full
+ option.
+ * testsuite/Makefile.in: Regenerate.
+ * testsuite/incremental_test.sh: Filter all forms of --incremental.
+
+2010-10-12 Viktor Kutuzov <vkutuzov@accesssoftek.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * 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 <richard.sandiford@linaro.org>
+
+ * fileread.cc (Input_file::find_file): Initialize *found_name
+ and *namep when using the fallback search for case 4.
+
+2010-10-11 Cary Coutant <ccoutant@google.com>
+
+ * options.h (class General_options): Redefine -z lazy as an alias for
+ the negation of -z now.
+
+2010-10-11 Ian Lance Taylor <iant@google.com>
+
+ * resolve.cc (symbol_to_bits): Report the value of the unsupported
+ binding.
+
+2010-10-06 Nick Clifton <nickc@redhat.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <nickc@redhat.com>
+
+ * 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 <dougkwan@google.com>
+
+ * gold/testsuite/arm_branch_out_of_range.sh: Fix broken tests.
+
+2010-09-28 Sriraman Tallam <tmsriram@google.com>
+
+ * 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 <Ralf.Wildenhues@gmx.de>
+
+ * configure: Regenerate.
+
+2010-09-17 Ian Lance Taylor <iant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * script_sections.cc (class Memory_region): Remove "NULL" from
+ vector initializations.
+
+2010-09-15 Cary Coutant <ccoutant@google.com>
+
+ * incremental.cc (Output_section_incremental_inputs::write_info_blocks):
+ Resolve forwarding symbols.
+
+2010-09-15 Doug Kwan <dougkwan@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <nickc@redhat.com>
+
+ PR gold/11997
+ * testsuite/memory_test.t: Discard any sections that are not
+ needed.
+
+2010-09-09 H.J. Lu <hongjiu.lu@intel.com>
+
+ 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 <espindola@google.com>
+
+ * 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 <espindola@google.com>
+
+ * layout.cc (Layout::set_segment_offsets): Always advance to a new page.
+
+2010-09-08 Doug Kwan <dougkwan@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <espindola@google.com>
+
+ * arm.cc (do_finalize_sections): Create the __exidx_start and
+ __exdix_end symbols even when the section is missing.
+
+2010-09-08 Nick Clifton <nickc@redhat.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * incremental.h (class Incremental_input_entry): Add virtual
+ destructor.
+
+2010-08-27 Ian Lance Taylor <iant@google.com>
+
+ * testsuite/start_lib_test_3.c: Mark t3 as used.
+
+2010-08-27 Nick Clifton <nickc@redhat.com>
+
+ * options.cc (version_script): Fix small typo in previous
+ whitespace tidyup.
+
+2010-08-25 Nick Clifton <nickc@redhat.com>
+
+ * 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 <nickc@redhat.com>
+
+ PR 11899
+ * layout.cc (segment_precedes): Sort segments by their physical
+ addresses, if they have been set.
+
+2010-08-23 Cary Coutant <ccoutant@google.com>
+
+ * 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 <nvachhar@google.com>
+ Cary Coutant <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * Makefile.in: Rebuild with automake 1.11.1.
+ * aclocal.m4: Likewise.
+ * testsuite/Makefile.in: Likewise.
+
+2010-08-19 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * common.cc (Sort_commons::operator()): Remove unnecessary code.
+
+2010-08-13 Ian Lance Taylor <iant@google.com>
+
+ * testsuite/incremental_test_1.c: Add prototype to avoid warning.
+
+2010-08-12 Cary Coutant <ccoutant@google.com>
+ Doug Kwan <dougkwan@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * testsuite/incremental_test.sh: Rewrite.
+ * testsuite/incremental_test_1.c: Rewrite.
+ * testsuite/incremental_test_2.c: Rewrite.
+
+2010-08-12 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * version.cc (version_string): Bump to 1.10.
+
+2010-08-03 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * testsuite/final_layout.sh: Use dc to convert from hex to
+ decimal.
+
+2010-07-29 Sriraman Tallam <tmsriram@google.com>
+
+ * arm.cc (Target_arm<big_endian>::gc_process_relocs): Add template
+ paramter to the call to gold::gc_process_relocs.
+ * i386.cc (Target_i386<big_endian>::gc_process_relocs): Add template
+ paramter to the call to gold::gc_process_relocs.
+ * x86_64.cc (Target_x86_64<big_endian>::gc_process_relocs): Add template
+ parameter to the call to gold::gc_process_relocs.
+ * powerpc.cc (Target_powerpc<big_endian>::gc_process_relocs): Add
+ template parameter to the call to gold::gc_process_relocs.
+ * sparc.cc (Target_sparc<big_endian>::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 <Ralf.Wildenhues@gmx.de>
+
+ * configure.ac (AM_INIT_AUTOMAKE): Use parallel-tests option.
+ * Makefile.in: Regenerate.
+ * testsuite/Makefile.in: Regenerate.
+
+2010-07-27 Jeffrey Yasskin <jyasskin@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * plugin.cc (Plugin_finish::run): Don't call cleanup handlers from
+ here.
+
+2010-07-14 Ian Lance Taylor <iant@google.com>
+
+ * descriptors.cc (Descriptors::open): Report correct name in error
+ message.
+
+2010-07-13 Doug Kwan <dougkwan@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <herron.philip@googlemail.com>
+ Ian Lance Taylor <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <espindola@google.com>
+
+ * plugin.cc (Plugin::load): Use dlerror.
+
+2010-06-26 Jeffrey Yaskin <jyasskin@google.com>
+
+ * symtab.cc (detect_odr_violations): When reporting an ODR
+ violation, report an object where the symbol is defined.
+
+2010-06-25 Doug Kwan <dougkwan@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * layout.cc (gdb_sections): Add .debug_types.
+ (lines_only_debug_sections): Likewise.
+
+2010-06-18 Rafael Espindola <espindola@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * arm.cc: Allow combining objects with no EABI version
+ information.
+
+2010-06-15 Rafael Espindola <espindola@google.com>
+
+ * plugin.cc (Plugin_hook::run): Set in_real_elf for the start symbol.
+
+2010-06-15 Viktor Kutuzov <vkutuzov@accesssoftek.com>
+
+ * fileread.cc: Only #include <sys/uio.h> if HAVE_READV.
+ (struct iovec): Correct !HAVE_READV definition.
+
+2010-06-10 Cary Coutant <ccoutant@google.com>
+
+ * 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 <nickc@redhat.com>
+
+ * 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<name>" found in an input script.
+ * script-c.h: Add prototype for script_add_library.
+
+2010-06-07 Doug Kwan <dougkwan@google.com>
+
+ * 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 <dd@crosstwine.com>
+
+ * gold-threads.cc (Lock_impl_threads::Lock_impl_threads): Correct
+ #ifdef typo.
+
+2010-06-03 Sriraman Tallam <tmsriram@google.com>
+
+ 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 <tmsriram@google.com>
+
+ * 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 <espindola@google.com>
+
+ * plugin.cc (Plugin::load): Pass the output name to the plugin.
+
+2010-06-01 Rafael Espindola <espindola@google.com>
+
+ * plugin.cc (Sized_pluginobj::::do_add_symbols): Correctly set the
+ visibility of symbols.
+
+2010-05-27 Doug Kwan <dougkwan@google.com>
+
+ * 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 <espindola@google.com>
+
+ 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 <espindola@google.com>
+
+ * script-sections.cc (Output_section_definition::set_section_addresses):
+ Check for --section-start.
+
+2010-05-26 Doug Kwan <dougkwan@google.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * timer.cc: Only #include <sys/times.h> if HAVE_TIMES is defined.
+
+2010-05-23 Doug Kwan <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ PR gold/11619
+ * arm.cc (Arm_input_section::do_output_offset): Add a cast to
+ avoid a compilation error.
+
+2010-05-19 Rafael Espindola <espindola@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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<Input_section>.
+ (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 <Ralf.Wildenhues@gmx.de>
+
+ * 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 <espindola@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <nickc@redhat.com>
+
+ * po/es.po: Updated Spanish translation.
+
+2010-04-27 H.J. Lu <hongjiu.lu@intel.com>
+
+ * Makefile.am (install-exec-local): Properly install gold as
+ default cross linker.
+ * Makefile.in: Regenerated.
+
+2010-04-27 H.J. Lu <hongjiu.lu@intel.com>
+ Nick Clifton <nickc@redhat.com>
+
+ * 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 <iant@google.com>
+
+ * layout.cc (Layout::layout_reloc): In relocatable link don't
+ combine reloc sections for grouped sections.
+
+2010-04-23 Sriraman Tallam <tmsriram@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <nickc@redhat.com>
+
+ * po/gold.pot: Updated by the Translation project.
+ * po/vi.po: Updated Vietnamese translation.
+
+2010-04-22 H.J. Lu <hongjiu.lu@intel.com>
+
+ * testsuite/Makefile.am (check_PROGRAMS): Add
+ icf_virtual_function_folding_test.
+ * testsuite/Makefile.in: Regenerated.
+
+2010-04-15 Andrew Haley <aph@redhat.com>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ * testsuite/plugin_common_test_1.c (foo): Add prototype.
+ * testsuite/plugin_common_test_2.c (foo): Likewise.
+
+2010-04-08 Doug Kwan <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <Ralf.Wildenhues@gmx.de>
+
+ * configure.ac (AM_INIT_AUTOMAKE): Add option no-dist.
+ * configure: Regenerate.
+ * Makefile.in: Regenerate.
+ * testsuite/Makefile.in: Regenerate.
+
+2010-04-06 Cary Coutant <ccoutant@google.com>
+
+ 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 <nickc@redhat.com>
+
+ * po/vi.po: New Vietnamese translation.
+
+2010-03-30 Doug Kwan <dougkwan@google.com>
+
+ * arm.cc (Target_arm::using_thumb_only): Handle v6-M
+
+2010-03-25 Doug Kwan <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * fileread.cc (find_or_make_view): Fix comment.
+
+2010-03-23 Ian Lance Taylor <iant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <davem@davemloft.net>
+
+ * sparc.cc (Target_sparc::Scan::local): Accept R_SPARC_WPLT30.
+
+2010-03-09 Sriraman Tallam <tmsriram@google.com>
+
+ * icf.cc (get_section_contents): Add '@' marker after processing the
+ merge reloc.
+
+2010-03-08 Doug Kwan <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * incremental.cc: Include "libiberty.h".
+
+2010-03-05 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+ Ian Lance Taylor <iant@google.com>
+
+ * 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 <nickc@redhat.com>
+
+ * po/fi.po: New Finnish translation.
+
+2010-03-01 Doug Kwan <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+ Ian Lance Taylor <iant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <davem@davemloft.net>
+
+ * output.h (Output_reloc<SHT_REL>::Output_reloc): Add
+ is_symbolless parameter.
+ (Output_reloc<SHT_REL>::is_symbolless): New.
+ (Output_reloc<SHT_REL>::is_symbolless_): New.
+ (Output_reloc<SHT_REL>::type_): Decrease to 29 bits.
+ (Output_reloc<SHT_RELA>::Output_reloc): Add is_symbolless parameter.
+ (Output_reloc<SHT_RELA>::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<SHT_REL>::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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <davem@davemloft.net>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <davem@davemloft.net>
+
+ * 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 <iant@google.com>
+
+ * configure.ac: Rewrite targetobjs duplicate removal code to use
+ only shell constructs.
+ * configure: Rebuild.
+
+2010-02-05 Doug Kwan <dougkwan@google.com>
+
+ 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 <dougkwan@google.com>
+
+ 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * arm.cc (Target_arm::relocate_section): Do view adjustment for all
+ types of relaxed input section.
+
+2010-02-02 Doug Kwan <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * 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 <dougkwan@google.com>
+
+ * arm.cc (Target_arm::Scan::global): General PLTs for the same set
+ of relocation types as ld.
+
+2010-01-29 Doug Kwan <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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<big_endian>::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 <vkutuzov@accesssoftek.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * 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 <dougkwan@google.com>
+
+ * arm.cc (Arm_exidx_fixup): New class.
+
+2010-01-21 Doug Kwan <dougkwan@google.com>
+
+ * arm.cc (Arm_exidx_cantunwind, Arm_exidx_merged_section): New
+ classes.
+ (Arm_exidx_section_offset_map): New type.
+
+2010-01-21 Doug Kwan <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * object.cc (Sized_relobj::do_layout): Change to call layout_gnu_stack
+ in the first pass of do_layout.
+
+2010-01-13 Doug Kwan <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ PR gold/11144
+ * testsuite/Makefile.am (dynamic_list.stdout): Use --dyn-syms
+ instead of -Ds.
+ * testsuite/Makefile.in: Regenerated.
+
+2010-01-10 Doug Kwan <dougkwan@google.com>
+
+ * options.h (DEFINE_var): Use parentheses around argument varname__
+ in macro body to avoid any unintended subsequent substitutions.
+
+2010-01-10 Ian Lance Taylor <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * dynobj.cc (big_endian>::find_dynsym_sections): Set pi to NULL in
+ the SHT_SYMTAB case.
+
+2010-01-08 Ian Lance Taylor <iant@google.com>
+
+ * object.cc (Sized_relobj::do_layout): Don't get confused if
+ layout_eh_frame returns NULL.
+
+2010-01-08 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ PR 11072
+ * layout.cc (Layout::include_section): Remove .gnu_debuglink
+ sections.
+
+2010-01-08 H.J. Lu <hongjiu.lu@intel.com>
+
+ * version.cc (print_version): Change to "Copyright 2010".
+
+2010-01-08 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ PR 11042
+ * copy-relocs.cc (Copy_relocs::emit_copy_reloc): Mark the dynamic
+ object as needed.
+
+2010-01-07 Dmitry Gorbachev <d.g.gorbachev@gmail.com>
+ Ian Lance Taylor <iant@google.com>
+
+ PR 11019
+ * object.cc: Instantiate Xindex::initialize_symtab_xindex and
+ Xindex::read_symtab_xindex.
+
+2010-01-07 Doug Kwan <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <tmsriram@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <vkutuzov@accesssoftek.com>
+
+ * Makefile.am (incremental_dump_DEPENDENCIES): Remove
+ $(THREADSLIB) and $(LIBDL).
+ * Makefile.in: Rebuild.
+
+2010-01-06 Ian Lance Taylor <iant@google.com>
+
+ 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 <map>
+ (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 <iant@google.com>
+
+ 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 <cstdio>.
+ (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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <tmsriram@google.com>
+
+ * 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 <iant@google.com>
+
+ PR 10980
+ * options.h (class General_options): Permit two dashes with
+ --retain-symbols-file.
+
+2009-12-30 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <espindola@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <cgd@google.com>
+
+ * attributes.cc (Output_attributes_section_data::do_write): Use
+ std::vector::front rather than std::vector::data.
+
+2009-12-28 Ian Lance Taylor <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * gold.cc (queue_middle_tasks): Fix formatting.
+ * object.cc (Relobj::is_section_name_included): Likewise.
+
+2009-12-23 Ian Lance Taylor <iant@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * options.cc (General_options::parse_version): Make -v continue and do
+ the link like GNU ld does.
+
+2009-12-17 Rafael Avila de Espindola <espindola@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * layout.cc (Layout::create_shstrtab): Only write out after input
+ sections if we are compressing debug sections.
+
+2009-12-15 Ian Lance Taylor <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ Revert -Wshadow changes, all changes from:
+ 2009-12-11 Doug Kwan <dougkwan@google.com>
+ 2009-12-11 Nick Clifton <nickc@redhat.com>
+ * configure.ac: Remove -Wshadow when setting WARN_CXXFLAGS.
+
+2009-12-11 Doug Kwan <dougkwan@google.com>
+
+ * 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 <nickc@redhat.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * plugin.cc (Plugin::load): Don't cast from void* to a function
+ pointer.
+
+2009-12-09 Ian Lance Taylor <iant@google.com>
+
+ * dynobj.cc (Sized_dynobj::do_read_symbols): Clear version
+ information fields.
+
+2009-12-09 H.J. Lu <hongjiu.lu@intel.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <espindola@google.com>
+
+ PR gold/11055
+ * incremental-dump.cc (dump_incremental_inputs): New.
+ (main): Use dump_incremental_inputs.
+
+2009-12-07 H.J. Lu <hongjiu.lu@intel.com>
+
+ 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ * 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 <espindola@google.com>
+
+ * incremental.cc (Incremental_inputs::sized_create_inputs_section_data):
+ Don't set the data_offset twice.
+
+2009-12-04 Rafael Avila de Espindola <espindola@google.com>
+
+ * testsuite/Makefile.in: Regenerate.
+
+2009-12-03 Doug Kwan <dougkwan@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <espindola@google.com>
+
+ * incremental.cc (Incremental_inputs_entry): Remove unused argument
+ from the get_* methods.
+
+2009-12-02 Rafael Avila de Espindola <espindola@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <espindola@google.com>
+
+ * incremental-dump.cc (main): Fix typos.
+
+2009-11-27 Rafael Avila de Espindola <espindola@google.com>
+
+ PR gold/11025
+ * incremental-dump.cc (main): Use llu to print 64 bit values.
+
+2009-11-26 Per Øyvind Karlsen <peroyvind@mandriva.org>
+ H.J. Lu <hongjiu.lu@intel.com>
+
+ * Makefile.am (incremental_dump_DEPENDENCIES): Add $(THREADSLIB)
+ $(LIBDL).
+ (incremental_dump_LDADD): Likewise.
+ * Makefile.in: Regenerated.
+
+2009-11-25 Doug Kwan <dougkwan@google.com>
+
+ Revert:
+
+ 2009-11-25 Doug Kwan <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <hongjiu.lu@intel.com>
+
+ PR gold/10930
+ * testsuite/plugin_test.c: Include "config.h".
+
+2009-11-09 Doug Kwan <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ PR 10876
+ * defstd.cc (in_segment): Set only_if_ref true for "end".
+
+2009-11-06 Doug Kwan <dougkwan@google.com>
+
+ * 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 <mikolaj@google.com>
+
+ * 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 <iant@google.com>
+
+ PR 10910
+ * output.cc (Output_segment::add_output_section): Add missing
+ return statement.
+
+2009-11-04 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * options.h (class General_options): Add --warn_constructors.
+
+2009-11-03 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <hongjiu.lu@intel.com>
+
+ * po/Make-in (.po.gmo): Don't generate .gmo files in source
+ tree.
+
+2009-10-30 Doug Kwan <dougkwan@google.com>
+
+ * arm.cc (Stub_addend_reader): Fix bug in previouls check-in.
+
+2009-10-30 Doug Kwan <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * arm.cc: Use Arm_address instead of elfcpp::Elf_types<32>::Elf_Addr.
+
+2009-10-28 Ian Lance Taylor <iant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <mikolajz@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <aldot@gcc.gnu.org>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <iant@google.com>
+
+ * plugin.cc: Include "gold.h" before other header files.
+
+2009-10-10 Chris Demetriou <cgd@google.com>
+
+ * 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 <andrew_pinski@playstation.sony.com>
+ Ian Lance Taylor <iant@google.com>
+
+ * descriptor.cc: Include <cstdio> 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 <iant@google.com>
+
+ * testsuite/retain_symbols_file_test.sh: Don't test for __tcf_0.
+
+2009-10-09 Andrew Pinski <andrew_pinski@playstation.sony.com>
+ Ian Lance Taylor <iant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <andrew_pinski@playstation.sony.com>
+
+ * pread.c: Include stdio.h.
+
+2009-10-09 Andrew Pinski <andrew_pinski@playstation.sony.com>
+
+ * plugin.cc: Don't include dlfcn.h when ENABLE_PLUGINS is not
+ defined.
+
+2009-10-09 Andrew Pinski <andrew_pinski@playstation.sony.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * 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 <mikolajz@google.com>
+
+ * 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 <mikolajz@google.com>
+
+ * incremental.cc: Include <cstdarg> 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 <vkutuzov@accesssoftek.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * testsuite/initpri1.c: Don't try to use constructor priorities if
+ compiling with gcc before 4.3.
+
+2009-09-22 Mikolaj Zalewski <mikolajz@google.com>
+
+ * 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 <csilvers@google.com>
+
+ * object.cc (Sized_relobj::do_count): Test should_retain_symbol map.
+ * options.cc: Include <cerrno> and <fstream>.
+ (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 <nickc@redhat.com>
+
+ * po/es.po: Updated Spanish translation.
+
+2009-09-17 Doug Kwan <dougkwan@google.com>
+
+ * 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 <vkutuzov@accesssoftek.com>
+
+ * 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 <ccoutant@google.com>
+
+ * testsuite/Makefile.am (MOSTLYCLEANFILES): Add more generated files.
+ * testsuite/Makefile.in: Regenerate.
+
+2009-09-11 Nick Clifton <nickc@redhat.com>
+
+ * po/gold.pot: Updated by the Translation project.
+
+2009-09-08 Cary Coutant <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * output.cc (Output_file::resize): Call map_no_anonymous rather
+ than map.
+
+2009-09-01 Mikolaj Zalewski <mikolajz@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * options.h (General_options::no_keep_memory): Remove incorrect
+ short option.
+
+2009-08-24 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * Makefile.am (am__skiplex, am__skipyacc): New.
+ * Makefile.in: Regenerate.
+
+2009-08-22 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <cgd@google.com>
+
+ * testsuite/debug_msg.sh: Match .* rather than ${srcdir} when
+ checking source file names in error messages.
+
+2009-08-18 Doug Kwan <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * gold.h (FUNCTION_NAME): Define.
+ (gold_unreachable): Use FUNCTION_NAME.
+
+2009-08-12 Sriraman Tallam <tmsriram@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * dynobj.h (Sized_dynobj::do_section_entsize): Revert the previous
+ patch.
+
+2009-08-07 Sriraman Tallam <tmsriram@google.com>
+ * dynobj.h (Sized_dynobj::do_section_entsize): Add return to avoid
+ compiler warnings.
+
+2009-08-06 Sriraman Tallam <tmsriram@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <cgd@google.com>
+
+ * layout.cc (is_compressible_debug_section): Fix incorrect
+ comment about compressed section names.
+
+2009-07-20 Ian Lance Taylor <ian@airs.com>
+
+ PR 10419
+ * x86_64.cc (Target_x86_64::do_code_fill): Correct nop sequences.
+
+2009-07-16 Ian Lance Taylor <iant@google.com>
+
+ PR 10400
+ * layout.h: #include <map>.
+ (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 <iant@google.com>
+
+ * merge.cc (Object_merge_map::initialize_input_to_output_map):
+ Reserve space in the hash table.
+
+2009-07-06 Mikolaj Zalewski <mikolajz@google.com>
+
+ * 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 <ian@airs.com>
+
+ * freebsd.h (Target_freebsd::do_adjust_elf_header): Use size
+ instead of 32.
+
+2009-06-24 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * script-sections.cc (Output_section_definition::
+ set_section_addresses): Rename shadowing local load_address to
+ laddr.
+
+2009-06-24 Ian Lance Taylor <iant@google.com>
+
+ PR 10244
+ * reloc.cc (relocate_sections): Skip empty relocation sections.
+
+2009-06-23 Ian Lance Taylor <iant@google.com>
+
+ PR 10156
+ * layout.cc (Layout::create_note): Use choose_output_section
+ rather than make_output_section.
+
+2009-06-23 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * configure.ac: Call AC_CHECK_DECLS using C, not C++.
+ * configure: Rebuild.
+
+2009-06-23 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * layout.cc (Layout::section_name_mapping): Add mapping for
+ special ARM sections.
+
+2009-06-03 Doug Kwan <dougkwan@google.com>
+
+ * arm.cc (utils::sign_extend): Reverse test in gold_assert.
+ (utils::has_overflow): Same.
+
+2009-06-03 Ian Lance Taylor <iant@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * arm.cc (Target_arm::scan::global): Use || instead of |.
+
+2009-06-02 Doug Kwan <dougkwan@google.com>
+
+ * 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 <mikolajz@google.com>
+
+ * incremental.cc (Incremental_inputs::report_command_line): Filter
+ out --incremental-* options.
+
+2009-05-29 Doug Kwan <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <nickc@redhat.com>
+
+ * po/id.po: New Indonesian translation.
+ * po/gold.pot: Updated template file.
+
+2009-05-22 Sriraman Tallam <tmsriram@google.com>
+
+ * 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 <tmsriram@google.com>
+
+ * 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 <dougkwan@google.com>
+
+ * 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 <iant@google.com>
+
+ * configure.ac: Check for declarations for cases where libiberty.h
+ checks HAVE_DECL_xxx.
+ * configure, config.in: Rebuild.
+
+2009-05-15 Mikolaj Zalewski <mikolajz@google.com>
+
+ * 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 <iant@google.com>
+
+ * x86_64.cc (do_adjust_output_section): Set entsize to
+ plt_entry_size.
+
+2009-04-23 Elliott Hughes <enh@google.com>
+
+ * output.cc (Output_file::close): After short writes, continue
+ writing from the correct offset in the buffer being written.
+
+2009-04-23 Chris Demetriou <cgd@google.com>
+
+ * 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 <mikolajz@google.com>
+
+ * 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 <iant@google.com>
+ Mikolaj Zalewski <mikolajz@google.com>
+
+ * 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 <iant@google.com>
+
+ * ffsll.c (ffsll): Correct implementation.
+
+2009-03-27 Ian Lance Taylor <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * symtab.h (needs_plt_entry): Check for unsatisfied reference from
+ an executable.
+ (needs_dynamic_reloc): Likewise.
+
+2009-03-24 Ian Lance Taylor <iant@google.com>
+
+ * 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 <espindola@google.com>
+
+ * 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 <enh@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <mikolajz@google.com>
+
+ * incremental.cc: New file.
+ * Makefile.am (CCFILES): Add incremental.cc.
+ * Makefile.in: Rebuild.
+
+2009-03-19 Paul Pluzhnikov <ppluzhnikov@google.com>
+
+ * layout.cc (Layout::output_section_name): Preserve names
+ of '.note.' sections.
+
+2009-03-19 Ian Lance Taylor <iant@google.com>
+
+ * descriptors.cc (Descriptors::open): Check that the options are
+ valid before using them.
+
+2009-03-18 Ian Lance Taylor <iant@google.com>
+
+ * script-sections.h: Include <list>.
+ (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 <iant@google.com>
+
+ * 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 <ppluzhnikov@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <nickc@redhat.com>
+
+ * po/es.po: New Spanish translation.
+
+2009-03-06 Cary Coutant <ccoutant@google.com>
+
+ * options.cc (parse_short_option): Keep dash_z from registering itself.
+
+2009-03-03 Ian Lance Taylor <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * configure.ac: Check for byteswap.h.
+ * configure: Rebuild.
+ * config.in: Rebuild.
+
+2009-03-01 Mikolaj Zalewski <mikolajz@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <ccoutant@google.com>
+
+ * 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 <espindola@google.com>
+
+ * archive.cc (Archive::include_member): Update calls to add_symbols.
+ * dynobj.cc (Sized_dynobj<size, big_endian>::make_version_map): Add
+ the Layout argument.
+ * dynobj.h (do_add_symbols): Add the Layout argument.
+ * object.cc (Sized_relobj<size, big_endian>::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<size, big_endian>::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 <iant@google.com>
+
+ * object.cc (Sized_relobj::do_layout): Make info message start
+ with lower case letter.
+
+2009-02-06 Mikolaj Zalewski <mikolajz@google.com>
+
+ * 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 <cgd@google.com>
+
+ * 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 <baldrick@free.fr>
+
+ 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 <mikolajz@google.com>
+
+ * script.cc (Lazy_demangler): New class.
+ (Version_script_info::get_symbol_version_helper): Demangle a
+ symbol only once.
+
+2009-01-29 Cary Coutant <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * version.cc (version_string): Bump to 1.9.
+
+ * gold.h: Include <cstring> and <stdint.h>.
+ * version.cc: Include <cstdio>.
+ * 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 <tmsriram@google.com>
+
+ * 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 <me.sourceware@sourceware.org>
+
+ * 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 <schwab@suse.de>
+
+ * 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 <schwab@suse.de>
+
+ * configure.tgt (powerpc64-*): Fix targ_obj.
+
+2009-01-15 Ian Lance Taylor <iant@google.com>
+
+ * object.cc (Sized_relobj::write_local_symbols): Don't write out
+ local symbols when stripping all symbols.
+
+2009-01-14 Cary Coutant <ccoutant@google.com>
+
+ * output.cc (Output_reloc): Add explicit instantiations.
+
+2009-01-14 Cary Coutant <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * version.cc (version_string): Bump to 1.8.
+
+2008-12-23 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * options.h (class General_options): Add --no case for
+ --export-dynamic.
+
+2008-12-16 Cary Coutant <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ PR 7091
+ * target-reloc.h (Default_scan_relocatable_relocs): For each
+ function, map r_type == 0 to RELOC_DISCARD.
+
+2008-12-10 Cary Coutant <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <espindola@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * plugin.cc (ld_plugin_message): Change format parameter to const.
+ Fix mismatch between new[] and delete.
+
+2008-11-14 Cary Coutant <ccoutant@google.com>
+
+ * reloc.cc (Sized_relobj::do_read_relocs): Use constant invalid_address
+ instead of -1U.
+
+2008-11-05 Craig Silverstein <csilvers@google.com>
+
+ * 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 <csilvers@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * plugin.cc (make_sized_plugin_object): Fix conditional
+ compilation to work when not all targets are enabled.
+
+2008-09-29 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <aoliva@redhat.com>
+
+ * 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 <aoliva@redhat.com>
+
+ * 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 <cgd@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * fileread.cc (File_read::make_view): Add check for attempt to map
+ beyond end of file.
+
+2008-09-05 Cary Coutant <ccoutant@google.com>
+
+ * symtab.cc (Symbol_table::add_from_dynobj): Fix typos in
+ explicit instantiations.
+
+2008-08-28 Kris Van Hees <kris.van.hees@oracle.com>
+
+ 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 <csilvers@google.com>
+
+ * fileread.cc (File_read::open): Do not lock the file unless it
+ was successfully opened.
+
+2008-08-14 Cary Coutant <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <amodra@bigpond.net.au>
+
+ * Makefile.am (POTFILES.in): Set LC_ALL=C.
+ * Makefile.in: Regenerate.
+ * po/POTFILES.in: Regenerate.
+
+2008-07-29 Ian Lance Taylor <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <clocale>. 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 <iant@google.com>
+
+ 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 <simonb@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <simonb@google.com>
+
+ * symtab.cc (Symbol_table::sized_write_symbol): Set symbol size
+ to zero when writing undefined symbols.
+
+2008-07-22 Ian Lance Taylor <iant@google.com>
+
+ * output.cc (Output_section::add_input_section): Don't try to
+ merge empty merge sections.
+
+2008-07-21 Craig Silverstein <csilvers@google.com>
+
+ * symtab.cc (Symbol_table::warn_about_undefined_dynobj_symbol):
+ Include symbol version in error message.
+
+2008-07-20 Chris Demetriou <cgd@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * layout.cc (Layout::include_section): Do not discard unrecognized
+ SHT_STRTAB sections.
+
+2008-06-30 Craig Silverstein <csilvers@cs.stanford.edu>
+
+ * 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 <yosh@gimp.org>
+
+ PR 6585
+ * symtab.cc (Symbol_table::add_undefined_symbols_from_command_line):
+ Correct typo.
+
+2008-06-30 Ian Lance Taylor <iant@google.com>
+
+ 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 <ccoutant@google.com>
+
+ * 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 <csilvers@google.com>
+
+ * version.cc (version_string): Bump to 1.7
+
+2008-06-18 Craig Silverstein <csilvers@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <edelsohn@gnu.org>
+
+ * powerpc.cc (Output_data_plt_powerpc::do_write): 8 + 4 = 0xC.
+
+2008-06-12 David Edelsohn <edelsohn@gnu.org>
+ David S. Miller <davem@davemloft.net>
+
+ * 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 <iant@google.com>
+
+ * testsuite/relro_test.cc: Include <cstdio>, <cstdlib>, and
+ <exception>.
+ (throwing, orig_terminate): New static variables.
+ (terminate_handler): New static function.
+ (t2): Set terminate handler.
+
+2008-06-05 Kris Van Hees <kris.van.hees@oracle.com>
+
+ PR 6584
+ * binary.cc (Binary_to_elf::sized_convert): Fix .data
+ alignment.
+
+2008-05-30 Cary Coutant <ccoutant@google.com>
+
+ * 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 <kris.van.hees@oracle.com>
+
+ PR 6407
+ * target-reloc.h (relocate_for_relocatable): Fix new_offset
+ calculation.
+
+2008-05-28 Caleb Howe <cshowe@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <cstdio> 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ PR 6493
+ * gold.cc (gold_nomem): Use return value of write.
+
+2008-05-08 Ian Lance Taylor <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <cstring>.
+ (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 <csilvers@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * i386.cc (Relocate::relocate): Fix typos for R_386_PC16 and
+ R_386_PC8 relocations.
+
+2008-04-23 Ian Lance Taylor <iant@google.com>
+
+ * 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 <bonzini@gnu.org>
+
+ * aclocal.m4: Regenerate.
+ * configure: Regenerate.
+
+2008-04-19 Ian Lance Taylor <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <davem@davemloft.net>
+
+ * options.cc (General_options::parse_V): New function.
+ * options.h: Add entries for -V and -Qy.
+
+2008-04-17 Ian Lance Taylor <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <davem@davemloft.net>
+
+ * 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 <iant@google.com>
+
+ * 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<elfcpp::SHT_REL>): 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 <iant@google.com>
+
+ * 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 <davem@davemloft.net>
+
+ * 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 <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <davem@davemloft.net>
+ Ian Lance Taylor <iant@google.com>
+
+ * 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 <davem@davemloft.net>
+
+ * 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 <iant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <csilvers@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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<SHT_REL>::local_section_offset): Add
+ addend parameter. Change caller. Handle merge sections.
+ (Output_reloc<SHT_REL>::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<SHT_REL>): 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 <ccoutant@google.com>
+
+ * 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 <csilvers@google.com>
+
+ * 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 <davem@davemloft.net>
+
+ * 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 <csilvers@google.com>
+
+ * TODO: New file.
+
+2008-04-02 Ian Lance Taylor <iant@google.com>
+
+ * 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 <ccoutant@google.com>
+
+ 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * 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 <cstring>
+ * dwarf_reader.cc: Include <algorithm>
+ * main.cc: Include <cstring>.
+ * options.cc: Include <cstring>.
+ * output.cc: Include <cstring>.
+ * script.cc: Include <cstring>.
+ * script.h: Include <string>.
+ * symtab.cc: Include <cstring> and <algorithm>.
+ * target-select.cc: Include <cstring>.
+ * version.cc: Include <string>.
+ * testsuite/testmain.cc: Include <cstdlib>.
+ * configure, config.in: Rebuild.
+
+2008-03-25 Ian Lance Taylor <iant@google.com>
+
+ * 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 <vector>.
+ (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 <ccoutant@google.com>
+
+ * 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 <bje@au.ibm.com>
+
+ * yyscript.y: Fix spelling error in comment.
+
+2008-03-24 Ian Lance Taylor <iant@google.com>
+
+ * 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 <cerrno>, <fcntl.h>, <unistd.h>,
+ "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 <iant@google.com>
+
+ * 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 <iant@google.com>
+
+ * gold.h: Include <cstddef> and <sys/types.h>
+ * options.h: Include <cstring>.
+
+2008-03-21 Ian Lance Taylor <iant@google.com>
+
+ * 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
+# <http://www.gnu.org/licenses/>.
+#
+
+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
+# <http://www.gnu.org/licenses/>.
+#
+
+
+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 <conftest.tar])
+ grep GrepMe conftest.dir/file >/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 <iant@google.com>.
+
+// 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 <cerrno>
+#include <cstring>
+#include <climits>
+#include <vector>
+#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<char*>(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<const char*>(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<const elfcpp::Elf_Word*>(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<const char*>(pword + nsyms);
+ section_size_type names_size =
+ reinterpret_cast<const char*>(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<section_size_type>(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<const Archive_header*>(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<size_t>(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<size_t>(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<int>(sizeof hdr->ar_name))
+ {
+ gold_error(_("%s: malformed archive header name at %zu"),
+ this->name().c_str(), static_cast<size_t>(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<size_t>(x) >= this->extended_names_.size())
+ {
+ gold_error(_("%s: bad extended name index at %zu"),
+ this->name().c_str(), static_cast<size_t>(off));
+ return -1;
+ }
+
+ const char* name = this->extended_names_.data() + x;
+ const char* name_end = strchr(name, '\n');
+ if (static_cast<size_t>(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<size_t>(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<off_t>(sizeof(Archive_header)))
+ {
+ if (filesize != this->off_)
+ {
+ gold_error(_("%s: short archive header at %zu"),
+ this->archive_->filename().c_str(),
+ static_cast<size_t>(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<const Archive_header*>(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<off_t>(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<Nested_archive_table::iterator, bool> 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<size_t>(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<off_t, Archive_member>::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<off_t, Archive_member>::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<Armap_entry>::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<Archive_member>::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 <iant@google.com>.
+
+// 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 <string>
+#include <vector>
+
+#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<size_t>(val); }
+ };
+
+ // For keeping track of open nested archives in a thin archive file.
+ typedef Unordered_map<std::string, Archive*> 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_entry> 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<bool> armap_checked_;
+ // Track which elements have been included by offset.
+ Unordered_set<off_t, Seen_hash> seen_offsets_;
+ // Table of objects whose symbols have been pre-read.
+ std::map<off_t, Archive_member> 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<Archive_member> 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 <dougkwan@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include "gold.h"
+
+#include <cstdio>
+#include <cstring>
+#include <stack>
+#include <string>
+#include <vector>
+
+#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_t> 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 <dougkwan@google.com>.
+
+// 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*> 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 <this->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 <this->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 <dougkwan@google.com>.
+
+// 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_<n> 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 <dougkwan@google.com> based on the i386 code
+// by Ian Lance Taylor <iant@google.com>.
+// 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 <cstring>
+#include <limits>
+#include <cstdio>
+#include <string>
+#include <algorithm>
+#include <map>
+#include <utility>
+#include <set>
+
+#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<bool big_endian>
+class Output_data_plt_arm;
+
+template<bool big_endian>
+class Output_data_plt_arm_standard;
+
+template<bool big_endian>
+class Stub_table;
+
+template<bool big_endian>
+class Arm_input_section;
+
+class Arm_exidx_cantunwind;
+
+class Arm_exidx_merged_section;
+
+class Arm_exidx_fixup;
+
+template<bool big_endian>
+class Arm_output_section;
+
+class Arm_exidx_input_section;
+
+template<bool big_endian>
+class Arm_relobj;
+
+template<bool big_endian>
+class Arm_relocate_functions;
+
+template<bool big_endian>
+class Arm_output_data_got;
+
+template<bool big_endian>
+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<size_t, section_size_type> 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<Reloc> 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<section_offset_type>(-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<true>(view, view_size);
+ else
+ this->do_fixed_endian_write<false>(view, view_size);
+ }
+
+ // This must be overridden if a child class uses the THUMB16_SPECIAL_TYPE
+ // instruction template.
+ virtual uint16_t
+ do_thumb16_special(size_t)
+ { gold_unreachable(); }
+
+ private:
+ // A template to implement do_write.
+ template<bool big_endian>
+ 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<unsigned int>(-1);
+ // We assume we never jump to this address.
+ static const Arm_address invalid_address = static_cast<Arm_address>(-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<char>(
+ (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<true>(view, view_size);
+ else
+ this->do_fixed_endian_v4bx_write<false>(view, view_size);
+ }
+
+ private:
+ // A template to implement do_write.
+ template<bool big_endian>
+ 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<bool big_endian>
+class Stub_table : public Output_data
+{
+ public:
+ Stub_table(Arm_input_section<big_endian>* 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<big_endian>*
+ 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<Arm_address, Cortex_a8_stub*> 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<big_endian>*, 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<big_endian>*,
+ 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<big_endian>*, Output_section*,
+ unsigned char*, Arm_address, section_size_type);
+
+ // Unordered map of relocation stubs.
+ typedef
+ Unordered_map<Reloc_stub::Key, Reloc_stub*, Reloc_stub::Key::hash,
+ Reloc_stub::Key::equal_to>
+ Reloc_stub_map;
+
+ // List of Cortex-A8 stubs ordered by addresses of branches being
+ // fixed up in output.
+ typedef std::map<Arm_address, Cortex_a8_stub*> Cortex_a8_stub_list;
+ // List of Arm V4BX relocation stubs ordered by associated registers.
+ typedef std::vector<Arm_v4bx_stub*> Arm_v4bx_stub_list;
+
+ // Owner of this stub table.
+ Arm_input_section<big_endian>* 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<true>(of);
+ else
+ this->do_fixed_endian_write<false>(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<bool big_endian>
+ void inline
+ do_fixed_endian_write(Output_file*);
+
+ // The object containing the section pointed by this.
+ Relobj* relobj_;
+ // The section index of the section pointed by this.
+ 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<section_offset_type, section_offset_type>
+ 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<bool big_endian>
+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<big_endian>*
+ stub_table() const
+ { return this->stub_table_; }
+
+ // Set the stub_table.
+ void
+ set_stub_table(Stub_table<big_endian>* 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<big_endian>*
+ as_arm_input_section(Output_relaxed_input_section* poris)
+ { return static_cast<Arm_input_section<big_endian>*>(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<uint64_t>(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<section_offset_type, uint32_t>(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<big_endian>* 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<bool big_endian>
+ 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<bool big_endian>
+class Arm_output_section : public Output_section
+{
+ public:
+ typedef std::vector<std::pair<Relobj*, unsigned int> > 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<big_endian>*, 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<big_endian>*
+ as_arm_output_section(Output_section* os)
+ { return static_cast<Arm_output_section<big_endian>*>(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<big_endian>*,
+ std::vector<Output_relaxed_input_section*>*,
+ 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<section_offset_type>(-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<bool big_endian>
+class Arm_relobj : public Sized_relobj_file<32, big_endian>
+{
+ public:
+ static const Arm_address invalid_address = static_cast<Arm_address>(-1);
+
+ Arm_relobj(const std::string& name, Input_file* input_file, off_t offset,
+ const typename elfcpp::Ehdr<32, big_endian>& ehdr)
+ : 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<big_endian>*
+ 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<big_endian>* 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<big_endian>*, 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<big_endian>*
+ as_arm_relobj(Relobj* relobj)
+ { return static_cast<Arm_relobj<big_endian>*>(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<unsigned int, Arm_address> 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_symbol_position, char,
+ Mapping_symbol_position_less> 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<bool>(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<unsigned int>* 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<char>*,
+ Stringpool_template<char>*);
+
+ 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<big_endian>*);
+
+ // 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<big_endian>*> Stub_table_list;
+ typedef Unordered_map<unsigned int, const Arm_exidx_input_section*>
+ 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<bool> 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<bool>* 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<bool big_endian>
+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<big_endian>*
+ as_arm_dynobj(Dynobj* dynobj)
+ { return static_cast<Arm_dynobj<big_endian>*>(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<int sh_type, bool big_endian>
+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<sh_type,
+ 32, big_endian>::Reloc& /* reloc */) const;
+};
+
+// Specialized Stub_addend_reader for SHT_REL type relocation sections.
+
+template<bool big_endian>
+struct Stub_addend_reader<elfcpp::SHT_REL, big_endian>
+{
+ elfcpp::Elf_types<32>::Elf_Swxword
+ operator()(
+ unsigned int,
+ const unsigned char*,
+ const typename Reloc_types<elfcpp::SHT_REL, 32, big_endian>::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<bool big_endian>
+struct Stub_addend_reader<elfcpp::SHT_RELA, big_endian>
+{
+ elfcpp::Elf_types<32>::Elf_Swxword
+ operator()(
+ unsigned int,
+ const unsigned char*,
+ const typename Reloc_types<elfcpp::SHT_RELA, 32,
+ big_endian>::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<bool big_endian>
+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_reloc> 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<bool big_endian, int sh_type, typename Classify_reloc>
+class Arm_scan_relocatable_relocs :
+ public Default_scan_relocatable_relocs<sh_type, Classify_reloc>
+{
+ 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<big_endian>* arm_target =
+ Target_arm<big_endian>::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<bool big_endian>
+class Target_arm : public Sized_target<32, big_endian>
+{
+ public:
+ typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, big_endian>
+ 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<size_t>(-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<big_endian>*
+ 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<big_endian>*
+ find_arm_input_section(Relobj* relobj, unsigned int shndx) const;
+
+ // Make a new Stub_table
+ Stub_table<big_endian>*
+ new_stub_table(Arm_input_section<big_endian>*);
+
+ // 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<big_endian>*
+ default_target()
+ {
+ gold_assert(parameters->target().machine_code() == elfcpp::EM_ARM
+ && parameters->target().is_big_endian() == big_endian);
+ return static_cast<Target_arm<big_endian>*>(
+ 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<big_endian>*, 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<big_endian>*
+ make_data_plt(Layout* layout, Output_data_space* got_plt)
+ { return this->do_make_data_plt(layout, got_plt); }
+
+ // Make an ELF object.
+ Object*
+ do_make_elf_object(const std::string&, Input_file*, off_t,
+ 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<big_endian>(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<big_endian>*
+ do_make_data_plt(Layout* layout, Output_data_space* got_plt)
+ {
+ return new Output_data_plt_arm_standard<big_endian>(layout, got_plt);
+ }
+
+ private:
+ // The class which scans relocations.
+ class Scan
+ {
+ 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<big_endian>::Status
+ relocate_tls(const Relocate_info<32, big_endian>*, Target_arm<big_endian>*,
+ size_t, const elfcpp::Rel<32, big_endian>&, unsigned int,
+ 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<big_endian>*
+ 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<big_endian>*
+ 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<int sh_type>
+ 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<big_endian>*, 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<big_endian>*> Stub_table_list;
+
+ // Map input section to Arm_input_section.
+ typedef Unordered_map<Section_id,
+ Arm_input_section<big_endian>*,
+ Section_id_hash>
+ Arm_input_section_map;
+
+ // Map output addresses to relocs for Cortex-A8 erratum.
+ typedef Unordered_map<Arm_address, const Cortex_a8_reloc*>
+ Cortex_a8_relocs_info;
+
+ // The GOT section.
+ Arm_output_data_got<big_endian>* got_;
+ // The PLT section.
+ Output_data_plt_arm<big_endian>* 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<elfcpp::SHT_REL, 32, big_endian> 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<bool big_endian>
+const Target::Target_info Target_arm<big_endian>::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<bool big_endian>
+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<big_endian> 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<big_endian>*, 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<big_endian>*, 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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<Valtype*>(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<Valtype*>(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<Valtype*>(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<big_endian>* 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<Valtype*>(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<Valtype*>(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<Valtype*>(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<Valtype*>(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<Valtype*>(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<Valtype*>(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<Valtype*>(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<Valtype*>(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<Valtype*>(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<Valtype*>(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<big_endian>* object,
+ const Arm_address address,
+ const bool is_interworking)
+ {
+
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(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<big_endian>* 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 <addr>)
+ 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<Valtype*>(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<Valtype*>(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<Valtype*>(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<Valtype*>(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<bool big_endian>
+typename Arm_relocate_functions<big_endian>::Status
+Arm_relocate_functions<big_endian>::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<big_endian>* 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<Valtype*>(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<big_endian>* arm_target =
+ Target_arm<big_endian>::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<big_endian>* 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<bool big_endian>
+typename Arm_relocate_functions<big_endian>::Status
+Arm_relocate_functions<big_endian>::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<big_endian>* 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<Valtype*>(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<big_endian>* arm_target =
+ Target_arm<big_endian>::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<big_endian>* 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<bool big_endian>
+typename Arm_relocate_functions<big_endian>::Status
+Arm_relocate_functions<big_endian>::thm_jump19(
+ unsigned char* view,
+ const Arm_relobj<big_endian>* 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<Valtype*>(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<bool big_endian>
+Arm_output_data_got<big_endian>*
+Target_arm<big_endian>::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<big_endian>(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<bool big_endian>
+typename Target_arm<big_endian>::Reloc_section*
+Target_arm<big_endian>::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<bool big_endian>
+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<section_size_type>(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
+ // <stub-type>:<symbol name>:<addend>.
+ 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<int>(len));
+ delete[] buffer;
+ return std::string(buffer);
+ }
+ else
+ {
+ // local symbol key name
+ // <stub-type>:<object>:<r_sym>:<addend>.
+ 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<int>(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<true>* big_endian_target =
+ Target_arm<true>::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<false>* little_endian_target =
+ Target_arm<false>::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<int64_t>(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<int64_t>(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<cond> X
+ // after:
+ //
+ static const Insn_template elf32_arm_stub_a8_veneer_b_cond[] =
+ {
+ Insn_template::thumb16_bcond_insn(0xd001), // b<cond>.n true
+ Insn_template::thumb32_b_insn(0xf000b800, -4), // b.w after
+ Insn_template::thumb32_b_insn(0xf000b800, -4) // true:
+ // b.w X
+ };
+
+ // 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<n>, #1
+ Insn_template::arm_insn(0x01a0f000), // moveq pc, r<n>
+ Insn_template::arm_insn(0xe12fff10) // bx r<n>
+ };
+
+ // 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<bool big_endian>
+void
+Stub_table<big_endian>::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<bool big_endian>
+void
+Stub_table<big_endian>::relocate_stub(
+ Stub* stub,
+ const Relocate_info<32, big_endian>* relinfo,
+ Target_arm<big_endian>* 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<bool big_endian>
+void
+Stub_table<big_endian>::relocate_stubs(
+ const Relocate_info<32, big_endian>* relinfo,
+ Target_arm<big_endian>* 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<section_size_type>(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<bool big_endian>
+void
+Stub_table<big_endian>::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 big_endian>
+bool
+Stub_table<big_endian>::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<bool big_endian>
+void
+Stub_table<big_endian>::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<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::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<bool big_endian>
+void
+Stub_table<big_endian>::apply_cortex_a8_workaround_to_address_range(
+ Target_arm<big_endian>* 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<bool big_endian>
+void
+Arm_input_section<big_endian>::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<uint32_t, uint64_t>(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, &section_size, false);
+ this->original_size_ =
+ convert_types<uint32_t, uint64_t>(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<bool big_endian>
+void
+Arm_input_section<big_endian>::do_write(Output_file* of)
+{
+ // We have to write out the original section content.
+ gold_assert(this->original_contents_ != NULL);
+ of->write(this->offset(), this->original_contents_,
+ this->original_size_);
+
+ // 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<bool big_endian>
+void
+Arm_input_section<big_endian>::set_final_data_size()
+{
+ off_t off = convert_types<off_t, uint64_t>(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<bool big_endian>
+void
+Arm_input_section<big_endian>::do_reset_address_and_file_offset()
+{
+ // Size of the original input section contents.
+ off_t off = convert_types<off_t, uint64_t>(this->original_size_);
+
+ // If this is a stub table owner, account for the stub table size.
+ if (this->is_stub_table_owner())
+ {
+ Stub_table<big_endian>* 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<bool big_endian>
+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<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::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<big_endian>::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<section_offset_type>(original_size);
+ section_offset_type out_max =
+ convert_types<section_offset_type>(this->data_size());
+ for (Arm_exidx_section_offset_map::const_iterator p =
+ this->section_offset_map_.begin();
+ 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<size_t>(in_end - in_start + 1);
+ if (out_end != -1)
+ {
+ size_t out_chunk_size =
+ convert_types<size_t>(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<section_offset_type>(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<bool big_endian>
+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<const Valtype*>(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<bool big_endian>
+void
+Arm_output_section<big_endian>::create_stub_group(
+ Input_section_list::const_iterator begin,
+ Input_section_list::const_iterator end,
+ Input_section_list::const_iterator owner,
+ Target_arm<big_endian>* target,
+ std::vector<Output_relaxed_input_section*>* 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<big_endian>* arm_input_section;
+ if (owner->is_relaxed_input_section())
+ {
+ arm_input_section =
+ Arm_input_section<big_endian>::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<Object> 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<big_endian>* 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<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::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<bool big_endian>
+void
+Arm_output_section<big_endian>::group_sections(
+ section_size_type group_size,
+ bool stubs_always_after_branch,
+ Target_arm<big_endian>* 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<Output_relaxed_input_section*> 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<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::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<bool big_endian>
+void
+Arm_output_section<big_endian>::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<bool big_endian>
+void
+Arm_output_section<big_endian>::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<Output_section::Input_section> 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, Section_id_hash> Section_id_set;
+ typedef Unordered_map<Section_id, const Output_section::Input_section*,
+ Section_id_hash> 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, Section_id_hash> 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<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::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<Object> 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<big_endian>(exidx_input_section,
+ exidx_contents,
+ exidx_size,
+ &section_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<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::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<bool big_endian>
+void
+Arm_output_section<big_endian>::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<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::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 big_endian>
+bool
+Arm_relobj<big_endian>::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 big_endian>
+bool
+Arm_relobj<big_endian>::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<bool big_endian>
+Arm_address
+Arm_relobj<big_endian>::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 big_endian>
+bool
+Arm_relobj<big_endian>::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<bool big_endian>
+void
+Arm_relobj<big_endian>::scan_section_for_cortex_a8_erratum(
+ const elfcpp::Shdr<32, big_endian>& shdr,
+ unsigned int shndx,
+ Output_section* os,
+ Target_arm<big_endian>* 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<bool big_endian>
+void
+Arm_relobj<big_endian>::scan_sections_for_stubs(
+ Target_arm<big_endian>* 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<size, big_endian>::do_count_local_symbols.
+
+template<bool big_endian>
+void
+Arm_relobj<big_endian>::do_count_local_symbols(
+ Stringpool_template<char>* pool,
+ Stringpool_template<char>* 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<bool> 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<unsigned int>(strtabshdr.get_sh_type()));
+ return;
+ }
+ const char* pnames =
+ reinterpret_cast<const char*>(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<big_endian>::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<bool big_endian>
+void
+Arm_relobj<big_endian>::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<big_endian>* arm_target =
+ Target_arm<big_endian>::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<big_endian>* 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<big_endian>* 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<big_endian>* 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 big_endian>
+bool
+Arm_relobj<big_endian>::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<bool big_endian>
+void
+Arm_relobj<big_endian>::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<bool big_endian>
+void
+Arm_relobj<big_endian>::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<unsigned int> 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<unsigned int, unsigned int> 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<Reloc_map::iterator, bool> 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<bool big_endian>
+void
+Arm_relobj<big_endian>::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<bool big_endian>
+void
+Arm_relobj<big_endian>::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<bool big_endian>
+void
+Arm_dynobj<big_endian>::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<bool big_endian>
+elfcpp::Elf_types<32>::Elf_Swxword
+Stub_addend_reader<elfcpp::SHT_REL, big_endian>::operator()(
+ unsigned int r_type,
+ const unsigned char* view,
+ const typename Reloc_types<elfcpp::SHT_REL, 32, big_endian>::Reloc&) const
+{
+ typedef class Arm_relocate_functions<big_endian> RelocFuncs;
+
+ switch (r_type)
+ {
+ case elfcpp::R_ARM_CALL:
+ case elfcpp::R_ARM_JUMP24:
+ case elfcpp::R_ARM_PLT32:
+ {
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+ const Valtype* wv = reinterpret_cast<const Valtype*>(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<const Valtype*>(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<const Valtype*>(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<bool big_endian>
+void
+Arm_output_data_got<big_endian>::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<bool big_endian>
+void
+Arm_output_data_got<big_endian>::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<bool big_endian>
+void
+Arm_output_data_got<big_endian>::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<const Sized_symbol<32>*>(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<Valtype*>(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<bool big_endian>
+class Output_data_plt_arm : public Output_section_data
+{
+ public:
+ typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, big_endian>
+ 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<bool big_endian>
+Output_data_plt_arm<big_endian>::Output_data_plt_arm(Layout* layout,
+ uint64_t addralign,
+ Output_data_space* got_plt)
+ : Output_section_data(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<bool big_endian>
+void
+Output_data_plt_arm<big_endian>::do_adjust_output_section(Output_section* os)
+{
+ os->set_entsize(0);
+}
+
+// Add an entry to the PLT.
+
+template<bool big_endian>
+void
+Output_data_plt_arm<big_endian>::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<bool big_endian>
+class Output_data_plt_arm_standard : public Output_data_plt_arm<big_endian>
+{
+ public:
+ Output_data_plt_arm_standard(Layout* layout, Output_data_space* got_plt)
+ : Output_data_plt_arm<big_endian>(layout, 4, got_plt)
+ { }
+
+ protected:
+ // Return the offset of the first non-reserved PLT entry.
+ virtual unsigned int
+ do_first_plt_entry_offset() const
+ { return sizeof(first_plt_entry); }
+
+ // Return the size of a PLT entry.
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return sizeof(plt_entry); }
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address);
+
+ virtual void
+ do_fill_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset);
+
+ private:
+ // Template for the first PLT entry.
+ static const uint32_t first_plt_entry[5];
+
+ // Template for subsequent PLT entries.
+ static const uint32_t plt_entry[3];
+};
+
+// ARM PLTs.
+// FIXME: This is not very flexible. Right now this has only been tested
+// on armv5te. If we are to support additional architecture features like
+// Thumb-2 or BE8, we need to make this more flexible like GNU ld.
+
+// The first entry in the PLT.
+template<bool big_endian>
+const uint32_t Output_data_plt_arm_standard<big_endian>::first_plt_entry[5] =
+{
+ 0xe52de004, // str lr, [sp, #-4]!
+ 0xe59fe004, // ldr lr, [pc, #4]
+ 0xe08fe00e, // add lr, pc, lr
+ 0xe5bef008, // ldr pc, [lr, #8]!
+ 0x00000000, // &GOT[0] - .
+};
+
+template<bool big_endian>
+void
+Output_data_plt_arm_standard<big_endian>::do_fill_first_plt_entry(
+ unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address)
+{
+ // Write first PLT entry. All but the last word are constants.
+ const size_t num_first_plt_words = (sizeof(first_plt_entry)
+ / sizeof(plt_entry[0]));
+ for (size_t i = 0; i < num_first_plt_words - 1; i++)
+ elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]);
+ // Last word in first PLT entry is &GOT[0] - .
+ elfcpp::Swap<32, big_endian>::writeval(pov + 16,
+ got_address - (plt_address + 16));
+}
+
+// Subsequent entries in the PLT.
+
+template<bool big_endian>
+const uint32_t Output_data_plt_arm_standard<big_endian>::plt_entry[3] =
+{
+ 0xe28fc600, // add ip, pc, #0xNN00000
+ 0xe28cca00, // add ip, ip, #0xNN000
+ 0xe5bcf000, // ldr pc, [ip, #0xNNN]!
+};
+
+template<bool big_endian>
+void
+Output_data_plt_arm_standard<big_endian>::do_fill_plt_entry(
+ unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset)
+{
+ int32_t offset = ((got_address + got_offset)
+ - (plt_address + plt_offset + 8));
+
+ gold_assert(offset >= 0 && offset < 0x0fffffff);
+ uint32_t plt_insn0 = plt_entry[0] | ((offset >> 20) & 0xff);
+ elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0);
+ uint32_t plt_insn1 = plt_entry[1] | ((offset >> 12) & 0xff);
+ elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1);
+ uint32_t plt_insn2 = plt_entry[2] | (offset & 0xfff);
+ elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2);
+}
+
+// Write out the PLT. This uses the hand-coded instructions above,
+// and adjusts them as needed. This is all specified by the arm ELF
+// Processor Supplement.
+
+template<bool big_endian>
+void
+Output_data_plt_arm<big_endian>::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<section_size_type>(pov - oview) == oview_size);
+ gold_assert(static_cast<section_size_type>(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<bool big_endian>
+void
+Target_arm<big_endian>::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<bool big_endian>
+unsigned int
+Target_arm<big_endian>::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<bool big_endian>
+unsigned int
+Target_arm<big_endian>::first_plt_entry_offset() const
+{
+ return this->plt_->first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<bool big_endian>
+unsigned int
+Target_arm<big_endian>::plt_entry_size() const
+{
+ return this->plt_->get_plt_entry_size();
+}
+
+// Get the section to use for TLS_DESC relocations.
+
+template<bool big_endian>
+typename Target_arm<big_endian>::Reloc_section*
+Target_arm<big_endian>::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<bool big_endian>
+void
+Target_arm<big_endian>::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<bool big_endian>
+unsigned int
+Target_arm<big_endian>::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<big_endian>* 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<bool big_endian>
+tls::Tls_optimization
+Target_arm<big_endian>::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<bool big_endian>
+int
+Target_arm<big_endian>::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<bool big_endian>
+void
+Target_arm<big_endian>::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<bool big_endian>
+void
+Target_arm<big_endian>::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<bool big_endian>
+inline void
+Target_arm<big_endian>::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<big_endian>* 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<big_endian>::optimize_tls_reloc(!output_is_shared,
+ r_type);
+ switch (r_type)
+ {
+ case elfcpp::R_ARM_TLS_GD32: // Global-dynamic
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Arm_output_data_got<big_endian>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+ 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<big_endian>* 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<bool big_endian>
+void
+Target_arm<big_endian>::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<bool big_endian>
+inline bool
+Target_arm<big_endian>::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<bool big_endian>
+inline bool
+Target_arm<big_endian>::Scan::local_reloc_may_be_function_pointer(
+ Symbol_table*,
+ Layout*,
+ Target_arm<big_endian>* 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<bool big_endian>
+inline bool
+Target_arm<big_endian>::Scan::global_reloc_may_be_function_pointer(
+ Symbol_table*,
+ Layout*,
+ Target_arm<big_endian>* 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<bool big_endian>
+inline void
+Target_arm<big_endian>::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<big_endian>* 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<big_endian>::optimize_tls_reloc(is_final, r_type);
+ switch (r_type)
+ {
+ case elfcpp::R_ARM_TLS_GD32: // Global-dynamic
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Arm_output_data_got<big_endian>* got
+ = target->got_section(symtab, layout);
+ 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<big_endian>* 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<bool big_endian>
+void
+Target_arm<big_endian>::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<big_endian> Arm;
+ typedef typename Target_arm<big_endian>::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<bool big_endian>
+void
+Target_arm<big_endian>::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<big_endian>::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<bool big_endian>
+void
+Target_arm<big_endian>::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<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::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<big_endian>* arm_dynobj =
+ Arm_dynobj<big_endian>::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<big_endian>* os =
+ Arm_output_section<big_endian>::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<bool big_endian>
+inline bool
+Target_arm<big_endian>::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<bool big_endian>
+inline bool
+Target_arm<big_endian>::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<big_endian> 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<big_endian>* object =
+ Arm_relobj<big_endian>::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<big_endian>::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<Arm_address>(1);
+ symval.set_output_value(stripped_value);
+ psymval = &symval;
+ }
+
+ // To look up relocation stubs, we need to pass the symbol table index of
+ // a local symbol.
+ 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<bool big_endian>
+inline typename Arm_relocate_functions<big_endian>::Status
+Target_arm<big_endian>::Relocate::relocate_tls(
+ const Relocate_info<32, big_endian>* relinfo,
+ Target_arm<big_endian>* 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<big_endian> 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<big_endian>::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<bool big_endian>
+void
+Target_arm<big_endian>::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<big_endian>::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<bool big_endian>
+unsigned int
+Target_arm<big_endian>::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<bool big_endian>
+void
+Target_arm<big_endian>::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<big_endian, elfcpp::SHT_REL,
+ Relocatable_size_for_reloc> 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<bool big_endian>
+void
+Target_arm<big_endian>::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<bool big_endian>
+void
+Target_arm<big_endian>::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<elfcpp::SHT_REL, 32, big_endian>::Reloc Reltype;
+ typedef typename Reloc_types<elfcpp::SHT_REL, 32, big_endian>::Reloc_write
+ Reltype_write;
+ const Arm_address invalid_address = static_cast<Arm_address>(0) - 1;
+
+ const Arm_relobj<big_endian>* object =
+ Arm_relobj<big_endian>::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<section_offset_type, Arm_address>(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<Arm_address>(1);
+ symval.set_output_value(stripped_value);
+ psymval = &symval;
+ }
+
+ unsigned char* paddend = view + offset;
+ typename Arm_relocate_functions<big_endian>::Status reloc_status =
+ Arm_relocate_functions<big_endian>::STATUS_OKAY;
+ switch (r_type)
+ {
+ case elfcpp::R_ARM_ABS8:
+ reloc_status = Arm_relocate_functions<big_endian>::abs8(paddend, object,
+ psymval);
+ break;
+
+ case elfcpp::R_ARM_ABS12:
+ reloc_status = Arm_relocate_functions<big_endian>::abs12(paddend, object,
+ psymval);
+ break;
+
+ case elfcpp::R_ARM_ABS16:
+ reloc_status = Arm_relocate_functions<big_endian>::abs16(paddend, object,
+ psymval);
+ break;
+
+ case elfcpp::R_ARM_THM_ABS5:
+ reloc_status = Arm_relocate_functions<big_endian>::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<big_endian>::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<big_endian>::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<big_endian>::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<big_endian>::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<big_endian>::thm_jump19(paddend, object,
+ psymval, 0, thumb_bit);
+ break;
+
+ case elfcpp::R_ARM_THM_JUMP6:
+ reloc_status =
+ Arm_relocate_functions<big_endian>::thm_jump6(paddend, object, psymval,
+ 0);
+ break;
+
+ case elfcpp::R_ARM_THM_JUMP8:
+ reloc_status =
+ Arm_relocate_functions<big_endian>::thm_jump8(paddend, object, psymval,
+ 0);
+ break;
+
+ case elfcpp::R_ARM_THM_JUMP11:
+ reloc_status =
+ Arm_relocate_functions<big_endian>::thm_jump11(paddend, object, psymval,
+ 0);
+ break;
+
+ case elfcpp::R_ARM_PREL31:
+ reloc_status =
+ Arm_relocate_functions<big_endian>::prel31(paddend, object, psymval, 0,
+ thumb_bit);
+ break;
+
+ case elfcpp::R_ARM_THM_PC8:
+ reloc_status =
+ Arm_relocate_functions<big_endian>::thm_pc8(paddend, object, psymval,
+ 0);
+ break;
+
+ case elfcpp::R_ARM_THM_PC12:
+ reloc_status =
+ Arm_relocate_functions<big_endian>::thm_pc12(paddend, object, psymval,
+ 0);
+ break;
+
+ case elfcpp::R_ARM_THM_ALU_PREL_11_0:
+ reloc_status =
+ Arm_relocate_functions<big_endian>::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<big_endian>::STATUS_OKAY:
+ break;
+ case Arm_relocate_functions<big_endian>::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<big_endian>::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<bool big_endian>
+uint64_t
+Target_arm<big_endian>::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<bool big_endian>
+unsigned int
+Target_arm<big_endian>::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 big_endian>
+bool
+Target_arm<big_endian>::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<bool big_endian>
+void
+Target_arm<big_endian>::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<bool big_endian>
+void
+Target_arm<big_endian>::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<bool big_endian>
+Object*
+Target_arm<big_endian>::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<big_endian>* obj =
+ new Arm_relobj<big_endian>(name, input_file, offset, ehdr);
+ obj->setup();
+ return obj;
+ }
+ else if (et == elfcpp::ET_DYN)
+ {
+ Sized_dynobj<32, big_endian>* obj =
+ new Arm_dynobj<big_endian>(name, input_file, offset, ehdr);
+ 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<bool big_endian>
+int
+Target_arm<big_endian>::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<bool big_endian>
+void
+Target_arm<big_endian>::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<bool big_endian>
+int
+Target_arm<big_endian>::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<bool big_endian>
+std::string
+Target_arm<big_endian>::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, "<unknown value %u>", value);
+ return std::string(buffer);
+ }
+}
+
+// Return the string value to store in TAG_CPU_name.
+
+template<bool big_endian>
+std::string
+Target_arm<big_endian>::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, "<unknown CPU value %u>", value);
+ return std::string(buffer);
+ }
+}
+
+// Query attributes object to see if integer divide instructions may be
+// present in an object.
+
+template<bool big_endian>
+bool
+Target_arm<big_endian>::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 big_endian>
+bool
+Target_arm<big_endian>::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<bool big_endian>
+void
+Target_arm<big_endian>::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 "<unknown CPU n>", 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<bool big_endian>
+Arm_input_section<big_endian>*
+Target_arm<big_endian>::new_arm_input_section(
+ Relobj* relobj,
+ unsigned int shndx)
+{
+ Section_id sid(relobj, shndx);
+
+ Arm_input_section<big_endian>* arm_input_section =
+ new Arm_input_section<big_endian>(relobj, shndx);
+ arm_input_section->init();
+
+ // Register new Arm_input_section in map for look-up.
+ std::pair<typename Arm_input_section_map::iterator, bool> 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<bool big_endian>
+Arm_input_section<big_endian>*
+Target_arm<big_endian>::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<bool big_endian>
+Stub_table<big_endian>*
+Target_arm<big_endian>::new_stub_table(Arm_input_section<big_endian>* owner)
+{
+ Stub_table<big_endian>* stub_table =
+ new Stub_table<big_endian>(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<bool big_endian>
+void
+Target_arm<big_endian>::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<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::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<Arm_address>(1);
+ symval.set_output_value(stripped_value);
+ psymval = &symval;
+ }
+
+ // Get the symbol value.
+ Symbol_value<32>::Value value = psymval->value(arm_relobj, 0);
+
+ // 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<big_endian>* stub_table =
+ arm_relobj->stub_table(relinfo->data_shndx);
+ gold_assert(stub_table != NULL);
+
+ // Locate stub by destination.
+ Reloc_stub::Key stub_key(stub_type, gsym, arm_relobj, r_sym, addend);
+
+ // 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<bool big_endian>
+template<int sh_type>
+void inline
+Target_arm<big_endian>::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<sh_type, 32, big_endian>::Reloc Reltype;
+ const int reloc_size =
+ Reloc_types<sh_type, 32, big_endian>::reloc_size;
+
+ Arm_relobj<big_endian>* arm_object =
+ Arm_relobj<big_endian>::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<const Valtype*>(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<big_endian>* 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<sh_type, big_endian> 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<const Sized_symbol<32>*>(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<bool big_endian>
+void
+Target_arm<big_endian>::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<elfcpp::SHT_REL>(
+ 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<elfcpp::SHT_RELA>(
+ 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<bool big_endian>
+void
+Target_arm<big_endian>::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(&section_list);
+ for (Layout::Section_list::const_iterator p = section_list.begin();
+ p != section_list.end();
+ ++p)
+ {
+ Arm_output_section<big_endian>* output_section =
+ Arm_output_section<big_endian>::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 big_endian>
+bool
+Target_arm<big_endian>::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<big_endian>* 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<big_endian>::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<big_endian>* 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<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::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<Object> 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<const Output_section*> 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<big_endian>* 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<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::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<Object> tl(task, arm_relobj);
+ arm_relobj->update_output_local_symbol_count();
+ }
+ }
+ }
+
+ return continue_relaxation;
+}
+
+// Relocate a stub.
+
+template<bool big_endian>
+void
+Target_arm<big_endian>::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<bool big_endian>
+int
+Target_arm<big_endian>::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<bool big_endian>
+int
+Target_arm<big_endian>::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<bool big_endian>
+void
+Target_arm<big_endian>::scan_span_for_cortex_a8_erratum(
+ Arm_relobj<big_endian>* 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<const Valtype*>(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<c>.W.
+ is_b = (insn & 0xf800d000U) == 0xf0009000U;
+ // Encoding T1: BL<c>.W.
+ is_bl = (insn & 0xf800d000U) == 0xf000d000U;
+ // Encoding T2: BLX<c>.W.
+ is_blx = (insn & 0xf800d000U) == 0xf000c000U;
+ // Encoding T3: B<c>.W (not permitted in IT block).
+ is_bcc = ((insn & 0xf800d000U) == 0xf0008000U
+ && (insn & 0x07f00000U) != 0x03800000U);
+ }
+
+ bool is_32bit_branch = is_b || is_bl || is_blx || is_bcc;
+
+ // If this instruction is a 32-bit THUMB branch that crosses a 4K
+ // page boundary and it follows 32-bit non-branch instruction,
+ // we need to work around.
+ 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<big_endian> 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<big_endian>* 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<bool big_endian>
+void
+Target_arm<big_endian>::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<Valtype*>(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<big_endian> 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<bool big_endian>
+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<big_endian>(); }
+};
+
+// Fix .ARM.exidx section coverage.
+
+template<bool big_endian>
+void
+Target_arm<big_endian>::fix_exidx_coverage(
+ Layout* layout,
+ const Input_objects* input_objects,
+ Arm_output_section<big_endian>* 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<Output_section*, output_section_address_less_than>
+ 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<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::as_arm_relobj(*p);
+ std::vector<unsigned int> 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<big_endian>::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<big_endian>* arm_output_section =
+ Arm_output_section<big_endian>::as_arm_output_section(*p);
+ arm_output_section->append_text_sections_to_list(&sorted_text_sections);
+ }
+
+ exidx_section->fix_exidx_coverage(layout, sorted_text_sections, symtab,
+ merge_exidx_entries(), task);
+}
+
+template<bool big_endian>
+void
+Target_arm<big_endian>::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<bool big_endian>
+class Output_data_plt_arm_nacl;
+
+template<bool big_endian>
+class Target_arm_nacl : public Target_arm<big_endian>
+{
+ public:
+ Target_arm_nacl()
+ : Target_arm<big_endian>(&arm_nacl_info)
+ { }
+
+ protected:
+ virtual Output_data_plt_arm<big_endian>*
+ do_make_data_plt(Layout* layout, Output_data_space* got_plt)
+ { return new Output_data_plt_arm_nacl<big_endian>(layout, got_plt); }
+
+ private:
+ static const Target::Target_info arm_nacl_info;
+};
+
+template<bool big_endian>
+const Target::Target_info Target_arm_nacl<big_endian>::arm_nacl_info =
+{
+ 32, // size
+ big_endian, // is_big_endian
+ elfcpp::EM_ARM, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ false, // has_code_fill
+ true, // is_default_stack_executable
+ false, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/lib/ld-nacl-arm.so.1", // dynamic_linker
+ 0x20000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // common_pagesize (overridable by -z common-page-size)
+ true, // isolate_execinstr
+ 0x10000000, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0, // large_common_section_flags
+ ".ARM.attributes", // attributes_section
+ "aeabi", // attributes_vendor
+ "_start" // entry_symbol_name
+};
+
+template<bool big_endian>
+class Output_data_plt_arm_nacl : public Output_data_plt_arm<big_endian>
+{
+ public:
+ Output_data_plt_arm_nacl(Layout* layout, Output_data_space* got_plt)
+ : Output_data_plt_arm<big_endian>(layout, 16, got_plt)
+ { }
+
+ protected:
+ // Return the offset of the first non-reserved PLT entry.
+ virtual unsigned int
+ do_first_plt_entry_offset() const
+ { return sizeof(first_plt_entry); }
+
+ // Return the size of a PLT entry.
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return sizeof(plt_entry); }
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address);
+
+ virtual void
+ do_fill_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset);
+
+ private:
+ inline uint32_t arm_movw_immediate(uint32_t value)
+ {
+ return (value & 0x00000fff) | ((value & 0x0000f000) << 4);
+ }
+
+ inline uint32_t arm_movt_immediate(uint32_t value)
+ {
+ return ((value & 0x0fff0000) >> 16) | ((value & 0xf0000000) >> 12);
+ }
+
+ // Template for the first PLT entry.
+ static const uint32_t first_plt_entry[16];
+
+ // Template for subsequent PLT entries.
+ static const uint32_t plt_entry[4];
+};
+
+// The first entry in the PLT.
+template<bool big_endian>
+const uint32_t Output_data_plt_arm_nacl<big_endian>::first_plt_entry[16] =
+{
+ // First bundle:
+ 0xe300c000, // movw ip, #:lower16:&GOT[2]-.+8
+ 0xe340c000, // movt ip, #:upper16:&GOT[2]-.+8
+ 0xe08cc00f, // add ip, ip, pc
+ 0xe52dc008, // str ip, [sp, #-8]!
+ // Second bundle:
+ 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<bool big_endian>
+void
+Output_data_plt_arm_nacl<big_endian>::do_fill_first_plt_entry(
+ unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address)
+{
+ // Write first PLT entry. All but first two words are constants.
+ const size_t num_first_plt_words = (sizeof(first_plt_entry)
+ / sizeof(first_plt_entry[0]));
+
+ int32_t got_displacement = got_address + 8 - (plt_address + 16);
+
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 0, first_plt_entry[0] | arm_movw_immediate (got_displacement));
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 4, first_plt_entry[1] | arm_movt_immediate (got_displacement));
+
+ for (size_t i = 2; i < num_first_plt_words; ++i)
+ elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]);
+}
+
+// Subsequent entries in the PLT.
+
+template<bool big_endian>
+const uint32_t Output_data_plt_arm_nacl<big_endian>::plt_entry[4] =
+{
+ 0xe300c000, // movw ip, #:lower16:&GOT[n]-.+8
+ 0xe340c000, // movt ip, #:upper16:&GOT[n]-.+8
+ 0xe08cc00f, // add ip, ip, pc
+ 0xea000000, // b .Lplt_tail
+};
+
+template<bool big_endian>
+void
+Output_data_plt_arm_nacl<big_endian>::do_fill_plt_entry(
+ unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset)
+{
+ // Calculate the displacement between the PLT slot and the
+ // common tail that's part of the special initial PLT slot.
+ int32_t tail_displacement = (plt_address + (11 * sizeof(uint32_t))
+ - (plt_address + plt_offset
+ + sizeof(plt_entry) + sizeof(uint32_t)));
+ gold_assert((tail_displacement & 3) == 0);
+ tail_displacement >>= 2;
+
+ gold_assert ((tail_displacement & 0xff000000) == 0
+ || (-tail_displacement & 0xff000000) == 0);
+
+ // Calculate the displacement between the PLT slot and the entry
+ // in the GOT. The offset accounts for the value produced by
+ // adding to pc in the penultimate instruction of the PLT stub.
+ const int32_t got_displacement = (got_address + got_offset
+ - (plt_address + sizeof(plt_entry)));
+
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 0, plt_entry[0] | arm_movw_immediate (got_displacement));
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 4, plt_entry[1] | arm_movt_immediate (got_displacement));
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 8, plt_entry[2]);
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 12, plt_entry[3] | (tail_displacement & 0x00ffffff));
+}
+
+// Target selectors.
+
+template<bool big_endian>
+class Target_selector_arm_nacl
+ : public Target_selector_nacl<Target_selector_arm<big_endian>,
+ Target_arm_nacl<big_endian> >
+{
+ public:
+ Target_selector_arm_nacl()
+ : Target_selector_nacl<Target_selector_arm<big_endian>,
+ Target_arm_nacl<big_endian> >(
+ "arm",
+ big_endian ? "elf32-bigarm-nacl" : "elf32-littlearm-nacl",
+ big_endian ? "armelfb_nacl" : "armelf_nacl")
+ { }
+};
+
+Target_selector_arm_nacl<false> target_selector_arm;
+Target_selector_arm_nacl<true> target_selector_armbe;
+
+} // End anonymous namespace.
diff --git a/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 <dougkwan@google.com>.
+// 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 <limits>
+
+#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<unsigned char>* buffer) const
+{
+ // No need to write default attributes.
+ if (this->is_default_attribute())
+ return;
+
+ // Write tag.
+ write_unsigned_LEB_128(buffer, convert_types<uint64_t, int>(tag));
+
+ // Write integer value.
+ if (Object_attribute::attribute_type_has_int_value(this->type_))
+ write_unsigned_LEB_128(buffer,
+ convert_types<uint64_t, int>(this->int_value_));
+
+ // Write string value.
+ if (Object_attribute::attribute_type_has_string_value(this->type_))
+ {
+ const unsigned char* start =
+ reinterpret_cast<const unsigned char*>(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);
+
+ // <size> <vendor_name> NUL 0x1 <size>
+ 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<Other_attributes::iterator, bool> 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<unsigned char>* buffer) const
+{
+ // Write subsection size.
+ size_t voa_size = this->size();
+ uint32_t voa_size_as_u32 = convert_types<uint32_t, size_t>(voa_size);
+ insert_into_vector<32>(buffer, voa_size_as_u32);
+
+ // Write vendor name.
+ const unsigned char* vendor_start =
+ reinterpret_cast<const unsigned char*>(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<uint32_t, size_t>(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' <sections for each vendor>
+ 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<const char*>(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<int, uint64_t>(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<int, uint64_t>(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<unsigned int, uint64_t>(val);
+ string_arg = reinterpret_cast<const char *>(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<const char *>(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<unsigned int, uint64_t>(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<unsigned char>* 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<unsigned char> 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 <dougkwan@google.com>.
+// 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 <map>
+
+#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<unsigned char>* 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<int, Object_attribute*> 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<unsigned char>* 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<unsigned char>*) 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 <iant@google.com>.
+
+// 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 <cerrno>
+#include <cstring>
+#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<int size, bool big_endian>
+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<size>::sym_size;
+
+ size_t output_size = (elfcpp::Elf_sizes<size>::ehdr_size
+ + 5 * elfcpp::Elf_sizes<size>::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<size, big_endian>(&pout);
+
+ this->write_section_header<size, big_endian>("", &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<size, big_endian>(".data", &shstrtab,
+ elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ data_offset,
+ filesize, 0, 0,
+ 1, 0, &pout);
+ this->write_section_header<size, big_endian>(".symtab", &shstrtab,
+ elfcpp::SHT_SYMTAB,
+ 0, symtab_offset, 4 * sym_size,
+ 3, 1, align, sym_size, &pout);
+ this->write_section_header<size, big_endian>(".strtab", &shstrtab,
+ elfcpp::SHT_STRTAB,
+ 0, strtab_offset,
+ strtab.get_strtab_size(),
+ 0, 0, 1, 0, &pout);
+ this->write_section_header<size, big_endian>(".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<size, big_endian>("", &strtab, 0, 0, &pout);
+ this->write_symbol<size, big_endian>(start_symbol_name, &strtab, 0, 1,
+ &pout);
+ this->write_symbol<size, big_endian>(end_symbol_name, &strtab, filesize, 1,
+ &pout);
+ this->write_symbol<size, big_endian>(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<size_t>(pout - buffer) == output_size);
+
+ this->data_ = buffer;
+ this->filesize_ = output_size;
+
+ f.unlock(task);
+
+ return true;
+}
+
+// Write out the file header.
+
+template<int size, bool big_endian>
+void
+Binary_to_elf::write_file_header(unsigned char** ppout)
+{
+ elfcpp::Ehdr_write<size, big_endian> 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<size>::ehdr_size);
+ oehdr.put_e_flags(0);
+ oehdr.put_e_ehsize(elfcpp::Elf_sizes<size>::ehdr_size);
+ oehdr.put_e_phentsize(0);
+ oehdr.put_e_phnum(0);
+ oehdr.put_e_shentsize(elfcpp::Elf_sizes<size>::shdr_size);
+ oehdr.put_e_shnum(5);
+ oehdr.put_e_shstrndx(4);
+
+ *ppout += elfcpp::Elf_sizes<size>::ehdr_size;
+}
+
+// Write out a section header.
+
+template<int size, bool big_endian>
+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<size, big_endian> 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<size>::shdr_size;
+}
+
+// Write out a symbol.
+
+template<int size, bool big_endian>
+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<size, big_endian> 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<size>::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 <iant@google.com>.
+
+// 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 <string>
+
+#include "elfcpp.h"
+
+namespace gold
+{
+
+class Task;
+
+template<typename Stringpool_char>
+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<int size, bool big_endian>
+ bool
+ sized_convert(const Task*);
+
+ template<int size, bool big_endian>
+ void
+ write_file_header(unsigned char**);
+
+ template<int size, bool big_endian>
+ void
+ write_section_header(const char*, const Stringpool_template<char>*,
+ elfcpp::SHT, unsigned int, section_size_type,
+ section_size_type, unsigned int, unsigned int,
+ unsigned int, unsigned int, unsigned char**);
+
+ template<int size, bool big_endian>
+ void
+ write_symbol(const std::string&, const Stringpool_template<char>*,
+ 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 <iant@google.com>.
+
+// 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 <algorithm>
+
+#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<int size>
+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<int size>
+bool
+Sort_commons<size>::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<size>* psa = symtab->get_sized_symbol<size>(pa);
+ const Sized_symbol<size>* psb = symtab->get_sized_symbol<size>(pb);
+
+ // The size.
+ typename Sized_symbol<size>::Size_type sa = psa->symsize();
+ typename Sized_symbol<size>::Size_type sb = psb->symsize();
+
+ // The alignment.
+ typename Sized_symbol<size>::Value_type aa = psa->value();
+ typename Sized_symbol<size>::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<int size>
+void
+Symbol_table::do_allocate_commons(Layout* layout, Mapfile* mapfile,
+ Sort_commons_order sort_order)
+{
+ if (!this->commons_.empty())
+ this->do_allocate_commons_list<size>(layout, COMMONS_NORMAL,
+ &this->commons_, mapfile,
+ sort_order);
+ if (!this->tls_commons_.empty())
+ this->do_allocate_commons_list<size>(layout, COMMONS_TLS,
+ &this->tls_commons_, mapfile,
+ sort_order);
+ if (!this->small_commons_.empty())
+ this->do_allocate_commons_list<size>(layout, COMMONS_SMALL,
+ &this->small_commons_, mapfile,
+ sort_order);
+ if (!this->large_commons_.empty())
+ this->do_allocate_commons_list<size>(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<int size>
+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<size>* ssym = this->get_sized_symbol<size>(sym);
+ if (ssym->value() > addralign)
+ addralign = ssym->value();
+ }
+ }
+ if (!any)
+ return;
+
+ // Sort the common symbols.
+ std::sort(commons->begin(), commons->end(),
+ Sort_commons<size>(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<size>* ssym = this->get_sized_symbol<size>(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 <iant@google.com>.
+
+// 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 <iant@google.com>.
+
+// 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 <zlib.h>
+#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<Bytef*>(*compressed_data) + header_size,
+ compressed_size,
+ reinterpret_cast<const Bytef*>(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<Bytef*>(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<const char*>(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<const char*>(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 <iant@google.com>.
+
+// 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 <string>
+
+#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 <byteswap.h> 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 <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <ext/hash_map> header file. */
+#undef HAVE_EXT_HASH_MAP
+
+/* Define to 1 if you have the <ext/hash_set> 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 <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define if your <locale.h> file defines LC_MESSAGES. */
+#undef HAVE_LC_MESSAGES
+
+/* Define to 1 if you have the <locale.h> 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 <memory.h> 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 <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> 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 <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> 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<off_t> is usable */
+#undef HAVE_TR1_HASH_OFF_T
+
+/* Define to 1 if you have the <tr1/unordered_map> 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 <tr1/unordered_set> header file. */
+#undef HAVE_TR1_UNORDERED_SET
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the <windows.h> header file. */
+#undef HAVE_WINDOWS_H
+
+/* Define to 1 if you have the <zlib.h> 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 </dev/null 6>&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 <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#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<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ 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 <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#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 <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#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 <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* 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 <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> 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 <limits.h>
+#else
+# include <assert.h>
+#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 <ac_nonexistent.h>
+_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 <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> 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 <limits.h>
+#else
+# include <assert.h>
+#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 <ac_nonexistent.h>
+_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 <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+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 <string.h>
+
+_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 <stdlib.h>
+
+_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 <ctype.h>
+#include <stdlib.h>
+#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 <sys/types.h>
+ #include <sys/param.h>
+
+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 <sys/types.h>
+ #include <sys/param.h>
+
+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 <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+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 <limits.h>
+
+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 <features.h>
+#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 <omp.h>
+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 <features.h>
+#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 <features.h>
+#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 <sys/mman.h>
+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 <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> 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 <limits.h>
+#else
+# include <assert.h>
+#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 <ac_nonexistent.h>
+_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 <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> 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 <limits.h>
+#else
+# include <assert.h>
+#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 <ac_nonexistent.h>
+_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 <tr1/unordered_map>
+void bar() { ::std::tr1::unordered_map<int, int> 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<off_t> is defined" >&5
+$as_echo_n "checking whether std::tr1::hash<off_t> 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 <sys/types.h>
+#include <tr1/unordered_map>
+std::tr1::hash<off_t> 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<typename T> extern void foo(const char*, ...)
+ __attribute__ ((__format__ (__printf__, 1, 2)));
+template<typename T> void foo(const char* format, ...) {}
+void bar() { foo<int>("%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 <sys/stat.h>
+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 <locale.h>
+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 2>/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
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$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
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$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 <http://www.gnu.org/licenses/>.
+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 <features.h>
+#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 <omp.h>
+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 <features.h>
+#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 <features.h>
+#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 <sys/mman.h>
+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 <tr1/unordered_map>
+void bar() { ::std::tr1::unordered_map<int, int> 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<off_t> is defined],
+[gold_cv_hash_off_t],
+[CXXFLAGS_hold=$CXXFLAGS
+CXXFLAGS="$CXXFLAGS $LFS_CFLAGS"
+AC_COMPILE_IFELSE([
+#include <sys/types.h>
+#include <tr1/unordered_map>
+std::tr1::hash<off_t> 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<off_t> 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<typename T> extern void foo(const char*, ...)
+ __attribute__ ((__format__ (__printf__, 1, 2)));
+template<typename T> void foo(const char* format, ...) {}
+void bar() { foo<int>("%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 <sys/stat.h>
+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 <iant@google.com>.
+
+# 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 <iant@google.com>.
+
+// 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<int sh_type, int size, bool big_endian>
+void
+Copy_relocs<sh_type, size, big_endian>::Copy_reloc_entry::emit(
+ Output_data_reloc<sh_type, true, size, big_endian>* 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<int sh_type, int size, bool big_endian>
+void
+Copy_relocs<sh_type, size, big_endian>::copy_reloc(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_symbol<size>* sym,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int shndx,
+ Output_section* output_section,
+ const Reloc& rel,
+ Output_data_reloc<sh_type, true, size, big_endian>* 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<int sh_type, int size, bool big_endian>
+bool
+Copy_relocs<sh_type, size, big_endian>::need_copy_reloc(
+ Sized_symbol<size>* sym,
+ Sized_relobj_file<size, big_endian>* 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<int sh_type, int size, bool big_endian>
+void
+Copy_relocs<sh_type, size, big_endian>::emit_copy_reloc(
+ Symbol_table* symtab,
+ Sized_symbol<size>* sym,
+ Output_data* posd,
+ off_t offset,
+ Output_data_reloc<sh_type, true, size, big_endian>* 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<int sh_type, int size, bool big_endian>
+void
+Copy_relocs<sh_type, size, big_endian>::make_copy_reloc(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_symbol<size>* sym,
+ Output_data_reloc<sh_type, true, size, big_endian>* reloc_section)
+{
+ // We should not be here if -z nocopyreloc is given.
+ gold_assert(parameters->options().copyreloc());
+
+ typename elfcpp::Elf_types<size>::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<size>::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<const Task*>(-1);
+ Object* obj = sym->object();
+ Task_lock_obj<Object> tl(dummy_task, obj);
+ addralign = obj->section_addralign(shndx);
+ }
+
+ typename Sized_symbol<size>::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<int sh_type, int size, bool big_endian>
+void
+Copy_relocs<sh_type, size, big_endian>::save(
+ Symbol* sym,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int shndx,
+ Output_section* output_section,
+ const Reloc& rel)
+{
+ unsigned int reloc_type = elfcpp::elf_r_type<size>(rel.get_r_info());
+ typename elfcpp::Elf_types<size>::Elf_Addr addend =
+ Reloc_types<sh_type, size, big_endian>::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<int sh_type, int size, bool big_endian>
+void
+Copy_relocs<sh_type, size, big_endian>::emit(
+ Output_data_reloc<sh_type, true, size, big_endian>* 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<elfcpp::SHT_REL, 32, false>;
+
+template
+class Copy_relocs<elfcpp::SHT_RELA, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Copy_relocs<elfcpp::SHT_REL, 32, true>;
+
+template
+class Copy_relocs<elfcpp::SHT_RELA, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Copy_relocs<elfcpp::SHT_REL, 64, false>;
+
+template
+class Copy_relocs<elfcpp::SHT_RELA, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Copy_relocs<elfcpp::SHT_REL, 64, true>;
+
+template
+class Copy_relocs<elfcpp::SHT_RELA, 64, true>;
+#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 <iant@google.com>.
+
+// 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<int sh_type, int size, bool big_endian>
+class Copy_relocs
+{
+ private:
+ typedef typename Reloc_types<sh_type, size, big_endian>::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<size>* sym,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int shndx, Output_section* output_section,
+ const Reloc& rel,
+ Output_data_reloc<sh_type, true, size, big_endian>*);
+
+ // 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<sh_type, true, size, big_endian>*);
+
+ // Emit a COPY reloc.
+ void
+ emit_copy_reloc(Symbol_table*, Sized_symbol<size>*,
+ Output_data*, off_t,
+ Output_data_reloc<sh_type, true, size, big_endian>*);
+
+ private:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename elfcpp::Elf_types<size>::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<size, big_endian>* 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<sh_type, true, size, big_endian>*);
+
+ private:
+ Symbol* sym_;
+ unsigned int reloc_type_;
+ Sized_relobj_file<size, big_endian>* relobj_;
+ unsigned int shndx_;
+ Output_section* output_section_;
+ Address address_;
+ Addend addend_;
+ };
+
+ // A list of relocs to be saved.
+ typedef std::vector<Copy_reloc_entry> Copy_reloc_entries;
+
+ // Return whether we need a COPY reloc.
+ bool
+ need_copy_reloc(Sized_symbol<size>* gsym,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int shndx) const;
+
+ // Make a new COPY reloc and emit it.
+ void
+ make_copy_reloc(Symbol_table*, Layout*, Sized_symbol<size>*,
+ Output_data_reloc<sh_type, true, size, big_endian>*);
+
+ // Save a reloc against SYM for possible emission later.
+ void
+ save(Symbol*, Sized_relobj_file<size, big_endian>*, 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 <iant@google.com>.
+
+// 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 <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <map>
+#include <string>
+#include <vector>
+
+#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<Object*> 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<std::string, Archive_info> 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<const Symbol*, Objects*, Cref_table_compare> 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<Cref_table::iterator, bool> 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 <iant@google.com>.
+
+// 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 <cstdio>
+
+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 <iant@google.com>.
+
+// 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 <cstring>
+
+#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 <iant@google.com>.
+
+// 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 <iant@google.com>.
+
+// 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 <iant@google.com>.
+
+// 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 <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <fcntl.h>
+#include <unistd.h>
+
+#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<size_t>(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<size_t>(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<size_t>(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<size_t>(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 <iant@google.com>.
+
+// 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 <vector>
+
+#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_descriptor> 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 <iant@google.com>.
+
+// 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 <cerrno>
+#include <cstring>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#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<std::string> 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<const char*, Dir_cache*> 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<const char*, Dir_cache*> v(dirname, cache);
+ std::pair<Cache_hash::iterator, bool> 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<std::string>& 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<unsigned int>(*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<std::string>::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 <iant@google.com>.
+
+// 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 <string>
+#include <list>
+
+#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<std::string>& 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 <iant@google.com>.
+
+// 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 <algorithm>
+#include <vector>
+
+#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<int size, bool big_endian>
+bool
+Sized_elf_reloc_mapper<size, big_endian>::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<int size, bool big_endian>
+unsigned int
+Sized_elf_reloc_mapper<size, big_endian>::symbol_section(
+ unsigned int symndx, Address* value, bool* is_ordinary)
+{
+ const int symsize = elfcpp::Elf_sizes<size>::sym_size;
+ gold_assert(static_cast<off_t>((symndx + 1) * symsize) <= this->symtab_size_);
+ elfcpp::Sym<size, big_endian> 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<int size, bool big_endian>
+unsigned int
+Sized_elf_reloc_mapper<size, big_endian>::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<size>::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<const char*>(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<const char*>(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<const char*>(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<true>();
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
+ this->do_parse<false>();
+#else
+ gold_unreachable();
+#endif
+ }
+}
+
+template<bool big_endian>
+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<const char*>(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 <int valsize>
+inline typename elfcpp::Valtype_base<valsize>::Valtype
+Dwarf_info_reader::read_from_pointer(const unsigned char* source)
+{
+ typename elfcpp::Valtype_base<valsize>::Valtype return_value;
+ if (this->object_->is_big_endian())
+ return_value = elfcpp::Swap_unaligned<valsize, true>::readval(source);
+ else
+ return_value = elfcpp::Swap_unaligned<valsize, false>::readval(source);
+ return return_value;
+}
+
+// Read a possibly unaligned integer of SIZE. Update SOURCE after read.
+template <int valsize>
+inline typename elfcpp::Valtype_base<valsize>::Valtype
+Dwarf_info_reader::read_from_pointer(const unsigned char** source)
+{
+ typename elfcpp::Valtype_base<valsize>::Valtype return_value;
+ if (this->object_->is_big_endian())
+ return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source);
+ else
+ return_value = elfcpp::Swap_unaligned<valsize, false>::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<int size, bool big_endian>
+Sized_dwarf_line_info<size, big_endian>::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<size, big_endian>(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<int size, bool big_endian>
+const unsigned char*
+Sized_dwarf_line_info<size, big_endian>::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<const signed char*>(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<int size, bool big_endian>
+const unsigned char*
+Sized_dwarf_line_info<size, big_endian>::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<int>(this->directories_.size())
+ == this->current_header_index_);
+ gold_assert(static_cast<int>(this->files_.size())
+ == this->current_header_index_);
+ this->directories_.push_back(std::vector<std::string>(1));
+ this->files_.push_back(std::vector<std::pair<int, std::string> >(1));
+
+ // It is legal for the directory entry table to be empty.
+ if (*lineptr)
+ {
+ int dirindex = 1;
+ while (*lineptr)
+ {
+ const char* dirname = reinterpret_cast<const char*>(lineptr);
+ gold_assert(dirindex
+ == static_cast<int>(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<const char*>(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<int>(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<int>(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<int size, bool big_endian>
+bool
+Sized_dwarf_line_info<size, big_endian>::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<size, big_endian>::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<const char*>(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<int>(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<int size, bool big_endian>
+unsigned const char*
+Sized_dwarf_line_info<size, big_endian>::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<off_t>(lsm.address),
+ this->current_header_index_,
+ static_cast<unsigned int>(lsm.file_num),
+ true, lsm.line_num };
+ std::vector<Offset_to_lineno_entry>&
+ 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<off_t>(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<int size, bool big_endian>
+void
+Sized_dwarf_line_info<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_dwarf_line_info<size, big_endian>::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<int size, bool big_endian>
+bool
+Sized_dwarf_line_info<size, big_endian>::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<Offset_to_lineno_entry>::const_iterator
+offset_to_iterator(const std::vector<Offset_to_lineno_entry>* 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<Offset_to_lineno_entry>::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<Offset_to_lineno_entry>::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<int size, bool big_endian>
+std::string
+Sized_dwarf_line_info<size, big_endian>::do_addr2line(
+ unsigned int shndx,
+ off_t offset,
+ std::vector<std::string>* other_lines)
+{
+ if (this->data_valid_ == false)
+ return "";
+
+ const std::vector<Offset_to_lineno_entry>* 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<Offset_to_lineno_entry>::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<int size, bool big_endian>
+std::string
+Sized_dwarf_line_info<size, big_endian>::format_file_lineno(
+ const Offset_to_lineno_entry& loc) const
+{
+ std::string ret;
+
+ gold_assert(loc.header_num < static_cast<int>(this->files_.size()));
+ gold_assert(loc.file_num
+ < static_cast<unsigned int>(this->files_[loc.header_num].size()));
+ const std::pair<int, std::string>& filename_pair
+ = this->files_[loc.header_num][loc.file_num];
+ const std::string& filename = filename_pair.second;
+
+ gold_assert(loc.header_num < static_cast<int>(this->directories_.size()));
+ gold_assert(filename_pair.first
+ < static_cast<int>(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_entry> addr2line_cache;
+
+std::string
+Dwarf_line_info::one_addr2line(Object* object,
+ unsigned int shndx, off_t offset,
+ size_t cache_size,
+ std::vector<std::string>* other_lines)
+{
+ Dwarf_line_info* lineinfo = NULL;
+ std::vector<Addr2line_cache_entry>::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<Addr2line_cache_entry>::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<Addr2line_cache_entry>::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 <iant@google.com>.
+
+// 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 <vector>
+#include <map>
+#include <limits.h>
+#include <sys/types.h>
+
+#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<int size, bool big_endian>
+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<size>::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<size, big_endian> 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<Attribute> 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<unsigned int, const Abbrev_code*> 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> 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<Attribute_value> 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 <int valsize>
+ inline typename elfcpp::Valtype_base<valsize>::Valtype
+ read_from_pointer(const unsigned char* source);
+
+ // Read a possibly unaligned integer of SIZE. Update SOURCE after read.
+ template <int valsize>
+ inline typename elfcpp::Valtype_base<valsize>::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<bool big_endian>
+ 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<std::string>* 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<std::string>* 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<std::string>* other_lines) = 0;
+};
+
+template<int size, bool big_endian>
+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<std::string>* 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<unsigned char> 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<size, big_endian>* 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<std::vector<std::string> > directories_;
+ // The first part is an index into directories_, the second the filename.
+ std::vector<std::vector< std::pair<int, std::string> > > 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<off_t, std::pair<unsigned int, off_t> >
+ Reloc_map;
+ Reloc_map reloc_map_;
+
+ // We have a vector of offset->lineno entries for every input section.
+ typedef Unordered_map<unsigned int, std::vector<Offset_to_lineno_entry> >
+ 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 <ccoutant@google.com>.
+
+// 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 <cstdarg>
+#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+
+#include <vector>
+#include <algorithm>
+
+#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 <int size, bool big_endian>
+class Sized_relobj_dwo;
+
+// List of .dwo files to process.
+typedef std::vector<std::string> 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<section_offset_type, section_offset_type>
+ Str_offset_map_entry;
+ typedef std::vector<Str_offset_map_entry> 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 <int size, bool big_endian>
+ 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 <bool big_endian>
+ 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 <bool big_endian>
+ 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 <bool big_endian>
+ 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<bool> is_compressed_;
+ // Map input section index onto output section index.
+ std::vector<unsigned int> 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 <int size, bool big_endian>
+class Sized_relobj_dwo : public Sized_relobj<size, big_endian>
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename Sized_relobj<size, big_endian>::Symbols Symbols;
+
+ Sized_relobj_dwo(const char* name, Input_file* input_file,
+ const elfcpp::Ehdr<size, big_endian>& ehdr)
+ : Sized_relobj<size, big_endian>(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<char>*,
+ Stringpool_template<char>*)
+ { 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<size, big_endian, Object> 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<unsigned int> 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<unsigned int size, bool big_endian>
+ 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<unsigned int size, bool big_endian>
+ 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<bool big_endian>
+ 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<Section> 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 <int size, bool big_endian>
+void
+Sized_relobj_dwo<size, big_endian>::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 <int size, bool big_endian>
+const unsigned char*
+Sized_relobj_dwo<size, big_endian>::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 <int size, bool big_endian>
+const unsigned char*
+Sized_relobj_dwo<size, big_endian>::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<unsigned int> 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 <int size, bool big_endian>
+Relobj*
+Dwo_file::sized_make_object(const unsigned char* p, Input_file* input_file,
+ Dwp_output_file* output_file)
+{
+ elfcpp::Ehdr<size, big_endian> ehdr(p);
+ Sized_relobj_dwo<size, big_endian>* obj =
+ new Sized_relobj_dwo<size, big_endian>(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<true>(shndx, output_file);
+ else
+ this->sized_read_compunit_index<false>(shndx, output_file);
+}
+
+template <bool big_endian>
+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<true>(shndx, output_file);
+ else
+ this->sized_read_typeunit_index<false>(shndx, output_file);
+}
+
+template <bool big_endian>
+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<const char*>(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<true>(contents, len);
+ else
+ return this->sized_remap_str_offsets<false>(contents, len);
+}
+
+template <bool big_endian>
+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<unsigned int>(signature) & (this->capacity_ - 1);
+ unsigned int secondary_hash;
+ uint64_t probe = this->hash_table_[slot];
+ if (probe != 0 && probe != signature)
+ {
+ secondary_hash = (static_cast<unsigned int>(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<true>(".debug_cu_index", this->cu_index_);
+ this->write_index<true>(".debug_tu_index", this->tu_index_);
+ }
+ else
+ {
+ this->write_index<false>(".debug_cu_index", this->cu_index_);
+ this->write_index<false>(".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<bool big_endian>
+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<unsigned int size, bool big_endian>
+void
+Dwp_output_file::sized_write_ehdr()
+{
+ const unsigned int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size;
+ unsigned char buf[ehdr_size];
+ elfcpp::Ehdr_write<size, big_endian> 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<size>::ehdr_size);
+ ehdr.put_e_phentsize(0);
+ ehdr.put_e_phnum(0);
+ ehdr.put_e_shentsize(elfcpp::Elf_sizes<size>::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<unsigned int>(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<unsigned int size, bool big_endian>
+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<size>::shdr_size;
+ unsigned char buf[shdr_size];
+ elfcpp::Shdr_write<size, big_endian> 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 <ccoutant@google.com>.
+
+// 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 <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <stdint.h>
+#include <sys/types.h>
+
+#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<int size, bool big_endian>
+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<const char*>(__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<typename To, typename From>
+inline To
+convert_types(const From from)
+{
+ To to = from;
+ gold_assert(static_cast<From>(to) == from);
+ return to;
+}
+
+// A common case of convert_types<>: convert to section_size_type.
+template<typename From>
+inline section_size_type
+convert_to_section_size_type(const From from)
+{ return convert_types<section_size_type, From>(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 <iant@google.com>.
+
+// 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 <vector>
+#include <cstring>
+
+#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<int size, bool big_endian>
+Sized_dynobj<size, big_endian>::Sized_dynobj(
+ const std::string& name,
+ Input_file* input_file,
+ off_t offset,
+ const elfcpp::Ehdr<size, big_endian>& ehdr)
+ : Dynobj(name, input_file, offset),
+ elf_file_(this, ehdr),
+ dynsym_shndx_(-1U),
+ symbols_(NULL),
+ defined_count_(0)
+{
+}
+
+// Set up the object.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::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<size, big_endian>(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<size, big_endian>(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<size, big_endian>(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<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::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<const char*>(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<long long>(val),
+ static_cast<long long>(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<long long>(val),
+ static_cast<long long>(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<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::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<unsigned int>(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<int size, bool big_endian>
+Xindex*
+Sized_dynobj<size, big_endian>::do_initialize_xindex()
+{
+ gold_assert(this->dynsym_shndx_ != -1U);
+ Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset());
+ xindex->initialize_symtab_xindex<size, big_endian>(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<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::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<const char*>(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<unsigned long>(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<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::make_verdef_map(
+ Read_symbols_data* sd,
+ Version_map* version_map) const
+{
+ if (sd->verdef == NULL)
+ return;
+
+ const char* names = reinterpret_cast<const char*>(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<size, big_endian> 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<unsigned int>(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<unsigned int>(vd_aux));
+ return;
+ }
+
+ const unsigned char* pvda = p + vd_aux;
+ elfcpp::Verdaux<size, big_endian> 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<unsigned int>(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<unsigned int>(vd_next));
+ return;
+ }
+
+ p += vd_next;
+ }
+}
+
+// Add mappings for the required versions to VERSION_MAP.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::make_verneed_map(
+ Read_symbols_data* sd,
+ Version_map* version_map) const
+{
+ if (sd->verneed == NULL)
+ return;
+
+ const char* names = reinterpret_cast<const char*>(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<size, big_endian> 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<unsigned int>(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<size, big_endian> 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<unsigned int>(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<unsigned int>(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<unsigned int>(vn_next));
+ return;
+ }
+
+ p += vn_next;
+ }
+}
+
+// Create a vector mapping version numbers to version strings.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::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<const char*>(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<int size, bool big_endian>
+Archive::Should_include
+Sized_dynobj<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::do_for_all_global_symbols(
+ Read_symbols_data* sd,
+ Library_base::Symbol_visitor_base* v)
+{
+ const char* sym_names =
+ reinterpret_cast<const char*>(sd->symbol_names->data());
+ const unsigned char* syms =
+ sd->symbols->data() + sd->external_symbols_offset;
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ size_t symcount = ((sd->symbols_size - sd->external_symbols_offset)
+ / sym_size);
+ const unsigned char* p = syms;
+
+ for (size_t i = 0; i < symcount; ++i, p += sym_size)
+ {
+ elfcpp::Sym<size, big_endian> 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<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::do_for_all_local_got_entries(
+ Got_offset_list::Visitor*) const
+{
+}
+
+// Get symbol counts.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::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<uint32_t>& 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<const unsigned char*>(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<Symbol*>& 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<uint32_t> 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<uint32_t> bucket(bucketcount);
+ std::vector<uint32_t> 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<true>(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<false>(bucket, chain, phash,
+ hashlen);
+#else
+ gold_unreachable();
+#endif
+ }
+
+ *pphash = phash;
+ *phashlen = hashlen;
+}
+
+// Fill in an ELF hash table.
+
+template<bool big_endian>
+void
+Dynobj::sized_create_elf_hash_table(const std::vector<uint32_t>& bucket,
+ const std::vector<uint32_t>& 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<unsigned int>(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<const unsigned char*>(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<Symbol*>& 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<Symbol*> unhashed_dynsyms;
+ unhashed_dynsyms.reserve(count);
+
+ std::vector<Symbol*> hashed_dynsyms;
+ hashed_dynsyms.reserve(count);
+
+ std::vector<uint32_t> 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<int size, bool big_endian>
+void
+Dynobj::sized_create_gnu_hash_table(
+ const std::vector<Symbol*>& hashed_dynsyms,
+ const std::vector<uint32_t>& 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<size, big_endian>::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<size>::Elf_WXword Word;
+ std::vector<Word> bitmask(maskwords);
+ std::vector<uint32_t> counts(bucketcount);
+ std::vector<uint32_t> 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<Word>(1U)) << (hashval & mask);
+ bitmask[val] |= (static_cast<Word>(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<size, big_endian>::writeval(p, bitmask[i]);
+ p += size / 8;
+ }
+
+ *phashlen = hashlen;
+ *pphash = phash;
+}
+
+// Verdef methods.
+
+// Write this definition to a buffer for the output section.
+
+template<int size, bool big_endian>
+unsigned char*
+Verdef::write(const Stringpool* dynpool, bool is_last, unsigned char* pb) const
+{
+ const int verdef_size = elfcpp::Elf_sizes<size>::verdef_size;
+ const int verdaux_size = elfcpp::Elf_sizes<size>::verdaux_size;
+
+ elfcpp::Verdef_write<size, big_endian> 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<size, big_endian> 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<size, big_endian> 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<int size, bool big_endian>
+unsigned char*
+Verneed::write(const Stringpool* dynpool, bool is_last,
+ unsigned char* pb) const
+{
+ const int verneed_size = elfcpp::Elf_sizes<size>::verneed_size;
+ const int vernaux_size = elfcpp::Elf_sizes<size>::vernaux_size;
+
+ elfcpp::Verneed_write<size, big_endian> 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<size, big_endian> 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<std::string> 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<std::string>(),
+ 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<Dynobj*>(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<Version_table::iterator, bool> 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<std::string>(),
+ 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<Version_table::iterator, bool> 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<Symbol*>* 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<int size, bool big_endian>
+void
+Versions::symbol_section_contents(const Symbol_table* symtab,
+ const Stringpool* dynpool,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& 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<Symbol*>::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<int size, bool big_endian>
+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<size>::verdef_size;
+ const int verdaux_size = elfcpp::Elf_sizes<size>::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<size, big_endian>(dynpool,
+ i + 1 >= this->defs_.size(),
+ pb);
+
+ gold_assert(static_cast<unsigned int>(pb - pbuf) == sz);
+
+ *pp = pbuf;
+ *psize = sz;
+ *pentries = this->defs_.size();
+}
+
+// Return an allocated buffer holding the contents of the version
+// reference section.
+
+template<int size, bool big_endian>
+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<size>::verneed_size;
+ const int vernaux_size = elfcpp::Elf_sizes<size>::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<size, big_endian>(dynpool,
+ i + 1 >= this->needs_.size(),
+ pb);
+
+ gold_assert(static_cast<unsigned int>(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<Symbol*>&,
+ 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<Symbol*>&,
+ 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<Symbol*>&,
+ 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<Symbol*>&,
+ 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 <iant@google.com>.
+
+// 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 <vector>
+
+#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<std::string> 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<Symbol*>& 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<Symbol*>& 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<uint32_t>& hashcodes,
+ bool for_gnu_hash_table);
+
+ // Sized version of create_elf_hash_table.
+ template<bool big_endian>
+ static void
+ sized_create_elf_hash_table(const std::vector<uint32_t>& bucket,
+ const std::vector<uint32_t>& chain,
+ unsigned char* phash,
+ unsigned int hashlen);
+
+ // Sized version of create_gnu_hash_table.
+ template<int size, bool big_endian>
+ static void
+ sized_create_gnu_hash_table(const std::vector<Symbol*>& hashed_dynsyms,
+ const std::vector<uint32_t>& 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<int size, bool big_endian>
+class Sized_dynobj : public Dynobj
+{
+ public:
+ typedef typename Sized_relobj_file<size, big_endian>::Symbols Symbols;
+
+ Sized_dynobj(const std::string& name, Input_file* input_file, off_t offset,
+ const typename elfcpp::Ehdr<size, big_endian>&);
+
+ // 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<size, big_endian> This;
+ static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+ static const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ static const int dyn_size = elfcpp::Elf_sizes<size>::dyn_size;
+ typedef elfcpp::Shdr<size, big_endian> Shdr;
+ typedef elfcpp::Dyn<size, big_endian> 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<const char*> 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<size, big_endian, Object> 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<std::string>& 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<int size, bool big_endian>
+ 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<std::string> 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<int size, bool big_endian>
+ 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<Verneed_version*> 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<Symbol*>* 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<int size, bool big_endian>
+ void
+ symbol_section_contents(const Symbol_table*, const Stringpool*,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& syms,
+ unsigned char**, unsigned int*) const;
+
+ // Build an allocated buffer holding the contents of the version
+ // definition section (.gnu.version_d).
+ template<int size, bool big_endian>
+ 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<int size, bool big_endian>
+ 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<Verdef*> Defs;
+
+ // The type of the list of version references.
+ typedef std::vector<Verneed*> 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<Stringpool::Key, Stringpool::Key> 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<Key, Version_base*, Version_table_hash,
+ Version_table_eq> 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 <iant@google.com>.
+
+// 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 <cstring>
+#include <algorithm>
+
+#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<int size, bool big_endian>
+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<size> fde_addresses(this->fde_offsets_.size());
+ this->get_fde_addresses<size, big_endian>(of, &this->fde_offsets_,
+ &fde_addresses);
+
+ std::sort(fde_addresses.begin(), fde_addresses.end(),
+ Fde_address_compare<size>());
+
+ typename elfcpp::Elf_types<size>::Elf_Addr output_address;
+ output_address = this->address();
+
+ unsigned char* pfde = oview + 12;
+ for (typename Fde_addresses<size>::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<int size, bool big_endian>
+typename elfcpp::Elf_types<size>::Elf_Addr
+Eh_frame_hdr::get_fde_pc(
+ typename elfcpp::Elf_types<size>::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<size>::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<int size, bool big_endian>
+void
+Eh_frame_hdr::get_fde_addresses(Output_file* of,
+ const Fde_offsets* fde_offsets,
+ Fde_addresses<size>* fde_addresses)
+{
+ typename elfcpp::Elf_types<size>::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<size>::Elf_Addr fde_pc;
+ fde_pc = this->get_fde_pc<size, big_endian>(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<int size, bool big_endian>
+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<int32_t>(poffset);
+ uint32_t upsize = static_cast<uint32_t>(psize);
+ if (static_cast<uint64_t>(static_cast<int64_t>(spoffset)) != poffset
+ || static_cast<off_t>(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<Fde*>::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<Fde*>::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<int size, bool big_endian>
+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<Fde*>::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<size, big_endian>(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<int size, bool big_endian>
+bool
+Eh_frame::add_ehframe_input_section(
+ Sized_relobj_file<size, big_endian>* 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<int size, bool big_endian>
+bool
+Eh_frame::do_add_ehframe_input_section(
+ Sized_relobj_file<size, big_endian>* 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<size, big_endian> 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<unsigned int>(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<int size, bool big_endian>
+bool
+Eh_frame::read_cie(Sized_relobj_file<size, big_endian>* 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<size, big_endian>* 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<const unsigned char*>(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<unsigned int>(pcieend - p) < len)
+ return false;
+ p += len;
+ }
+
+ per_offset = p - pcontents;
+
+ if (static_cast<unsigned int>(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<size>::sym_size;
+ if (personality_symndx >= symbols_size / sym_size)
+ return false;
+ elfcpp::Sym<size, big_endian> 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<const char*>(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<int size, bool big_endian>
+bool
+Eh_frame::read_fde(Sized_relobj_file<size, big_endian>* 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<size, big_endian>* 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<size>::sym_size;
+ if (symndx >= symbols_size / sym_size)
+ return false;
+ elfcpp::Sym<size, big_endian> 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<int size, bool big_endian>
+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<size, big_endian>(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<size, big_endian>(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<size, big_endian>(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 <iant@google.com>.
+
+// 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 <map>
+#include <set>
+#include <vector>
+
+#include "output.h"
+#include "merge.h"
+
+namespace gold
+{
+
+template<int size, bool big_endian>
+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<int size, bool big_endian>
+ 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<section_offset_type, unsigned char> Fde_offset;
+
+ // The list of information we record for an FDE.
+ typedef std::vector<Fde_offset> 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<int size>
+ class Fde_addresses
+ {
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename std::pair<Address, Address> Fde_address;
+ typedef typename std::vector<Fde_address> 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<int size>
+ struct Fde_address_compare
+ {
+ bool
+ operator()(const typename Fde_addresses<size>::Fde_address& f1,
+ const typename Fde_addresses<size>::Fde_address& f2) const
+ { return f1.first < f2.first; }
+ };
+
+ // Return the PC to which an FDE refers.
+ template<int size, bool big_endian>
+ typename elfcpp::Elf_types<size>::Elf_Addr
+ get_fde_pc(typename elfcpp::Elf_types<size>::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<int size, bool big_endian>
+ void
+ get_fde_addresses(Output_file* of,
+ const Fde_offsets* fde_offsets,
+ Fde_addresses<size>* 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<const char*>(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<const char*>(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<int size, bool big_endian>
+ 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_fde> 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<const char*>(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<int size, bool big_endian>
+ 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<Fde*> 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<int size, bool big_endian>
+ bool
+ add_ehframe_input_section(Sized_relobj_file<size, big_endian>* 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*, Cie_less> Cie_offsets;
+
+ // A list of unmergeable CIEs.
+ typedef std::vector<Cie*> Unmergeable_cie_offsets;
+
+ // A mapping from offsets to CIEs. This is used while reading an
+ // input section.
+ typedef std::map<uint64_t, Cie*> Offsets_to_cie;
+
+ // A list of CIEs, and a bool indicating whether the CIE is
+ // mergeable.
+ typedef std::vector<std::pair<Cie*, bool> > New_cies;
+
+ // Skip an LEB128.
+ static bool
+ skip_leb128(const unsigned char**, const unsigned char*);
+
+ // The implementation of add_ehframe_input_section.
+ template<int size, bool big_endian>
+ bool
+ do_add_ehframe_input_section(Sized_relobj_file<size, big_endian>* 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<int size, bool big_endian>
+ bool
+ read_cie(Sized_relobj_file<size, big_endian>* 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<size, big_endian>* relocs,
+ Offsets_to_cie* cies,
+ New_cies* new_cies);
+
+ // Read an FDE.
+ template<int size, bool big_endian>
+ bool
+ read_fde(Sized_relobj_file<size, big_endian>* 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<size, big_endian>* relocs,
+ Offsets_to_cie* cies);
+
+ // Template version of write function.
+ template<int size, bool big_endian>
+ 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 <iant@google.com>.
+
+// 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 <cstdarg>
+#include <cstdio>
+
+#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<int size, bool big_endian>
+void
+Errors::error_at_location(const Relocate_info<size, big_endian>* 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<int size, bool big_endian>
+void
+Errors::warning_at_location(const Relocate_info<size, big_endian>* 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<int size, bool big_endian>
+void
+gold_error_at_location(const Relocate_info<size, big_endian>* 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<int size, bool big_endian>
+void
+gold_warning_at_location(const Relocate_info<size, big_endian>* 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<int size, bool big_endian>
+void
+gold_undefined_symbol_at_location(const Symbol* sym,
+ const Relocate_info<size, big_endian>* 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 <iant@google.com>.
+
+// 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 <cstdarg>
+
+#include "gold-threads.h"
+
+namespace gold
+{
+
+class Symbol;
+template<int size, bool big_endian>
+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<int size, bool big_endian>
+ void
+ error_at_location(const Relocate_info<size, big_endian>* relinfo,
+ size_t relnum, off_t reloffset,
+ const char* format, va_list);
+
+ // Report a warning at a reloc location.
+ template<int size, bool big_endian>
+ void
+ warning_at_location(const Relocate_info<size, big_endian>* 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<const Symbol*, int> 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 <iant@google.com>.
+
+// 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 <string>
+
+#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<unsigned long long>(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 <iant@google.com>.
+
+ 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 <string.h>
+
+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 <iant@google.com>.
+
+// 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 <cstring>
+#include <cerrno>
+#include <climits>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#ifdef HAVE_READV
+#include <sys/uio.h>
+#endif
+
+#include <sys/stat.h>
+#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<void*>(-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<unsigned char*>(this->data_));
+ break;
+ case DATA_MMAPPED:
+ if (::munmap(const_cast<unsigned char*>(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<unsigned long long>(size)
+ <= static_cast<unsigned long long>(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<off_t>(p->second->size())
+ >= start + static_cast<off_t>(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<section_size_type>(bytes) >= size)
+ {
+ memcpy(p, this->whole_file_view_->data() + start, size);
+ return;
+ }
+ }
+ else
+ {
+ this->reopen_descriptor();
+
+ char *read_ptr = static_cast<char *>(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<long long>(bytes),
+ static_cast<long long>(size),
+ static_cast<long long>(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<Views::iterator, bool> 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<unsigned long long>(size)
+ <= static_cast<unsigned long long>(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<off_t>(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<unsigned char*>(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<const unsigned char*>(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<unsigned long long>(size)
+ > static_cast<unsigned long long>(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<long long>(size),
+ static_cast<long long>(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<unsigned char*>(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<long long>(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<std::string> 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<std::string>::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<std::string>(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 <iant@google.com>.
+
+// 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 <list>
+#include <map>
+#include <string>
+#include <vector>
+
+#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_entry> 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<std::pair<off_t, unsigned int>, View*> Views;
+
+ // A simple list of Views.
+ typedef std::list<View*> 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 <iant@google.com>.
+
+// 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<elfcpp::ELFOSABI>(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<const char*>* 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 <config.h>
+
+/* Specification. */
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+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 <kucharsk@netcom.com>. */
+
+# include <sys/stat.h>
+# include <errno.h>
+
+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 <errno.h>
+
+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 <tmsriram@google.com>.
+
+// 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 <tmsriram@google.com>.
+
+// 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 <queue>
+#include <vector>
+
+#include "elfcpp.h"
+#include "symtab.h"
+#include "object.h"
+#include "icf.h"
+
+namespace gold
+{
+
+class Object;
+
+template<int size, bool big_endian>
+class Sized_relobj_file;
+
+template<int sh_type, int size, bool big_endian>
+struct Reloc_types;
+
+class Output_section;
+class General_options;
+class Layout;
+
+class Garbage_collection
+{
+ public:
+
+ typedef Unordered_set<Section_id, Section_id_hash> Sections_reachable;
+ typedef std::map<Section_id, Sections_reachable> Section_ref;
+ typedef std::queue<Section_id> 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<std::string, Sections_reachable> 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<typename Classify_reloc>
+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<int size, bool big_endian, typename Target_type, int sh_type,
+ typename Scan, typename Classify_reloc>
+inline void
+gc_process_relocs(
+ Symbol_table* symtab,
+ Layout*,
+ Target_type* target,
+ Sized_relobj_file<size, big_endian>* 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<sh_type, size, big_endian>::Reloc Reltype;
+ const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+ const int sym_size = elfcpp::Elf_sizes<size>::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<size>::Elf_WXword r_info = reloc.get_r_info();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+ typename elfcpp::Elf_types<size>::Elf_Swxword addend =
+ Reloc_types<sh_type, size, big_endian>::get_reloc_addend_noerror(&reloc);
+ Object* dst_obj;
+ unsigned int dst_indx;
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ Address dst_off;
+
+ if (r_sym < local_count)
+ {
+ gold_assert(plocal_syms != NULL);
+ typename elfcpp::Sym<size, big_endian> 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<long long>(symvalue),
+ static_cast<long long>(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<Classify_reloc>(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<const Sized_symbol<size>*>(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<long long>(symvalue),
+ static_cast<long long>(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<Classify_reloc>(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<size, big_endian>()
+ ->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 <ccoutant@google.com>.
+
+// 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 <typename T>
+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<off_t, Declaration_pair> 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_symbol>();
+}
+
+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<const unsigned char*>(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 <ccoutant@google.com>.
+
+// 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 <sys/types.h>
+#include <vector>
+
+#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<int size, bool big_endian>
+class Sized_relobj;
+class Dwarf_range_list;
+template <typename T>
+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<int> Cu_vector;
+
+ typedef Unordered_map<off_t, off_t> 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_unit> comp_units_;
+ // The list of DWARF type units.
+ std::vector<Type_unit> type_units_;
+ // The list of address ranges.
+ std::vector<Per_cu_range_list> ranges_;
+ // The symbol table.
+ Gdb_hashtab<Gdb_symbol>* gdb_symtab_;
+ // The CU vector portion of the constant pool.
+ std::vector<Cu_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 <iant@google.com>.
+
+// 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 <cstring>
+
+#ifdef ENABLE_THREADS
+#include <pthread.h>
+#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<Lock_impl_nothreads*>(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<Lock_impl_threads*>(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 <iant@google.com>.
+
+// 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 <iant@google.com>.
+
+// 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 <cstdlib>
+#include <cstdio>
+#include <cstring>
+#include <unistd.h>
+#include <algorithm>
+#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<Task*> 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<Object> 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<Target*>(&parameters->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 <iant@google.com>.
+
+// 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 <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <stdint.h>
+#include <sys/types.h>
+
+#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<int size, bool big_endian>
+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<int size, bool big_endian>
+extern void
+gold_error_at_location(const Relocate_info<size, big_endian>*,
+ 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<int size, bool big_endian>
+extern void
+gold_warning_at_location(const Relocate_info<size, big_endian>*,
+ 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<int size, bool big_endian>
+extern void
+gold_undefined_symbol_at_location(const Symbol*,
+ const Relocate_info<size, big_endian>*,
+ 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<const char*>(__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<typename To, typename From>
+inline To
+convert_types(const From from)
+{
+ To to = from;
+ gold_assert(static_cast<From>(to) == from);
+ return to;
+}
+
+// A common case of convert_types<>: convert to section_size_type.
+template<typename From>
+inline section_size_type
+convert_to_section_size_type(const From from)
+{ return convert_types<section_size_type, From>(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<typename Char_type>
+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<const unsigned char*>(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<typename Char_type>
+inline size_t
+string_hash(const Char_type* s)
+{
+ const unsigned char* p = reinterpret_cast<const unsigned char*>(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 <iant@google.com>.
+
+// 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 <cstring>
+
+#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<elfcpp::SHT_REL, true, 32, false> 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_ifunc> global_ifuncs_;
+ // Local STT_GNU_IFUNC symbols.
+ std::vector<Local_ifunc> local_ifuncs_;
+};
+
+// This is an abstract class for the standard PLT layout.
+// The derived classes below handle the actual PLT contents
+// for the executable (non-PIC) and shared-library (PIC) cases.
+// The unwind information is uniform across those two, so it's here.
+
+class Output_data_plt_i386_standard : public Output_data_plt_i386
+{
+ public:
+ Output_data_plt_i386_standard(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386(layout, plt_entry_size, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return plt_entry_size; }
+
+ virtual void
+ do_add_eh_frame(Layout* layout)
+ {
+ layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size,
+ plt_eh_frame_fde, plt_eh_frame_fde_size);
+ }
+
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 16;
+
+ // The .eh_frame unwind information for the PLT.
+ static const int plt_eh_frame_fde_size = 32;
+ static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+};
+
+// Actually fill the PLT contents for an executable (non-PIC).
+
+class Output_data_plt_i386_exec : public Output_data_plt_i386_standard
+{
+public:
+ Output_data_plt_i386_exec(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386_standard(layout, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset);
+
+ private:
+ // The first entry in the PLT for an executable.
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for an executable.
+ static const unsigned char plt_entry[plt_entry_size];
+};
+
+// Actually fill the PLT contents for a shared library (PIC).
+
+class Output_data_plt_i386_dyn : public Output_data_plt_i386_standard
+{
+ public:
+ Output_data_plt_i386_dyn(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386_standard(layout, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov, elfcpp::Elf_types<32>::Elf_Addr);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset);
+
+ private:
+ // The first entry in the PLT for a shared object.
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for a shared object.
+ static const unsigned char plt_entry[plt_entry_size];
+};
+
+// The i386 target class.
+// TLS info comes from
+// http://people.redhat.com/drepper/tls.pdf
+// 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<elfcpp::SHT_REL, true, 32, false> 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<elfcpp::SHT_REL, 32, false> 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<Global_ifunc>::const_iterator p =
+ this->global_ifuncs_.begin();
+ p != this->global_ifuncs_.end();
+ ++p)
+ {
+ const Sized_symbol<32>* ssym =
+ static_cast<const Sized_symbol<32>*>(p->sym);
+ elfcpp::Swap<32, false>::writeval(got_irelative_view + p->got_offset,
+ ssym->value());
+ }
+
+ for (std::vector<Local_ifunc>::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<section_size_type>(pov - oview) == oview_size);
+ gold_assert(static_cast<section_size_type>(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<elfcpp::SHT_REL,
+ Relocatable_size_for_reloc> 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<char*>(&jmp[0]), 5)
+ + std::string(length - 5, static_cast<char>(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<Sized_symbol<32>*>(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<size_t>(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<char>(0x90));
+}
+
+// The selector for i386-nacl object files.
+
+class Target_selector_i386_nacl
+ : public Target_selector_nacl<Target_selector_i386, Target_i386_nacl>
+{
+ public:
+ Target_selector_i386_nacl()
+ : Target_selector_nacl<Target_selector_i386,
+ Target_i386_nacl>("x86-32",
+ "elf32-i386-nacl",
+ "elf_i386_nacl")
+ { }
+};
+
+Target_selector_i386_nacl target_selector_i386;
+
+} // End anonymous namespace.
diff --git a/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 <tmsriram@google.com>.
+
+// 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 <num> --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<Section_id>& id_section,
+ std::vector<bool>* is_secn_or_group_unique,
+ std::vector<std::string>* section_contents)
+{
+ Unordered_map<uint32_t, unsigned int> uniq_map;
+ std::pair<Unordered_map<uint32_t, unsigned int>::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<const Task*>(-1);
+ Task_lock_obj<Object> 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
+ <const unsigned char*>((*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<unsigned int>& kept_section_id,
+ std::vector<std::string>* 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<const Task*>(-1);
+ Task_lock_obj<Object> 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<off_t, long long>(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<long long>((*it_a).first),
+ static_cast<long long>((*it_a).second),
+ static_cast<unsigned long long>(*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<unsigned long long>(*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<const char*>(str_contents);
+ switch(entsize)
+ {
+ case 1:
+ {
+ buffer.append(str_char);
+ break;
+ }
+ case 2:
+ {
+ const uint16_t* ptr_16 =
+ reinterpret_cast<const uint16_t*>(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<const uint32_t*>(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<const
+ char*>(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<const char*>(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<unsigned int>* num_tracked_relocs,
+ std::vector<unsigned int>* kept_section_id,
+ const std::vector<Section_id>& id_section,
+ std::vector<bool>* is_secn_or_group_unique,
+ std::vector<std::string>* section_contents)
+{
+ Unordered_multimap<uint32_t, unsigned int> section_cksum;
+ std::pair<Unordered_multimap<uint32_t, unsigned int>::iterator,
+ Unordered_multimap<uint32_t, unsigned int>::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<std::string> 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<const unsigned char*>(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<uint32_t, unsigned int>::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<unsigned int> num_tracked_relocs;
+ std::vector<bool> is_secn_or_group_unique;
+ std::vector<std::string> 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<const Task*>(-1);
+ Task_lock_obj<Object> 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,
+ &section_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 <tmsriram@google.com>.
+
+// 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 <vector>
+
+#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<Section_id> Sections_reachable_info;
+ typedef std::vector<Symbol*> Symbol_info;
+ typedef std::vector<std::pair<long long, long long> > Addend_info;
+ typedef std::vector<uint64_t> Offset_info;
+ typedef std::vector<unsigned int> Reloc_addend_size_info;
+ typedef Unordered_map<Section_id,
+ unsigned int,
+ Section_id_hash> Uniq_secn_id_map;
+ typedef Unordered_set<Section_id, Section_id_hash> 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<Section_id, Reloc_info,
+ Section_id_hash> 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<Section_id> 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<unsigned int> 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 <rafael.espindola@gmail.com>
+
+// 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 <stdio.h>
+#include <errno.h>
+#include <time.h>
+
+#include "incremental.h"
+
+namespace gold
+{
+ class Output_file;
+}
+
+using namespace gold;
+
+template<int size, bool big_endian>
+static typename Incremental_inputs_reader<size, big_endian>::
+ Incremental_input_entry_reader
+find_input_containing_global(
+ Incremental_inputs_reader<size, big_endian>& incremental_inputs,
+ unsigned int offset,
+ unsigned int* symndx)
+{
+ typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
+ static const unsigned int global_sym_entry_size =
+ Incremental_inputs_reader<size, big_endian>::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<int size, bool big_endian>
+static void
+dump_incremental_inputs(const char* argv0, const char* filename,
+ Sized_incremental_binary<size, big_endian>* inc)
+{
+ typedef Incremental_binary::Location Location;
+ typedef Incremental_binary::View View;
+ typedef Incremental_inputs_reader<size, big_endian> 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<size, big_endian>
+ 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<unsigned long long>(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<long long>(info.sh_offset),
+ static_cast<long long>(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<size, big_endian, Incremental_binary> 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<big_endian> isymtab(inc->symtab_reader());
+ Incremental_relocs_reader<size, big_endian> irelocs(inc->relocs_reader());
+ unsigned int sym_size = elfcpp::Elf_sizes<size>::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<size, big_endian> sym(sym_p);
+ const char* symname;
+ if (!strtab.get_c_string(sym.get_st_name(), &symname))
+ symname = "<unknown>";
+ 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<big_endian> 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<size, big_endian> sym(sym_p);
+ const char* symname;
+ if (!strtab.get_c_string(sym.get_st_name(), &symname))
+ symname = "<unknown>";
+ 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<size, big_endian> sym(sym_p);
+ const char* symname;
+ if (!strtab.get_c_string(sym.get_st_name(), &symname))
+ symname = "<unknown>";
+ 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<size, big_endian>(incremental_inputs,
+ offset, &sym_ndx);
+ Incremental_global_symbol_reader<big_endian> 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<long long>(irelocs.get_r_offset(r_off)),
+ static_cast<long long>(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<big_endian> 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<size, big_endian> sym(sym_p);
+ const char* symname;
+ if (!strtab.get_c_string(sym.get_st_name(), &symname))
+ symname = "<unknown>";
+ 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<size, big_endian> sym(sym_p);
+ const char* symname;
+ if (!strtab.get_c_string(sym.get_st_name(), &symname))
+ symname = "<unknown>";
+ 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 <file>\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<Sized_incremental_binary<32, false>*>(inc));
+ break;
+#endif
+#ifdef HAVE_TARGET_32_BIG
+ case Parameters::TARGET_32_BIG:
+ dump_incremental_inputs<32, true>(
+ argv[0], filename,
+ static_cast<Sized_incremental_binary<32, true>*>(inc));
+ break;
+#endif
+#ifdef HAVE_TARGET_64_LITTLE
+ case Parameters::TARGET_64_LITTLE:
+ dump_incremental_inputs<64, false>(
+ argv[0], filename,
+ static_cast<Sized_incremental_binary<64, false>*>(inc));
+ break;
+#endif
+#ifdef HAVE_TARGET_64_BIG
+ case Parameters::TARGET_64_BIG:
+ dump_incremental_inputs<64, true>(
+ argv[0], filename,
+ static_cast<Sized_incremental_binary<64, true>*>(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 <mikolajz@google.com>.
+
+// 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 <set>
+#include <cstdarg>
+#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<int size, bool big_endian>
+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<size, big_endian> 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<size, big_endian>::header_size;
+ static const int input_entry_size =
+ Incremental_inputs_reader<size, big_endian>::input_entry_size;
+ static const unsigned int object_info_size =
+ Incremental_inputs_reader<size, big_endian>::object_info_size;
+ static const unsigned int input_section_entry_size =
+ Incremental_inputs_reader<size, big_endian>::input_section_entry_size;
+ static const unsigned int global_sym_entry_size =
+ Incremental_inputs_reader<size, big_endian>::global_sym_entry_size;
+ static const unsigned int incr_reloc_size =
+ Incremental_relocs_reader<size, big_endian>::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<int size, bool big_endian>
+bool
+Sized_incremental_binary<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_incremental_binary<size, big_endian>::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<size, big_endian>(inputs_view.data(), strtab);
+ this->symtab_reader_ =
+ Incremental_symtab_reader<big_endian>(symtab_view.data(),
+ symtab_location.data_size);
+ this->relocs_reader_ =
+ Incremental_relocs_reader<size, big_endian>(relocs_view.data(),
+ relocs_location.data_size);
+ this->got_plt_reader_ =
+ Incremental_got_plt_reader<big_endian>(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<size, big_endian>& 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<const Input_argument*>& 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<int size, bool big_endian>
+bool
+Sized_incremental_binary<size, big_endian>::do_check_inputs(
+ const Command_line& cmdline,
+ Incremental_inputs* incremental_inputs)
+{
+ Incremental_inputs_reader<size, big_endian>& 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<int size, bool big_endian>
+bool
+Sized_incremental_binary<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_incremental_binary<size, big_endian>::do_init_layout(Layout* layout)
+{
+ typedef elfcpp::Shdr<size, big_endian> Shdr;
+ const int shdr_size = elfcpp::Elf_sizes<size>::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<long>(shdr.get_sh_addr()),
+ static_cast<long>(shdr.get_sh_offset()),
+ static_cast<long>(shdr.get_sh_size()),
+ shdr.get_sh_type(), name ? name : "<null>");
+ this->section_map_[i] = layout->init_fixed_output_section(name, shdr);
+ pshdr += shdr_size;
+ }
+}
+
+// Mark regions of the input file that must be kept unchanged.
+
+template<int size, bool big_endian>
+void
+Sized_incremental_binary<size, big_endian>::do_reserve_layout(
+ unsigned int input_file_index)
+{
+ const int sym_size = elfcpp::Elf_sizes<size>::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<size, big_endian> 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<int>(offset),
+ static_cast<int>(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<int size, bool big_endian>
+void
+Sized_incremental_binary<size, big_endian>::do_process_got_plt(
+ Symbol_table* symtab,
+ Layout* layout)
+{
+ Incremental_got_plt_reader<big_endian> got_plt_reader(this->got_plt_reader());
+ Sized_target<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
+
+ // 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<size>::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<size, big_endian>* 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<int size, bool big_endian>
+void
+Sized_incremental_binary<size, big_endian>::do_emit_copy_relocs(
+ Symbol_table* symtab)
+{
+ Sized_target<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
+
+ 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<int size, bool big_endian>
+void
+Sized_incremental_binary<size, big_endian>::do_apply_incremental_relocs(
+ const Symbol_table* symtab,
+ Layout* layout,
+ Output_file* of)
+{
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename elfcpp::Elf_types<size>::Elf_Swxword Addend;
+ Incremental_symtab_reader<big_endian> isymtab(this->symtab_reader());
+ Incremental_relocs_reader<size, big_endian> irelocs(this->relocs_reader());
+ unsigned int nglobals = isymtab.symbol_count();
+ const unsigned int incr_reloc_size = irelocs.reloc_size;
+
+ Relocate_info<size, big_endian> 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<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
+
+ 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<big_endian> 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<int size, bool big_endian>
+void
+Sized_incremental_binary<size, big_endian>::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<size>::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<int size, bool big_endian>
+Incremental_binary*
+make_sized_incremental_binary(Output_file* file,
+ const elfcpp::Ehdr<size, big_endian>& 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 != &parameters->target())
+ gold_error(_("%s: incompatible target"), file->filename());
+
+ return new Sized_incremental_binary<size, big_endian>(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<int size, bool big_endian>
+void
+Output_section_incremental_inputs<size, big_endian>::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<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
+ 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<int size, bool big_endian>
+void
+Output_section_incremental_inputs<size, big_endian>::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<off_t>(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<int size, bool big_endian>
+unsigned char*
+Output_section_incremental_inputs<size, big_endian>::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<int size, bool big_endian>
+unsigned char*
+Output_section_incremental_inputs<size, big_endian>::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<unsigned int>(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<int size, bool big_endian>
+unsigned char*
+Output_section_incremental_inputs<size, big_endian>::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<unsigned int>(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<unsigned int>(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<const Relobj*>(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<unsigned int>(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<unsigned int>(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<unsigned int>(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<unsigned int>(pov - oview) & 4)
+ {
+ Swap32::writeval(pov, 0);
+ pov += 4;
+ }
+ }
+ return pov;
+}
+
+// Write the contents of the .gnu_incremental_symtab section.
+
+template<int size, bool big_endian>
+void
+Output_section_incremental_inputs<size, big_endian>::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<int size, bool big_endian>
+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<int size, bool big_endian>
+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<int size, bool big_endian>
+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<size>* sym)
+ {
+ typedef Global_got_offset_visitor<size, big_endian> 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<int size, bool big_endian>
+void
+Output_section_incremental_inputs<size, big_endian>::write_got_plt(
+ unsigned char* pov,
+ off_t view_size)
+{
+ Sized_target<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
+
+ // 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<size, big_endian> 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<size, big_endian> Symbol_visitor;
+ symtab_->for_all_symbols<size, Symbol_visitor>(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<int size, bool big_endian>
+Sized_relobj_incr<size, big_endian>::Sized_relobj_incr(
+ const std::string& name,
+ Sized_incremental_binary<size, big_endian>* ibase,
+ unsigned int input_file_index)
+ : Sized_relobj<size, big_endian>(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<int size, bool big_endian>
+void
+Sized_relobj_incr<size, big_endian>::do_read_symbols(Read_symbols_data*)
+{
+ gold_unreachable();
+}
+
+// Lay out the input sections.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_incr<size, big_endian>::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<unsigned int> debug_info_sections;
+ std::vector<unsigned int> 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<Address>(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<unsigned int>::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<unsigned int>::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<int size, bool big_endian>
+void
+Sized_relobj_incr<size, big_endian>::do_layout_deferred_sections(Layout*)
+{
+}
+
+// Add the symbols to the symbol table.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_incr<size, big_endian>::do_add_symbols(
+ Symbol_table* symtab,
+ Read_symbols_data*,
+ Layout*)
+{
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ unsigned char symbuf[sym_size];
+ elfcpp::Sym<size, big_endian> sym(symbuf);
+ elfcpp::Sym_write<size, big_endian> osym(symbuf);
+
+ typedef typename elfcpp::Elf_types<size>::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<big_endian> 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<big_endian> 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<size, big_endian> gsym(sym_p);
+ const char* name;
+ if (!strtab.get_c_string(gsym.get_st_name(), &name))
+ name = "";
+
+ typename elfcpp::Elf_types<size>::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<int size, bool big_endian>
+Archive::Should_include
+Sized_relobj_incr<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_relobj_incr<size, big_endian>::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<int size, bool big_endian>
+uint64_t
+Sized_relobj_incr<size, big_endian>::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<int size, bool big_endian>
+std::string
+Sized_relobj_incr<size, big_endian>::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<int size, bool big_endian>
+const unsigned char*
+Sized_relobj_incr<size, big_endian>::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<int size, bool big_endian>
+uint64_t
+Sized_relobj_incr<size, big_endian>::do_section_flags(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return section entsize.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_relobj_incr<size, big_endian>::do_section_entsize(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return section address.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_relobj_incr<size, big_endian>::do_section_address(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return section type.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_relobj_incr<size, big_endian>::do_section_type(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return the section link field.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_relobj_incr<size, big_endian>::do_section_link(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return the section link field.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_relobj_incr<size, big_endian>::do_section_info(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return the section alignment.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_relobj_incr<size, big_endian>::do_section_addralign(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return the Xindex structure to use.
+
+template<int size, bool big_endian>
+Xindex*
+Sized_relobj_incr<size, big_endian>::do_initialize_xindex()
+{
+ gold_unreachable();
+}
+
+// Get symbol counts.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_incr<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_relobj_incr<size, big_endian>::do_read_relocs(Read_relocs_data*)
+{
+}
+
+// Process the relocs to find list of referenced sections. Used only
+// during garbage collection.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_incr<size, big_endian>::do_gc_process_relocs(Symbol_table*,
+ Layout*,
+ Read_relocs_data*)
+{
+ gold_unreachable();
+}
+
+// Scan the relocs and adjust the symbol table.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_incr<size, big_endian>::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<big_endian> 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<size, big_endian>& 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<int size, bool big_endian>
+void
+Sized_relobj_incr<size, big_endian>::do_count_local_symbols(
+ Stringpool_template<char>* pool,
+ Stringpool_template<char>*)
+{
+ const int sym_size = elfcpp::Elf_sizes<size>::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<size, big_endian> 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<int size, bool big_endian>
+unsigned int
+Sized_relobj_incr<size, big_endian>::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<int size, bool big_endian>
+unsigned int
+Sized_relobj_incr<size, big_endian>::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<int size, bool big_endian>
+unsigned int
+Sized_relobj_incr<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_relobj_incr<size, big_endian>::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<size, big_endian>::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<size, big_endian> 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<elfcpp::STT>(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<size, big_endian> osym(dyn_ov);
+ osym.put_st_name(dynpool->get_offset(lsym.name));
+ osym.put_st_value(lsym.st_value);
+ osym.put_st_size(lsym.st_size);
+ osym.put_st_info(elfcpp::STB_LOCAL,
+ static_cast<elfcpp::STT>(lsym.st_type));
+ osym.put_st_other(0);
+ osym.put_st_shndx(st_shndx);
+ dyn_ov += sym_size;
+ }
+ }
+
+ 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<int size, bool big_endian>
+void
+Sized_relobj_incr<size, big_endian>::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<int size, bool big_endian>
+Sized_incr_dynobj<size, big_endian>::Sized_incr_dynobj(
+ const std::string& name,
+ Sized_incremental_binary<size, big_endian>* 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<int size, bool big_endian>
+void
+Sized_incr_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data*)
+{
+ gold_unreachable();
+}
+
+// Lay out the input sections.
+
+template<int size, bool big_endian>
+void
+Sized_incr_dynobj<size, big_endian>::do_layout(
+ Symbol_table*,
+ Layout*,
+ Read_symbols_data*)
+{
+}
+
+// Add the symbols to the symbol table.
+
+template<int size, bool big_endian>
+void
+Sized_incr_dynobj<size, big_endian>::do_add_symbols(
+ Symbol_table* symtab,
+ Read_symbols_data*,
+ Layout*)
+{
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ unsigned char symbuf[sym_size];
+ elfcpp::Sym<size, big_endian> sym(symbuf);
+ elfcpp::Sym_write<size, big_endian> 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<big_endian> 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<Address> 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<size, big_endian> 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<size>* res =
+ symtab->add_from_incrobj<size, big_endian>(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<typename Copied_symbols::iterator, bool> 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<int size, bool big_endian>
+Archive::Should_include
+Sized_incr_dynobj<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_incr_dynobj<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_incr_dynobj<size, big_endian>::do_for_all_local_got_entries(
+ Got_offset_list::Visitor*) const
+{
+}
+
+// Get the size of a section.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_dynobj<size, big_endian>::do_section_size(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Get the name of a section.
+
+template<int size, bool big_endian>
+std::string
+Sized_incr_dynobj<size, big_endian>::do_section_name(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return a view of the contents of a section.
+
+template<int size, bool big_endian>
+const unsigned char*
+Sized_incr_dynobj<size, big_endian>::do_section_contents(
+ unsigned int,
+ section_size_type*,
+ bool)
+{
+ gold_unreachable();
+}
+
+// Return section flags.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_dynobj<size, big_endian>::do_section_flags(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return section entsize.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_dynobj<size, big_endian>::do_section_entsize(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return section address.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_dynobj<size, big_endian>::do_section_address(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return section type.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_incr_dynobj<size, big_endian>::do_section_type(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return the section link field.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_incr_dynobj<size, big_endian>::do_section_link(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return the section link field.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_incr_dynobj<size, big_endian>::do_section_info(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return the section alignment.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_dynobj<size, big_endian>::do_section_addralign(unsigned int)
+{
+ gold_unreachable();
+}
+
+// Return the Xindex structure to use.
+
+template<int size, bool big_endian>
+Xindex*
+Sized_incr_dynobj<size, big_endian>::do_initialize_xindex()
+{
+ gold_unreachable();
+}
+
+// Get symbol counts.
+
+template<int size, bool big_endian>
+void
+Sized_incr_dynobj<size, big_endian>::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<Sized_incremental_binary<32, false>*>(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<Sized_incremental_binary<32, true>*>(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<Sized_incremental_binary<64, false>*>(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<Sized_incremental_binary<64, true>*>(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 <mikolajz@google.com>.
+
+// 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 <map>
+#include <vector>
+
+#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<Incremental_input_entry*> 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<Input_section> sections_;
+
+ // COMDAT groups.
+ std::vector<Stringpool::Key> 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<Incremental_object_entry*> members_;
+
+ // Unused global symbols from this archive.
+ std::vector<Stringpool::Key> 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<Incremental_input_entry*> 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<bool big_endian>
+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<int size, bool big_endian>
+class Incremental_inputs_reader
+{
+ private:
+ typedef elfcpp::Swap<size, big_endian> 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<size, big_endian>::object_info_size;
+ static const unsigned int input_section_entry_size =
+ Incremental_inputs_reader<size, big_endian>::input_section_entry_size;
+ static const unsigned int global_sym_entry_size =
+ Incremental_inputs_reader<size, big_endian>::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<Incremental_input_type>(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<big_endian>
+ 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<big_endian>(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<big_endian>
+ global_symbol_reader_at_offset(unsigned int offset) const
+ {
+ const unsigned char* p = this->p_ + offset;
+ return Incremental_global_symbol_reader<big_endian>(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<bool big_endian>
+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<unsigned int>(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<int size, bool big_endian>
+class Incremental_relocs_reader
+{
+ private:
+ // Size of each field.
+ static const unsigned int field_size = size / 8;
+
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename elfcpp::Elf_types<size>::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<unsigned int>(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<size, big_endian>::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<size, big_endian>::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<bool big_endian>
+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<size, big_endian> 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<const Input_argument*> input_args_map_;
+ // Map from an input file index to an Incremental_library.
+ std::vector<Incremental_library*> library_map_;
+ // Map from an input file index to a Script_info.
+ std::vector<Script_info*> script_map_;
+
+ private:
+ // Edited output file object.
+ Output_file* output_;
+};
+
+template<int size, bool big_endian>
+class Sized_relobj_incr;
+
+template<int size, bool big_endian>
+class Sized_incremental_binary : public Incremental_binary
+{
+ public:
+ Sized_incremental_binary(Output_file* output,
+ const elfcpp::Ehdr<size, big_endian>& 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<size, big_endian>* obj)
+ { this->input_objects_[n] = obj; }
+
+ // Return a pointer to the object for input file N.
+ Sized_relobj_incr<size, big_endian>*
+ 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<size, big_endian>&
+ inputs_reader() const
+ { return this->inputs_reader_; }
+
+ const Incremental_symtab_reader<big_endian>&
+ symtab_reader() const
+ { return this->symtab_reader_; }
+
+ const Incremental_relocs_reader<size, big_endian>&
+ relocs_reader() const
+ { return this->relocs_reader_; }
+
+ const Incremental_got_plt_reader<big_endian>&
+ 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<size, big_endian> 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_reloc> 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<size, big_endian, Incremental_binary> elf_file_;
+
+ // Vector of pointers to the input objects for the unchanged files.
+ // For replaced files, the corresponding pointer is NULL.
+ std::vector<Sized_relobj_incr<size, big_endian>*> input_objects_;
+
+ // Map section index to an Output_section in the updated layout.
+ std::vector<Output_section*> section_map_;
+
+ // Map global symbols from the input file to the symbol table.
+ std::vector<Symbol*> 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<size, big_endian> inputs_reader_;
+ Incremental_symtab_reader<big_endian> symtab_reader_;
+ Incremental_relocs_reader<size, big_endian> relocs_reader_;
+ Incremental_got_plt_reader<big_endian> got_plt_reader_;
+ std::vector<Sized_input_reader> 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<int size, bool big_endian>
+class Sized_relobj_incr : public Sized_relobj<size, big_endian>
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename Sized_relobj<size, big_endian>::Symbols Symbols;
+
+ Sized_relobj_incr(const std::string& name,
+ Sized_incremental_binary<size, big_endian>* ibase,
+ unsigned int input_file_index);
+
+ private:
+ // For convenience.
+ typedef Sized_relobj_incr<size, big_endian> This;
+ static const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+ typedef typename Sized_relobj<size, big_endian>::Output_sections
+ Output_sections;
+ typedef Incremental_inputs_reader<size, big_endian> 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<char>*,
+ Stringpool_template<char>*);
+
+ // 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<size, big_endian>* 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_symbol> 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<int size, bool big_endian>
+class Sized_incr_dynobj : public Dynobj
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+
+ static const Address invalid_address = static_cast<Address>(0) - 1;
+
+ Sized_incr_dynobj(const std::string& name,
+ Sized_incremental_binary<size, big_endian>* ibase,
+ unsigned int input_file_index);
+
+ private:
+ typedef Incremental_inputs_reader<size, big_endian> 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<size, big_endian>* 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<std::string> 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 <dougkwan@google.com> by refactoring scattered
+// contents from other files in gold. Original code written by Ian
+// Lance Taylor <iant@google.com> and Caleb Howe <cshowe@google.com>.
+
+// 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 <vector>
+
+#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<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(byte & 0x7f) << shift);
+ shift += 7;
+ }
+ while (byte & 0x80);
+
+ if ((shift < 8 * static_cast<int>(sizeof(result))) && (byte & 0x40))
+ result |= -((static_cast<int64_t>(1)) << shift);
+ *len = num_read;
+ return result;
+}
+
+void
+write_unsigned_LEB_128(std::vector<unsigned char>* 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 <dougkwan@google.com> by refactoring scattered
+// contents from other files in gold. Original code written by Ian
+// Lance Taylor <iant@google.com> and Caleb Howe <cshowe@google.com>.
+
+// 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 <vector>
+#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<uint64_t>(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<int64_t>(1) << 7) | static_cast<int64_t>(byte);
+ return static_cast<int64_t>(byte);
+}
+
+// Write a ULEB 128 encoded VALUE to BUFFER.
+
+void
+write_unsigned_LEB_128(std::vector<unsigned char>* 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 <int valsize>
+void insert_into_vector(std::vector<unsigned char>* destination,
+ typename elfcpp::Valtype_base<valsize>::Valtype value)
+{
+ unsigned char buffer[valsize / 8];
+ if (parameters->target().is_big_endian())
+ elfcpp::Swap_unaligned<valsize, true>::writeval(buffer, value);
+ else
+ elfcpp::Swap_unaligned<valsize, false>::writeval(buffer, value);
+ destination->insert(destination->end(), buffer, buffer + valsize / 8);
+}
+
+// Read a possibly unaligned integer of SIZE from SOURCE.
+
+template <int valsize>
+typename elfcpp::Valtype_base<valsize>::Valtype
+read_from_pointer(const unsigned char* source)
+{
+ typename elfcpp::Valtype_base<valsize>::Valtype return_value;
+ if (parameters->target().is_big_endian())
+ return_value = elfcpp::Swap_unaligned<valsize, true>::readval(source);
+ else
+ return_value = elfcpp::Swap_unaligned<valsize, false>::readval(source);
+ return return_value;
+}
+
+// Read a possibly unaligned integer of SIZE. Update SOURCE after read.
+
+template <int valsize>
+typename elfcpp::Valtype_base<valsize>::Valtype
+read_from_pointer(unsigned char** source)
+{
+ typename elfcpp::Valtype_base<valsize>::Valtype return_value;
+ if (parameters->target().is_big_endian())
+ return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source);
+ else
+ return_value = elfcpp::Swap_unaligned<valsize, false>::readval(*source);
+ *source += valsize / 8;
+ return return_value;
+}
+
+// Same as the above except for use with const unsigned char data.
+
+template <int valsize>
+typename elfcpp::Valtype_base<valsize>::Valtype
+read_from_pointer(const unsigned char** source)
+{
+ typename elfcpp::Valtype_base<valsize>::Valtype return_value;
+ if (parameters->target().is_big_endian())
+ return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source);
+ else
+ return_value = elfcpp::Swap_unaligned<valsize, false>::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 <iant@google.com>.
+
+// 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 <cerrno>
+#include <cstring>
+#include <algorithm>
+#include <iostream>
+#include <fstream>
+#include <utility>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <unistd.h>
+#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<int>(start), static_cast<int>(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<long>(len), static_cast<int>(align),
+ static_cast<long>(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<long>(p->start_),
+ static_cast<long>(p->end_),
+ static_cast<long>(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<const char*>(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<int size, bool big_endian>
+bool
+Layout::include_section(Sized_relobj_file<size, big_endian>*, const char* name,
+ const elfcpp::Shdr<size, big_endian>& 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<elfcpp::PT>((*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<Section_id, Section_id_hash> 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<Key, Output_section*> v(key, NULL);
+ std::pair<Section_name_map::iterator, bool> 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<int size, bool big_endian>
+Output_section*
+Layout::init_fixed_output_section(const char* name,
+ elfcpp::Shdr<size, big_endian>& 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<size>::Elf_Addr sh_addr = shdr.get_sh_addr();
+ typename elfcpp::Elf_types<size>::Elf_Off sh_offset = shdr.get_sh_offset();
+ typename elfcpp::Elf_types<size>::Elf_WXword sh_size = shdr.get_sh_size();
+ typename elfcpp::Elf_types<size>::Elf_WXword sh_flags = shdr.get_sh_flags();
+ typename elfcpp::Elf_types<size>::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<int size, bool big_endian>
+Output_section*
+Layout::layout(Sized_relobj_file<size, big_endian>* object, unsigned int shndx,
+ const char* name, const elfcpp::Shdr<size, big_endian>& 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<int size, bool big_endian>
+Output_section*
+Layout::layout_reloc(Sized_relobj_file<size, big_endian>* object,
+ unsigned int,
+ const elfcpp::Shdr<size, big_endian>& 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<size>::rel_size);
+ posd = new Output_relocatable_relocs<elfcpp::SHT_REL,
+ size,
+ big_endian>(rr);
+ }
+ else if (sh_type == elfcpp::SHT_RELA)
+ {
+ os->set_entsize(elfcpp::Elf_sizes<size>::rela_size);
+ posd = new Output_relocatable_relocs<elfcpp::SHT_RELA,
+ size,
+ big_endian>(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<int size, bool big_endian>
+void
+Layout::layout_group(Symbol_table* symtab,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int,
+ const char* group_section_name,
+ const char* signature,
+ const elfcpp::Shdr<size, big_endian>& shdr,
+ elfcpp::Elf_Word flags,
+ std::vector<unsigned int>* 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<size, big_endian>(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<int size, bool big_endian>
+Output_section*
+Layout::layout_eh_frame(Sized_relobj_file<size, big_endian>* 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<size, big_endian>& 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<int size, bool big_endian>
+void
+Layout::add_to_gdb_index(bool is_type_unit,
+ Sized_relobj<size, big_endian>* 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(&parameters->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<Target*>(&parameters->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(&parameters->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<std::string, unsigned int>::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<std::string>::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<Symbol*> 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<size_t>(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<long>(off),
+ static_cast<long>((*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<Object> 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<off_t>(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<off_t>(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<long>(symtab_off),
+ static_cast<long>(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<long>(off),
+ static_cast<long>(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<Symbol*>* 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<Symbol*>& 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<int size, bool big_endian>
+void
+Layout::sized_create_version_sections(
+ const Versions* versions,
+ const Symbol_table* symtab,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& 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<size, big_endian>(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<size, big_endian>(&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<size, big_endian>(&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<elfcpp::SHT_REL, 32, false>::reloc_size;
+ else if (size == 64)
+ rel_size = Reloc_types<elfcpp::SHT_REL, 64, false>::reloc_size;
+ else
+ gold_unreachable();
+ }
+ else
+ {
+ rel_tag = elfcpp::DT_RELAENT;
+ if (size == 32)
+ rel_size = Reloc_types<elfcpp::SHT_RELA, 32, false>::reloc_size;
+ else if (size == 64)
+ rel_size = Reloc_types<elfcpp::SHT_RELA, 64, false>::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<Signatures::iterator, bool> 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<size_t>(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<const char*>(iv), output_file_size, ov);
+ else if (strcmp(style, "md5") == 0)
+ md5_buffer(reinterpret_cast<const char*>(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<const char*>(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<unsigned int>* 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<unsigned int>* 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<unsigned int>* 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<unsigned int>* 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 <iant@google.com>.
+
+// 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 <cstring>
+#include <list>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#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<Free_list_node>::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<Free_list_node>::iterator Iterator;
+
+ // The free list.
+ std::list<Free_list_node> 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<std::string, Comdat_section_info> 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<int size, bool big_endian>
+ Output_section*
+ init_fixed_output_section(const char*, elfcpp::Shdr<size, big_endian>&);
+
+ // 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<int size, bool big_endian>
+ Output_section*
+ layout(Sized_relobj_file<size, big_endian> *object, unsigned int shndx,
+ const char* name, const elfcpp::Shdr<size, big_endian>& shdr,
+ unsigned int reloc_shndx, unsigned int reloc_type, off_t* offset);
+
+ std::map<Section_id, unsigned int>*
+ 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<Const_section_id, Unique_segment_info*>
+ 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<int size, bool big_endian>
+ Output_section*
+ layout_reloc(Sized_relobj_file<size, big_endian>* object,
+ unsigned int reloc_shndx,
+ const elfcpp::Shdr<size, big_endian>& shdr,
+ Output_section* data_section,
+ Relocatable_relocs* rr);
+
+ // Layout a group section when doing a relocatable link.
+ template<int size, bool big_endian>
+ void
+ layout_group(Symbol_table* symtab,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int group_shndx,
+ const char* group_section_name,
+ const char* signature,
+ const elfcpp::Shdr<size, big_endian>& shdr,
+ elfcpp::Elf_Word flags,
+ std::vector<unsigned int>* 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<int size, bool big_endian>
+ Output_section*
+ layout_eh_frame(Sized_relobj_file<size, big_endian>* 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<size, big_endian>& 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<int size, bool big_endian>
+ void
+ add_to_gdb_index(bool is_type_unit,
+ Sized_relobj<size, big_endian>* 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<Output_segment*> Segment_list;
+
+ // A list of sections.
+
+ typedef std::vector<Output_section*> Section_list;
+
+ // The list of information to write out which is not attached to
+ // either a section or a segment.
+ typedef std::vector<Output_data*> 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_signature> 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<Symbol*>* 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<Symbol*>& dynamic_symbols,
+ const Output_section* dynstr);
+
+ template<int size, bool big_endian>
+ void
+ sized_create_version_sections(const Versions* versions,
+ const Symbol_table*,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& dynamic_symbols,
+ const Output_section* dynstr);
+
+ // Return whether to include this section in the link.
+ template<int size, bool big_endian>
+ bool
+ include_section(Sized_relobj_file<size, big_endian>* object, const char* name,
+ const elfcpp::Shdr<size, big_endian>&);
+
+ // 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<const Output_segment*, const Output_segment*>
+ 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<std::string, Kept_section> Signatures;
+
+ // Mapping from input section name/type/flags to output section. We
+ // use canonicalized strings here.
+
+ typedef std::pair<Stringpool::Key,
+ std::pair<elfcpp::Elf_Word, elfcpp::Elf_Xword> > Key;
+
+ struct Hash_key
+ {
+ size_t
+ operator()(const Key& k) const;
+ };
+
+ typedef Unordered_map<Key, Output_section*, Hash_key> 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*> 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_info> 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_id, unsigned int> 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<std::string, unsigned int> input_section_position_;
+ // Vector of glob only patterns in the section_ordering file.
+ std::vector<std::string> 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 <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include "gold.h"
+
+#include <cstdio>
+#include <cstring>
+
+#ifdef HAVE_MALLINFO
+#include <malloc.h>
+#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 <stdio.h>
+#include <sys/stat.h> // 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<const char**>(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<long long>(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 <iant@google.com>.
+
+// 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 <cerrno>
+#include <cstdio>
+#include <cstring>
+
+#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<unsigned long long>(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<int size, bool big_endian>
+void
+Mapfile::print_input_section_symbols(
+ const Sized_relobj_file<size, big_endian>* 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<size>* ssym =
+ static_cast<const Sized_symbol<size>*>(sym);
+ fprintf(this->map_file_,
+ "0x%0*llx %s\n",
+ size / 4,
+ static_cast<unsigned long long>(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<unsigned long long>(relobj->section_size(shndx)));
+
+ fprintf(this->map_file_, "0x%0*llx %10s %s\n",
+ parameters->target().get_size() / 4,
+ static_cast<unsigned long long>(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<Sized_relobj_file<32, false>*>(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<Sized_relobj_file<32, true>*>(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<Sized_relobj_file<64, false>*>(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<Sized_relobj_file<64, true>*>(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<unsigned long long>(od->data_size()));
+
+ fprintf(this->map_file_, "0x%0*llx %10s\n",
+ parameters->target().get_size() / 4,
+ static_cast<unsigned long long>(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<const Task*>(-1);
+ Task_lock_obj<Object> 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<unsigned long long>(os->data_size()));
+
+ fprintf(this->map_file_, "0x%0*llx %10s",
+ parameters->target().get_size() / 4,
+ static_cast<unsigned long long>(os->address()), sizebuf);
+
+ if (os->has_load_address())
+ fprintf(this->map_file_, " load address 0x%-*llx",
+ parameters->target().get_size() / 4,
+ static_cast<unsigned long long>(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 <iant@google.com>.
+
+// 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 <cstdio>
+#include <string>
+
+namespace gold
+{
+
+class Archive;
+class Symbol;
+class Relobj;
+template<int size, bool big_endian>
+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<int size, bool big_endian>
+ void
+ print_input_section_symbols(const Sized_relobj_file<size, big_endian>*,
+ 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 <iant@google.com>.
+
+// 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 <cstdlib>
+#include <algorithm>
+
+#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<section_size_type>(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<Input_merge_entry>::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<section_offset_type>(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<int size>
+void
+Object_merge_map::initialize_input_to_output_map(
+ unsigned int shndx,
+ typename elfcpp::Elf_types<size>::Elf_Addr starting_address,
+ Unordered_map<section_offset_type,
+ typename elfcpp::Elf_types<size>::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<Input_sections::iterator, bool> 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<size_t>(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<unsigned char*>(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<Merge_data_hashtable::iterator, bool> 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<unsigned char*>(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<unsigned long>(this->entsize()),
+ this->input_count_, this->hashtable_.size());
+}
+
+// Class Output_merge_string.
+
+// Add an input section to a merged string section.
+
+template<typename Char_type>
+bool
+Output_merge_string<Char_type>::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<const Char_type*>(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<uintptr_t>(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<uintptr_t>(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<typename Char_type>
+section_size_type
+Output_merge_string<Char_type>::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<typename Char_type>
+void
+Output_merge_string<Char_type>::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<typename Char_type>
+void
+Output_merge_string<Char_type>::do_write(Output_file* of)
+{
+ this->stringpool_.write(of, this->offset());
+}
+
+// Write a merged string section to a buffer.
+
+template<typename Char_type>
+void
+Output_merge_string<Char_type>::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<typename Char_type>
+const char*
+Output_merge_string<Char_type>::string_name()
+{
+ gold_unreachable();
+ return NULL;
+}
+
+template<>
+const char*
+Output_merge_string<char>::string_name()
+{
+ return "strings";
+}
+
+template<>
+const char*
+Output_merge_string<uint16_t>::string_name()
+{
+ return "16-bit strings";
+}
+
+template<>
+const char*
+Output_merge_string<uint32_t>::string_name()
+{
+ return "32-bit strings";
+}
+
+// Print merge stats to stderr.
+
+template<typename Char_type>
+void
+Output_merge_string<Char_type>::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<char>;
+
+template
+class Output_merge_string<uint16_t>;
+
+template
+class Output_merge_string<uint32_t>;
+
+#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<section_offset_type, elfcpp::Elf_types<32>::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<section_offset_type, elfcpp::Elf_types<64>::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 <iant@google.com>.
+
+// 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 <climits>
+#include <map>
+#include <vector>
+
+#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<int size>
+ void
+ initialize_input_to_output_map(
+ unsigned int shndx,
+ typename elfcpp::Elf_types<size>::Elf_Addr starting_address,
+ Unordered_map<section_offset_type,
+ typename elfcpp::Elf_types<size>::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<Input_merge_entry> 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<unsigned int, Input_merge_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<Section_id, Section_id_hash> 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_key, Merge_data_hash, Merge_data_eq>
+ 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<section_offset_type>(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<typename Char_type>
+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_string> 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_list*> Merged_strings_lists;
+
+ // As we see the strings, we add them to a Stringpool.
+ Stringpool_template<Char_type> 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 <iant@google.com>.
+
+ 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 <errno.h>
+#include <string.h>
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#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 <cstdio>
+#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 base_selector, class nacl_target>
+class Target_selector_nacl : public base_selector
+{
+ public:
+ Target_selector_nacl(const char* nacl_abi_name,
+ const char* bfd_name, const char* emulation)
+ : base_selector(), is_nacl_(false), nacl_abi_name_(nacl_abi_name),
+ bfd_name_(bfd_name), emulation_(emulation)
+ { }
+
+ protected:
+ virtual Target*
+ do_instantiate_target()
+ {
+ if (this->is_nacl_)
+ return new nacl_target();
+ return this->base_selector::do_instantiate_target();
+ }
+
+ virtual Target*
+ do_recognize(Input_file* file, off_t offset,
+ int machine, int osabi, int abiversion)
+ {
+ this->is_nacl_ = file != NULL && this->recognize_nacl_file(file, offset);
+ if (this->is_nacl_)
+ return this->instantiate_target();
+ return this->base_selector::do_recognize(file, offset,
+ machine, osabi, abiversion);
+ }
+
+ virtual Target*
+ do_recognize_by_bfd_name(const char* name)
+ {
+ gold_assert(this->bfd_name_ != NULL);
+ this->is_nacl_ = strcmp(name, this->bfd_name_) == 0;
+ if (this->is_nacl_)
+ return this->instantiate_target();
+ return this->base_selector::do_recognize_by_bfd_name(name);
+ }
+
+ virtual void
+ do_supported_bfd_names(std::vector<const char*>* names)
+ {
+ gold_assert(this->bfd_name_ != NULL);
+ this->base_selector::do_supported_bfd_names(names);
+ names->push_back(this->bfd_name_);
+ }
+
+ virtual void
+ do_supported_emulations(std::vector<const char*>* emulations)
+ {
+ gold_assert(this->emulation_ != NULL);
+ this->base_selector::do_supported_emulations(emulations);
+ emulations->push_back(this->emulation_);
+ }
+
+ virtual const char*
+ do_target_bfd_name(const Target* target)
+ {
+ return (!this->is_our_target(target)
+ ? NULL
+ : (this->is_nacl_
+ ? this->bfd_name_
+ : base_selector::do_target_bfd_name(target)));
+ }
+
+ private:
+ bool
+ recognize_nacl_file(Input_file* input_file, off_t offset)
+ {
+ if (this->is_big_endian())
+ {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
+# ifdef HAVE_TARGET_32_BIG
+ if (this->get_size() == 32)
+ return do_recognize_nacl_file<32, true>(input_file, offset);
+# endif
+# ifdef HAVE_TARGET_64_BIG
+ if (this->get_size() == 64)
+ return do_recognize_nacl_file<64, true>(input_file, offset);
+# endif
+#endif
+ gold_unreachable();
+ }
+ else
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
+# ifdef HAVE_TARGET_32_LITTLE
+ if (this->get_size() == 32)
+ return do_recognize_nacl_file<32, false>(input_file, offset);
+# endif
+# ifdef HAVE_TARGET_64_LITTLE
+ if (this->get_size() == 64)
+ return do_recognize_nacl_file<64, false>(input_file, offset);
+# endif
+#endif
+ gold_unreachable();
+ }
+ }
+
+ template<int size, bool big_endian>
+ bool
+ do_recognize_nacl_file(Input_file* input_file, off_t offset)
+ {
+ Sniff_file file(input_file, offset);
+ elfcpp::Elf_file<size, big_endian, Sniff_file> elf_file(&file);
+ const unsigned int shnum = elf_file.shnum();
+ for (unsigned int shndx = 1; shndx < shnum; ++shndx)
+ {
+ if (elf_file.section_type(shndx) == elfcpp::SHT_NOTE)
+ {
+ Sniff_file::Location loc = elf_file.section_contents(shndx);
+ if (loc.size() < (3 * 4
+ + align_address(sizeof "NaCl", 4)
+ + align_address(nacl_abi_name_.size() + 1, 4)))
+ continue;
+ Sniff_file::View view(file.view(loc));
+ const unsigned char* note_data = view.data();
+ if ((elfcpp::Swap<32, big_endian>::readval(note_data + 0)
+ == sizeof "NaCl")
+ && (elfcpp::Swap<32, big_endian>::readval(note_data + 4)
+ == nacl_abi_name_.size() + 1)
+ && (elfcpp::Swap<32, big_endian>::readval(note_data + 8)
+ == elfcpp::NT_VERSION))
+ {
+ const unsigned char* name = note_data + 12;
+ const unsigned char* desc = (name
+ + align_address(sizeof "NaCl", 4));
+ if (memcmp(name, "NaCl", sizeof "NaCl") == 0
+ && memcmp(desc, nacl_abi_name_.c_str(),
+ nacl_abi_name_.size() + 1) == 0)
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // Whether we decided this was the NaCl target variant.
+ bool is_nacl_;
+ // The string found in the NaCl ABI note.
+ std::string nacl_abi_name_;
+ // BFD name of NaCl target, for compatibility.
+ const char* const bfd_name_;
+ // GNU linker emulation for this NaCl target, for compatibility.
+ const char* const emulation_;
+};
+
+} // end namespace gold
+
+#endif // !defined(GOLD_NACL_H)
diff --git a/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 <iant@google.com>.
+
+// 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 <cerrno>
+#include <cstring>
+#include <cstdarg>
+#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<int size, bool big_endian>
+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<size, big_endian>(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<int size, bool big_endian>
+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<size>::shdr_size));
+ typename elfcpp::Shdr<size, big_endian> 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<int size, bool big_endian>
+void
+Object::read_section_data(elfcpp::Elf_file<size, big_endian, Object>* elf_file,
+ Read_symbols_data* sd)
+{
+ const int shdr_size = elfcpp::Elf_sizes<size>::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<size, big_endian> shdrnames(pshdrnames);
+
+ if (shdrnames.get_sh_type() != elfcpp::SHT_STRTAB)
+ this->error(_("section name section has wrong type: %u"),
+ static_cast<unsigned int>(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<const unsigned char*>(warning);
+ len = strlen(warning);
+ }
+ std::string warning(reinterpret_cast<const char*>(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<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::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<int size, bool big_endian>
+uint64_t
+Sized_relobj<size, big_endian>::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<int size, bool big_endian>
+Sized_relobj_file<size, big_endian>::Sized_relobj_file(
+ const std::string& name,
+ Input_file* input_file,
+ off_t offset,
+ const elfcpp::Ehdr<size, big_endian>& ehdr)
+ : Sized_relobj<size, big_endian>(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<int size, bool big_endian>
+Sized_relobj_file<size, big_endian>::~Sized_relobj_file()
+{
+}
+
+// Set up an object file based on the file header. This sets up the
+// section information.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::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<size, big_endian>(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<int size, bool big_endian>
+Xindex*
+Sized_relobj_file<size, big_endian>::do_initialize_xindex()
+{
+ gold_assert(this->symtab_shndx_ != -1U);
+ Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset());
+ xindex->initialize_symtab_xindex<size, big_endian>(this, this->symtab_shndx_);
+ return xindex;
+}
+
+// Return whether SHDR has the right type and flags to be a GNU
+// .eh_frame section.
+
+template<int size, bool big_endian>
+bool
+Sized_relobj_file<size, big_endian>::check_eh_frame_flags(
+ const elfcpp::Shdr<size, big_endian>* 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<int size, bool big_endian>
+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<size>::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<size, big_endian> 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<const char*>(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<size, big_endian> 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<int size, bool big_endian>
+bool
+Sized_relobj_file<size, big_endian>::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<size, big_endian>(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<int size, bool big_endian>
+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<size, big_endian>* obj)
+{
+ Compressed_section_map* uncompressed_map = new Compressed_section_map();
+ const unsigned int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+ const unsigned char* p = pshdrs + shdr_size;
+
+ for (unsigned int i = 1; i < shnum; ++i, p += shdr_size)
+ {
+ typename elfcpp::Shdr<size, big_endian> 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<unsigned long>(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<int size, bool big_endian>
+bool
+Sized_relobj_file<size, big_endian>::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<const char*>(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<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::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<unsigned int>(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<int size, bool big_endian>
+unsigned int
+Sized_relobj_file<size, big_endian>::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<size, big_endian> 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<int size, bool big_endian>
+bool
+Sized_relobj_file<size, big_endian>::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<bool>* 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<const elfcpp::Elf_Word*>(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<size, big_endian> 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<const char*>(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<unsigned int> 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<int size, bool big_endian>
+bool
+Sized_relobj_file<size, big_endian>::include_linkonce_section(
+ Layout* layout,
+ unsigned int index,
+ const char* name,
+ const elfcpp::Shdr<size, big_endian>& shdr)
+{
+ typename elfcpp::Elf_types<size>::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<int size, bool big_endian>
+inline void
+Sized_relobj_file<size, big_endian>::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<Address, off_t>(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<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::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<Address, off_t>(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=<safe,all>): 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<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::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<const char*>(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<unsigned int> reloc_shndx(shnum, 0);
+ std::vector<unsigned int> 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<Address>& 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<bool> 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<unsigned int> reloc_sections;
+
+ // Keep track of .eh_frame sections.
+ std::vector<unsigned int> eh_frame_sections;
+
+ // Keep track of .debug_info and .debug_types sections.
+ std::vector<unsigned int> debug_info_sections;
+ std::vector<unsigned int> 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<unsigned long>(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<Output_section*>(1);
+ out_section_offsets[i] = invalid_address;
+ }
+ else if (should_defer_layout)
+ this->deferred_layout_.push_back(Deferred_layout(i, name,
+ pshdrs,
+ reloc_shndx[i],
+ reloc_type[i]));
+ else
+ eh_frame_sections.push_back(i);
+ continue;
+ }
+
+ 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<Relobj*>(folded.first);
+ gold_info(_("%s: ICF folding section '%s' in file '%s'"
+ "into '%s' in file '%s'"),
+ program_name, this->section_name(i).c_str(),
+ this->name().c_str(),
+ folded_obj->section_name(folded.second).c_str(),
+ folded_obj->name().c_str());
+ }
+ out_sections[i] = NULL;
+ out_section_offsets[i] = invalid_address;
+ continue;
+ }
+ }
+
+ // Defer layout here if input files are claimed by plugins. When gc
+ // is turned on this function is called twice. For the second call
+ // should_defer_layout should be false.
+ if (should_defer_layout && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
+ {
+ gold_assert(!is_pass_two);
+ this->deferred_layout_.push_back(Deferred_layout(i, name,
+ pshdrs,
+ reloc_shndx[i],
+ reloc_type[i]));
+ // Put dummy values here; real values will be supplied by
+ // do_layout_deferred_sections.
+ out_sections[i] = reinterpret_cast<Output_section*>(2);
+ out_section_offsets[i] = invalid_address;
+ continue;
+ }
+
+ // During gc_pass_two if a section that was previously deferred is
+ // found, do not layout the section as layout_deferred_sections will
+ // do it later from gold.cc.
+ if (is_pass_two
+ && (out_sections[i] == reinterpret_cast<Output_section*>(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<Output_section*>(1);
+ out_section_offsets[i] = invalid_address;
+ }
+ else
+ {
+ // When garbage collection is switched on the actual layout
+ // only happens in the second call.
+ this->layout_section(layout, i, name, shdr, reloc_shndx[i],
+ reloc_type[i]);
+
+ // When 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<unsigned int>::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<Output_section*>(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<Output_section*>(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<unsigned int>::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<unsigned int>::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<unsigned int>::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<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::do_layout_deferred_sections(Layout* layout)
+{
+ typename std::vector<Deferred_layout>::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<Address>& 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<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::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<const char*>(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<int size, bool big_endian>
+Archive::Should_include
+Sized_relobj_file<size, big_endian>::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<const char*>(sd->symbol_names->data());
+ const unsigned char* syms =
+ sd->symbols->data() + sd->external_symbols_offset;
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ size_t symcount = ((sd->symbols_size - sd->external_symbols_offset)
+ / sym_size);
+
+ const unsigned char* p = syms;
+
+ for (size_t i = 0; i < symcount; ++i, p += sym_size)
+ {
+ elfcpp::Sym<size, big_endian> 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<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::do_for_all_global_symbols(
+ Read_symbols_data* sd,
+ Library_base::Symbol_visitor_base* v)
+{
+ const char* sym_names =
+ reinterpret_cast<const char*>(sd->symbol_names->data());
+ const unsigned char* syms =
+ sd->symbols->data() + sd->external_symbols_offset;
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ size_t symcount = ((sd->symbols_size - sd->external_symbols_offset)
+ / sym_size);
+ const unsigned char* p = syms;
+
+ for (size_t i = 0; i < symcount; ++i, p += sym_size)
+ {
+ elfcpp::Sym<size, big_endian> 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<int size, bool big_endian>
+bool
+Sized_relobj_file<size, big_endian>::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<int size, bool big_endian>
+unsigned int
+Sized_relobj_file<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::set_local_plt_offset(
+ unsigned int symndx, unsigned int plt_offset)
+{
+ std::pair<typename Local_plt_offsets::iterator, bool> 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<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::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<const char*>(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<size, big_endian> sym(psyms);
+
+ Symbol_value<size>& 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<unsigned int>(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<int size, bool big_endian>
+typename Sized_relobj_file<size, big_endian>::Compute_final_local_value_status
+Sized_relobj_file<size, big_endian>::compute_final_local_value_internal(
+ unsigned int r_sym,
+ const Symbol_value<size>* lv_in,
+ Symbol_value<size>* lv_out,
+ bool relocatable,
+ const Output_sections& out_sections,
+ const std::vector<Address>& 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<size, big_endian>* folded_obj = reinterpret_cast
+ <Sized_relobj_file<size, big_endian>*>(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<size>* msv =
+ new Merged_symbol_value<size>(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<int size, bool big_endian>
+typename Sized_relobj_file<size, big_endian>::Compute_final_local_value_status
+Sized_relobj_file<size, big_endian>::compute_final_local_value(
+ unsigned int r_sym,
+ const Symbol_value<size>* lv_in,
+ Symbol_value<size>* 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<Address>& 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<int size, bool big_endian>
+unsigned int
+Sized_relobj_file<size, big_endian>::do_finalize_local_symbols(
+ unsigned int index,
+ off_t off,
+ Symbol_table* symtab)
+{
+ gold_assert(off == static_cast<off_t>(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<Address>& out_offsets(this->section_offsets());
+
+ for (unsigned int i = 1; i < loccount; ++i)
+ {
+ Symbol_value<size>* 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<int size, bool big_endian>
+unsigned int
+Sized_relobj_file<size, big_endian>::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<size>& 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<int size, bool big_endian>
+unsigned int
+Sized_relobj_file<size, big_endian>::do_set_local_dynsym_offset(off_t off)
+{
+ gold_assert(off == static_cast<off_t>(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<int size, bool big_endian>
+uint64_t
+Sized_relobj_file<size, big_endian>::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<int size, bool big_endian>
+uint64_t
+Sized_relobj_file<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::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<const char*>(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<size, big_endian> isym(psyms);
+
+ Symbol_value<size>& 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<size, big_endian> osym(ov);
+
+ gold_assert(isym.get_st_name() < strtab_size);
+ const char* name = pnames + isym.get_st_name();
+ osym.put_st_name(sympool->get_offset(name));
+ osym.put_st_value(this->local_values_[i].value(this, 0));
+ osym.put_st_size(isym.get_st_size());
+ osym.put_st_info(isym.get_st_info());
+ osym.put_st_other(isym.get_st_other());
+ osym.put_st_shndx(st_shndx);
+
+ ov += sym_size;
+ }
+
+ // Write the symbol to the output dynamic symbol table.
+ if (lv.has_output_dynsym_entry())
+ {
+ gold_assert(dyn_ov < dyn_oview + dyn_output_size);
+ elfcpp::Sym_write<size, big_endian> osym(dyn_ov);
+
+ gold_assert(isym.get_st_name() < strtab_size);
+ const char* name = pnames + isym.get_st_name();
+ osym.put_st_name(dynpool->get_offset(name));
+ osym.put_st_value(this->local_values_[i].value(this, 0));
+ osym.put_st_size(isym.get_st_size());
+ osym.put_st_info(isym.get_st_info());
+ osym.put_st_other(isym.get_st_other());
+ osym.put_st_shndx(st_shndx);
+
+ dyn_ov += sym_size;
+ }
+ }
+
+
+ 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<int size, bool big_endian>
+bool
+Sized_relobj_file<size, big_endian>::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<const char*>(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<size, big_endian> 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<off_t>(sym.get_st_value()) <= offset
+ && (static_cast<off_t>(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<int size, bool big_endian>
+typename Sized_relobj_file<size, big_endian>::Address
+Sized_relobj_file<size, big_endian>::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<size, big_endian>* kept_relobj =
+ static_cast<Sized_relobj_file<size, big_endian>*>(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<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::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<int size, bool big_endian>
+const unsigned char*
+Sized_relobj_file<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::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<Relobj*>(obj));
+ else
+ {
+ // See if this is a duplicate SONAME.
+ Dynobj* dynobj = static_cast<Dynobj*>(obj);
+ const char* soname = dynobj->soname();
+
+ std::pair<Unordered_set<std::string>::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<int size, bool big_endian>
+std::string
+Relocate_info<size, big_endian>::location(size_t, off_t offset) const
+{
+ Sized_dwarf_line_info<size, big_endian> 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<long>(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<int size, bool big_endian>
+Object*
+make_elf_sized_object(const std::string& name, Input_file* input_file,
+ off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr,
+ bool* punconfigured)
+{
+ Target* target = select_target(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 != &parameters->target())
+ {
+ if (punconfigured != NULL)
+ *punconfigured = true;
+ else
+ gold_error(_("%s: incompatible target"), name.c_str());
+ return NULL;
+ }
+
+ return target->make_elf_object<size, big_endian>(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 <iant@google.com>.
+
+// 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 <string>
+#include <vector>
+
+#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<typename Stringpool_char>
+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<Section_relocs> 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<int size, bool big_endian>
+ 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<int size, bool big_endian>
+ 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<unsigned int> 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<Symbol*> 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<int size, bool big_endian>
+ void
+ read_section_data(elfcpp::Elf_file<size, big_endian, Object>*,
+ 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<int size, bool big_endian>
+ 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<char>* pool,
+ Stringpool_template<char>* 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_section*> 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<char>*,
+ Stringpool_template<char>*) = 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<Relocatable_relocs*>(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<Relocatable_relocs*>* 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<int size>
+class Merged_symbol_value
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Value;
+
+ // We use a hash table to map offsets in the input section to output
+ // addresses.
+ typedef Unordered_map<section_offset_type, Value> 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<int size>
+class Symbol_value
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::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<bool big_endian>
+ Value
+ value(const Sized_relobj_file<size, big_endian>* 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<size>* 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<size>* 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<size>* 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<Symbol*> 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<unsigned int, Compressed_section_info> 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<int size, bool big_endian>
+class Sized_relobj : public Relobj
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef Relobj::Symbols Symbols;
+
+ static const Address invalid_address = static_cast<Address>(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<size, big_endian>*
+ sized_relobj()
+ { return NULL; }
+
+ const virtual Sized_relobj_file<size, big_endian>*
+ 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<Address>&
+ 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<uint64_t>(-1)
+ ? invalid_address
+ : convert_types<Address, uint64_t>(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<Local_got_offsets::iterator, bool> 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<unsigned int, Got_offset_list*> 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<Address> section_offsets_;
+};
+
+// A regular object file. This is size and endian specific.
+
+template<int size, bool big_endian>
+class Sized_relobj_file : public Sized_relobj<size, big_endian>
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename Sized_relobj<size, big_endian>::Symbols Symbols;
+ typedef std::vector<Symbol_value<size> > Local_values;
+
+ static const Address invalid_address = static_cast<Address>(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<size, big_endian>&);
+
+ ~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<size, big_endian>*
+ sized_relobj()
+ { return this; }
+
+ const Sized_relobj_file<size, big_endian>*
+ 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<size>*
+ 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<size>* 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<size>* lv_in,
+ Symbol_value<size>* lv_out,
+ const Symbol_table* symtab);
+
+ protected:
+ typedef typename Sized_relobj<size, big_endian>::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<size>* 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<char>*,
+ Stringpool_template<char>*);
+
+ // 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<size, big_endian, Object>*
+ 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<size>::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<View_size> 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<size>*) 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<size, big_endian> This;
+ static const int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size;
+ static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+ static const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ typedef elfcpp::Shdr<size, big_endian> 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<unsigned int, Kept_comdat_section>
+ 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<size, big_endian>* 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<bool>*);
+
+ // Whether to include a linkonce section in the link.
+ bool
+ include_linkonce_section(Layout*, unsigned int, const char*,
+ const elfcpp::Shdr<size, big_endian>&);
+
+ // 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<int sh_type>
+ 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<int sh_type>
+ void
+ incremental_relocs_scan_reltype(
+ const Read_relocs_data::Relocs_list::iterator&);
+
+ void
+ incremental_relocs_write(const Relocate_info<size, big_endian>*,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section*,
+ Address output_offset,
+ Output_file*);
+
+ template<int sh_type>
+ void
+ incremental_relocs_write_reltype(const Relocate_info<size, big_endian>*,
+ 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<section_offset_type, section_size_type> 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<int sh_type>
+ 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<char>*,
+ const Stringpool_template<char>*,
+ 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<size>* lv_in,
+ Symbol_value<size>* lv_out,
+ bool relocatable,
+ const Output_sections& out_sections,
+ const std::vector<Address>& out_offsets,
+ const Symbol_table* symtab);
+
+ // The PLT offsets of local symbols.
+ typedef Unordered_map<unsigned int, unsigned int> Local_plt_offsets;
+
+ // Saved information for sections whose layout was deferred.
+ struct Deferred_layout
+ {
+ static const int shdr_size = elfcpp::Elf_sizes<size>::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<size, big_endian, Object> 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> deferred_layout_;
+ // The list of relocation sections whose layout was deferred.
+ std::vector<Deferred_layout> 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*> Relobj_list;
+ typedef Relobj_list::const_iterator Relobj_iterator;
+
+ // The type of the list of input dynamic objects.
+ typedef std::vector<Dynobj*> 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<std::string> 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<int size, bool big_endian>
+struct Relocate_info
+{
+ // Symbol table.
+ const Symbol_table* symtab;
+ // Layout.
+ const Layout* layout;
+ // Object being relocated.
+ Sized_relobj_file<size, big_endian>* 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<Object*, unsigned int> Section_id;
+
+// This is similar to Section_id but is used when the section
+// pointers are const.
+typedef std::pair<const Object*, unsigned int> 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<uintptr_t>(loc.first) ^ loc.second; }
+};
+
+struct Const_section_id_hash
+{
+ size_t operator()(const Const_section_id& loc) const
+ { return reinterpret_cast<uintptr_t>(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 <iant@google.com>.
+
+// 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 <cerrno>
+#include <cstdlib>
+#include <cstring>
+#include <fstream>
+#include <vector>
+#include <iostream>
+#include <sys/stat.h>
+#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<const One_option*> 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<std::string, One_option*> 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<int>(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 One_option*>::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<const char*> supported_names;
+ gold::supported_target_names(&supported_names);
+ for (std::vector<const char*>::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 char*>::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<const char*> supported_names;
+ gold::supported_target_names(&supported_names);
+ for (std::vector<const char*>::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 char*>::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<std::string, uint64_t>::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<std::string>::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
+// <-|--><option>[=arg]. If "=arg" is not present but the option
+// takes an argument, the next word is taken to the be the argument.
+// If equals_only is set, then only the <option>=<arg> form is
+// accepted, not the <option><space><arg> form. Returns a One_option
+// struct or NULL if argv[i] cannot be parsed as a long option. In
+// the not-NULL case, *arg is set to the option's argument (NULL if
+// the option takes no argument), and *i is advanced past this option.
+// NOTE: it is safe for argv and arg to point to the same place.
+gold::options::One_option*
+parse_long_option(int argc, const char** argv, bool equals_only,
+ const char** arg, int* i)
+{
+ const char* const this_argv = argv[*i];
+
+ const char* equals = strchr(this_argv, '=');
+ const char* option_start = this_argv + strspn(this_argv, "-");
+ std::string option(option_start,
+ equals ? equals - option_start : strlen(option_start));
+
+ gold::options::Option_map::iterator it
+ = gold::options::long_options->find(option);
+ if (it == gold::options::long_options->end())
+ return NULL;
+
+ gold::options::One_option* retval = it->second;
+
+ // If the dash-count doesn't match, we fail.
+ if (this_argv[0] != '-') // no dashes at all: had better be "-z <longopt>"
+ {
+ if (retval->dashes != gold::options::DASH_Z)
+ return NULL;
+ }
+ else if (this_argv[1] != '-') // one dash
+ {
+ if (retval->dashes != gold::options::ONE_DASH
+ && retval->dashes != gold::options::EXACTLY_ONE_DASH
+ && retval->dashes != gold::options::TWO_DASHES)
+ return NULL;
+ }
+ else // two dashes (or more!)
+ {
+ if (retval->dashes != gold::options::TWO_DASHES
+ && retval->dashes != gold::options::EXACTLY_TWO_DASHES
+ && retval->dashes != gold::options::ONE_DASH)
+ return NULL;
+ }
+
+ // Now that we know the option is good (or else bad in a way that
+ // will cause us to die), increment i to point past this argv.
+ ++(*i);
+
+ // Figure out the option's argument, if any.
+ if (!retval->takes_argument())
+ {
+ if (equals)
+ usage(_("unexpected argument"), this_argv);
+ else
+ *arg = NULL;
+ }
+ else
+ {
+ if (equals)
+ *arg = equals + 1;
+ else if (retval->takes_optional_argument())
+ *arg = retval->default_value;
+ else if (*i < argc && !equals_only)
+ *arg = argv[(*i)++];
+ else
+ usage(_("missing argument"), this_argv);
+ }
+
+ return retval;
+}
+
+// Parse a short option. Such options have the form -<option>[arg].
+// If "arg" is not present but the option takes an argument, the next
+// word is taken to the be the argument. If the option does not take
+// an argument, it may be followed by another short option. Returns a
+// One_option struct or NULL if argv[i] cannot be parsed as a short
+// option. In the not-NULL case, *arg is set to the option's argument
+// (NULL if the option takes no argument), and *i is advanced past
+// this option. This function keeps *i the same if we parsed a short
+// option that does not take an argument, that looks to be followed by
+// another short option in the same word.
+gold::options::One_option*
+parse_short_option(int argc, const char** argv, int pos_in_argv_i,
+ const char** arg, int* i)
+{
+ const char* const this_argv = argv[*i];
+
+ if (this_argv[0] != '-')
+ return NULL;
+
+ // We handle -z as a special case.
+ static gold::options::One_option dash_z("", gold::options::DASH_Z,
+ 'z', "", NULL, "Z-OPTION", false,
+ NULL);
+ gold::options::One_option* retval = NULL;
+ if (this_argv[pos_in_argv_i] == 'z')
+ retval = &dash_z;
+ else
+ {
+ const int char_as_int = static_cast<int>(this_argv[pos_in_argv_i]);
+ if (char_as_int > 0 && char_as_int < 128)
+ retval = gold::options::short_options[char_as_int];
+ }
+
+ if (retval == NULL)
+ return NULL;
+
+ // Figure out the option's argument, if any.
+ if (!retval->takes_argument())
+ {
+ *arg = NULL;
+ // We only advance past this argument if it's the only one in argv.
+ if (this_argv[pos_in_argv_i + 1] == '\0')
+ ++(*i);
+ }
+ else
+ {
+ // If we take an argument, we'll eat up this entire argv entry.
+ ++(*i);
+ if (this_argv[pos_in_argv_i + 1] != '\0')
+ *arg = this_argv + pos_in_argv_i + 1;
+ else if (retval->takes_optional_argument())
+ *arg = retval->default_value;
+ else if (*i < argc)
+ *arg = argv[(*i)++];
+ else
+ usage(_("missing argument"), this_argv);
+ }
+
+ // If we're a -z option, we need to parse our argument as a
+ // long-option, e.g. "-z stacksize=8192".
+ if (retval == &dash_z)
+ {
+ int dummy_i = 0;
+ const char* dash_z_arg = *arg;
+ retval = parse_long_option(1, arg, true, arg, &dummy_i);
+ if (retval == NULL)
+ usage(_("unknown -z option"), dash_z_arg);
+ }
+
+ return retval;
+}
+
+} // End anonymous namespace.
+
+namespace gold
+{
+
+General_options::General_options()
+ : printed_version_(false),
+ execstack_status_(EXECSTACK_FROM_INPUT),
+ icf_status_(ICF_NONE),
+ static_(false),
+ do_demangle_(false),
+ plugins_(NULL),
+ dynamic_list_(),
+ incremental_mode_(INCREMENTAL_OFF),
+ incremental_disposition_(INCREMENTAL_STARTUP),
+ incremental_startup_disposition_(INCREMENTAL_CHECK),
+ implicit_incremental_(false),
+ excluded_libs_(),
+ symbols_to_retain_(),
+ section_starts_(),
+ fix_v4bx_(FIX_V4BX_NONE),
+ endianness_(ENDIANNESS_NOT_SET)
+{
+ // Turn off option registration once construction is complete.
+ gold::options::ready_to_register = false;
+}
+
+General_options::Object_format
+General_options::format_enum() const
+{
+ return General_options::string_to_object_format(this->format());
+}
+
+General_options::Object_format
+General_options::oformat_enum() const
+{
+ return General_options::string_to_object_format(this->oformat());
+}
+
+// Add the sysroot, if any, to the search paths.
+
+void
+General_options::add_sysroot()
+{
+ if (this->sysroot() == NULL || this->sysroot()[0] == '\0')
+ {
+ this->set_sysroot(get_default_sysroot());
+ if (this->sysroot() == NULL || this->sysroot()[0] == '\0')
+ return;
+ }
+
+ char* canonical_sysroot = lrealpath(this->sysroot());
+
+ for (Dir_list::iterator p = this->library_path_.value.begin();
+ p != this->library_path_.value.end();
+ ++p)
+ p->add_sysroot(this->sysroot(), canonical_sysroot);
+
+ free(canonical_sysroot);
+}
+
+// Return whether FILENAME is in a system directory.
+
+bool
+General_options::is_in_system_directory(const std::string& filename) const
+{
+ for (Dir_list::const_iterator p = this->library_path_.value.begin();
+ p != this->library_path_.value.end();
+ ++p)
+ {
+ // We use a straight string comparison rather than calling
+ // FILENAME_CMP because we are only interested in the cases
+ // where we found the file in a system directory, which means
+ // that we used the directory name as a prefix for a -L search.
+ if (p->is_system_directory()
+ && filename.compare(0, p->name().size(), p->name()) == 0)
+ return true;
+ }
+ return false;
+}
+
+// Add a plugin to the list of plugins.
+
+void
+General_options::add_plugin(const char* filename)
+{
+ if (this->plugins_ == NULL)
+ this->plugins_ = new Plugin_manager(*this);
+ this->plugins_->add_plugin(filename);
+}
+
+// Add a plugin option to a plugin.
+
+void
+General_options::add_plugin_option(const char* arg)
+{
+ if (this->plugins_ == NULL)
+ gold_fatal("--plugin-opt requires --plugin.");
+ this->plugins_->add_plugin_option(arg);
+}
+
+// Set up variables and other state that isn't set up automatically by
+// the parse routine, and ensure options don't contradict each other
+// and are otherwise kosher.
+
+void
+General_options::finalize()
+{
+ // Normalize the strip modifiers. They have a total order:
+ // strip_all > strip_debug > strip_non_line > strip_debug_gdb.
+ // If one is true, set all beneath it to true as well.
+ if (this->strip_all())
+ this->set_strip_debug(true);
+ if (this->strip_debug())
+ this->set_strip_debug_non_line(true);
+ if (this->strip_debug_non_line())
+ this->set_strip_debug_gdb(true);
+
+ if (this->Bshareable())
+ this->set_shared(true);
+
+ // If the user specifies both -s and -r, convert the -s to -S.
+ // -r requires us to keep externally visible symbols!
+ if (this->strip_all() && this->relocatable())
+ {
+ this->set_strip_all(false);
+ gold_assert(this->strip_debug());
+ }
+
+ // For us, -dc and -dp are synonyms for --define-common.
+ if (this->dc())
+ this->set_define_common(true);
+ if (this->dp())
+ this->set_define_common(true);
+
+ // We also set --define-common if we're not relocatable, as long as
+ // the user didn't explicitly ask for something different.
+ if (!this->user_set_define_common())
+ this->set_define_common(!this->relocatable());
+
+ // execstack_status_ is a three-state variable; update it based on
+ // -z [no]execstack.
+ if (this->execstack())
+ this->set_execstack_status(EXECSTACK_YES);
+ else if (this->noexecstack())
+ this->set_execstack_status(EXECSTACK_NO);
+
+ // icf_status_ is a three-state variable; update it based on the
+ // value of this->icf().
+ if (strcmp(this->icf(), "none") == 0)
+ this->set_icf_status(ICF_NONE);
+ else if (strcmp(this->icf(), "safe") == 0)
+ this->set_icf_status(ICF_SAFE);
+ else
+ this->set_icf_status(ICF_ALL);
+
+ // Handle the optional argument for --demangle.
+ if (this->user_set_demangle())
+ {
+ this->set_do_demangle(true);
+ const char* style = this->demangle();
+ if (*style != '\0')
+ {
+ enum demangling_styles style_code;
+
+ style_code = cplus_demangle_name_to_style(style);
+ if (style_code == unknown_demangling)
+ gold_fatal("unknown demangling style '%s'", style);
+ cplus_demangle_set_style(style_code);
+ }
+ }
+ else if (this->user_set_no_demangle())
+ this->set_do_demangle(false);
+ else
+ {
+ // Testing COLLECT_NO_DEMANGLE makes our default demangling
+ // behaviour identical to that of gcc's linker wrapper.
+ this->set_do_demangle(getenv("COLLECT_NO_DEMANGLE") == NULL);
+ }
+
+ // -M is equivalent to "-Map -".
+ if (this->print_map() && !this->user_set_Map())
+ {
+ this->set_Map("-");
+ this->set_user_set_Map();
+ }
+
+ // Using -n or -N implies -static.
+ if (this->nmagic() || this->omagic())
+ this->set_static(true);
+
+ // If --thread_count is specified, it applies to
+ // --thread-count-{initial,middle,final}, though it doesn't override
+ // them.
+ if (this->thread_count() > 0 && this->thread_count_initial() == 0)
+ this->set_thread_count_initial(this->thread_count());
+ if (this->thread_count() > 0 && this->thread_count_middle() == 0)
+ this->set_thread_count_middle(this->thread_count());
+ if (this->thread_count() > 0 && this->thread_count_final() == 0)
+ this->set_thread_count_final(this->thread_count());
+
+ // Let's warn if you set the thread-count but we're going to ignore it.
+#ifndef ENABLE_THREADS
+ if (this->threads())
+ {
+ gold_warning(_("ignoring --threads: "
+ "%s was compiled without thread support"),
+ program_name);
+ this->set_threads(false);
+ }
+ if (this->thread_count() > 0 || this->thread_count_initial() > 0
+ || this->thread_count_middle() > 0 || this->thread_count_final() > 0)
+ gold_warning(_("ignoring --thread-count: "
+ "%s was compiled without thread support"),
+ program_name);
+#endif
+
+ std::string libpath;
+ if (this->user_set_Y())
+ {
+ libpath = this->Y();
+ if (libpath.compare(0, 2, "P,") == 0)
+ libpath.erase(0, 2);
+ }
+ else if (!this->nostdlib())
+ {
+#ifndef NATIVE_LINKER
+#define NATIVE_LINKER 0
+#endif
+ const char* p = LIB_PATH;
+ if (strcmp(p, "::DEFAULT::") != 0)
+ libpath = p;
+ else if (NATIVE_LINKER
+ || this->user_set_sysroot()
+ || *TARGET_SYSTEM_ROOT != '\0')
+ {
+ this->add_to_library_path_with_sysroot("/lib");
+ this->add_to_library_path_with_sysroot("/usr/lib");
+ }
+ else
+ this->add_to_library_path_with_sysroot(TOOLLIBDIR);
+ }
+
+ if (!libpath.empty())
+ {
+ size_t pos = 0;
+ size_t next_pos;
+ do
+ {
+ next_pos = libpath.find(':', pos);
+ size_t len = (next_pos == std::string::npos
+ ? next_pos
+ : next_pos - pos);
+ if (len != 0)
+ this->add_to_library_path_with_sysroot(libpath.substr(pos, len));
+ pos = next_pos + 1;
+ }
+ while (next_pos != std::string::npos);
+ }
+
+ // Parse the contents of -retain-symbols-file into a set.
+ if (this->retain_symbols_file())
+ {
+ std::ifstream in;
+ in.open(this->retain_symbols_file());
+ if (!in)
+ gold_fatal(_("unable to open -retain-symbols-file file %s: %s"),
+ this->retain_symbols_file(), strerror(errno));
+ std::string line;
+ std::getline(in, line); // this chops off the trailing \n, if any
+ while (in)
+ {
+ if (!line.empty() && line[line.length() - 1] == '\r') // Windows
+ line.resize(line.length() - 1);
+ this->symbols_to_retain_.insert(line);
+ std::getline(in, line);
+ }
+ }
+
+ // -Bgroup implies --unresolved-symbols=report-all.
+ if (this->Bgroup() && !this->user_set_unresolved_symbols())
+ this->set_unresolved_symbols("report-all");
+
+ // -shared implies --allow-shlib-undefined. Currently
+ // ---allow-shlib-undefined controls warnings issued based on the
+ // -symbol table. --unresolved-symbols controls warnings issued
+ // -based on relocations.
+ if (this->shared() && !this->user_set_allow_shlib_undefined())
+ this->set_allow_shlib_undefined(true);
+
+ // Normalize library_path() by adding the sysroot to all directories
+ // in the path, as appropriate.
+ this->add_sysroot();
+
+ // Now that we've normalized the options, check for contradictory ones.
+ if (this->shared() && this->is_static())
+ gold_fatal(_("-shared and -static are incompatible"));
+ if (this->shared() && this->pie())
+ gold_fatal(_("-shared and -pie are incompatible"));
+ if (this->pie() && this->is_static())
+ gold_fatal(_("-pie and -static are incompatible"));
+
+ if (this->shared() && this->relocatable())
+ gold_fatal(_("-shared and -r are incompatible"));
+ if (this->pie() && this->relocatable())
+ gold_fatal(_("-pie and -r are incompatible"));
+
+ if (!this->shared())
+ {
+ if (this->filter() != NULL)
+ gold_fatal(_("-F/--filter may not used without -shared"));
+ if (this->any_auxiliary())
+ gold_fatal(_("-f/--auxiliary may not be used without -shared"));
+ }
+
+ // TODO: implement support for -retain-symbols-file with -r, if needed.
+ if (this->relocatable() && this->retain_symbols_file())
+ gold_fatal(_("-retain-symbols-file does not yet work with -r"));
+
+ if (this->oformat_enum() != General_options::OBJECT_FORMAT_ELF
+ && (this->shared()
+ || this->pie()
+ || this->relocatable()))
+ gold_fatal(_("binary output format not compatible "
+ "with -shared or -pie or -r"));
+
+ if (this->user_set_hash_bucket_empty_fraction()
+ && (this->hash_bucket_empty_fraction() < 0.0
+ || this->hash_bucket_empty_fraction() >= 1.0))
+ gold_fatal(_("--hash-bucket-empty-fraction value %g out of range "
+ "[0.0, 1.0)"),
+ this->hash_bucket_empty_fraction());
+
+ if (this->implicit_incremental_ && this->incremental_mode_ == INCREMENTAL_OFF)
+ gold_fatal(_("Options --incremental-changed, --incremental-unchanged, "
+ "--incremental-unknown require the use of --incremental"));
+
+ // Check for options that are not compatible with incremental linking.
+ // Where an option can be disabled without seriously changing the semantics
+ // of the link, we turn the option off; otherwise, we issue a fatal error.
+
+ if (this->incremental_mode_ != INCREMENTAL_OFF)
+ {
+ if (this->relocatable())
+ gold_fatal(_("incremental linking is not compatible with -r"));
+ if (this->emit_relocs())
+ gold_fatal(_("incremental linking is not compatible with "
+ "--emit-relocs"));
+ if (this->has_plugins())
+ gold_fatal(_("incremental linking is not compatible with --plugin"));
+ if (this->gc_sections())
+ {
+ gold_warning(_("ignoring --gc-sections for an incremental link"));
+ this->set_gc_sections(false);
+ }
+ if (this->icf_enabled())
+ {
+ gold_warning(_("ignoring --icf for an incremental link"));
+ this->set_icf_status(ICF_NONE);
+ }
+ if (strcmp(this->compress_debug_sections(), "none") != 0)
+ {
+ gold_warning(_("ignoring --compress-debug-sections for an "
+ "incremental link"));
+ this->set_compress_debug_sections("none");
+ }
+ }
+
+ // --rosegment-gap implies --rosegment.
+ if (this->user_set_rosegment_gap())
+ this->set_rosegment(true);
+
+ // FIXME: we can/should be doing a lot more sanity checking here.
+}
+
+// Search_directory methods.
+
+// This is called if we have a sysroot. Apply the sysroot if
+// appropriate. Record whether the directory is in the sysroot.
+
+void
+Search_directory::add_sysroot(const char* sysroot,
+ const char* canonical_sysroot)
+{
+ gold_assert(*sysroot != '\0');
+ if (this->put_in_sysroot_)
+ {
+ if (!IS_DIR_SEPARATOR(this->name_[0])
+ && !IS_DIR_SEPARATOR(sysroot[strlen(sysroot) - 1]))
+ this->name_ = '/' + this->name_;
+ this->name_ = sysroot + this->name_;
+ this->is_in_sysroot_ = true;
+ }
+ else
+ {
+ // Check whether this entry is in the sysroot. To do this
+ // correctly, we need to use canonical names. Otherwise we will
+ // get confused by the ../../.. paths that gcc tends to use.
+ char* canonical_name = lrealpath(this->name_.c_str());
+ int canonical_name_len = strlen(canonical_name);
+ int canonical_sysroot_len = strlen(canonical_sysroot);
+ if (canonical_name_len > canonical_sysroot_len
+ && IS_DIR_SEPARATOR(canonical_name[canonical_sysroot_len]))
+ {
+ canonical_name[canonical_sysroot_len] = '\0';
+ if (FILENAME_CMP(canonical_name, canonical_sysroot) == 0)
+ this->is_in_sysroot_ = true;
+ }
+ free(canonical_name);
+ }
+}
+
+// Input_arguments methods.
+
+// Add a file to the list.
+
+Input_argument&
+Input_arguments::add_file(Input_file_argument& file)
+{
+ file.set_arg_serial(++this->file_count_);
+ if (this->in_group_)
+ {
+ gold_assert(!this->input_argument_list_.empty());
+ gold_assert(this->input_argument_list_.back().is_group());
+ return this->input_argument_list_.back().group()->add_file(file);
+ }
+ if (this->in_lib_)
+ {
+ gold_assert(!this->input_argument_list_.empty());
+ gold_assert(this->input_argument_list_.back().is_lib());
+ return this->input_argument_list_.back().lib()->add_file(file);
+ }
+ this->input_argument_list_.push_back(Input_argument(file));
+ return this->input_argument_list_.back();
+}
+
+// Start a group.
+
+void
+Input_arguments::start_group()
+{
+ if (this->in_group_)
+ gold_fatal(_("May not nest groups"));
+ if (this->in_lib_)
+ gold_fatal(_("may not nest groups in libraries"));
+ Input_file_group* group = new Input_file_group();
+ this->input_argument_list_.push_back(Input_argument(group));
+ this->in_group_ = true;
+}
+
+// End a group.
+
+void
+Input_arguments::end_group()
+{
+ if (!this->in_group_)
+ gold_fatal(_("Group end without group start"));
+ this->in_group_ = false;
+}
+
+// Start a lib.
+
+void
+Input_arguments::start_lib(const Position_dependent_options& options)
+{
+ if (this->in_lib_)
+ gold_fatal(_("may not nest libraries"));
+ if (this->in_group_)
+ gold_fatal(_("may not nest libraries in groups"));
+ Input_file_lib* lib = new Input_file_lib(options);
+ this->input_argument_list_.push_back(Input_argument(lib));
+ this->in_lib_ = true;
+}
+
+// End a lib.
+
+void
+Input_arguments::end_lib()
+{
+ if (!this->in_lib_)
+ gold_fatal(_("lib end without lib start"));
+ this->in_lib_ = false;
+}
+
+// Command_line options.
+
+Command_line::Command_line()
+{
+}
+
+// Pre_options is the hook that sets the ready_to_register flag.
+
+Command_line::Pre_options::Pre_options()
+{
+ gold::options::ready_to_register = true;
+}
+
+// Process the command line options. For process_one_option, i is the
+// index of argv to process next, and must be an option (that is,
+// start with a dash). The return value is the index of the next
+// option to process (i+1 or i+2, or argc to indicate processing is
+// done). no_more_options is set to true if (and when) "--" is seen
+// as an option.
+
+int
+Command_line::process_one_option(int argc, const char** argv, int i,
+ bool* no_more_options)
+{
+ gold_assert(argv[i][0] == '-' && !(*no_more_options));
+
+ // If we are reading "--", then just set no_more_options and return.
+ if (argv[i][1] == '-' && argv[i][2] == '\0')
+ {
+ *no_more_options = true;
+ return i + 1;
+ }
+
+ int new_i = i;
+ options::One_option* option = NULL;
+ const char* arg = NULL;
+
+ // First, try to process argv as a long option.
+ option = parse_long_option(argc, argv, false, &arg, &new_i);
+ if (option)
+ {
+ option->reader->parse_to_value(argv[i], arg, this, &this->options_);
+ return new_i;
+ }
+
+ // Now, try to process argv as a short option. Since several short
+ // options can be combined in one argv, we may have to parse a lot
+ // until we're done reading this argv.
+ int pos_in_argv_i = 1;
+ while (new_i == i)
+ {
+ option = parse_short_option(argc, argv, pos_in_argv_i, &arg, &new_i);
+ if (!option)
+ break;
+ option->reader->parse_to_value(argv[i], arg, this, &this->options_);
+ ++pos_in_argv_i;
+ }
+ if (option)
+ return new_i;
+
+ // I guess it's neither a long option nor a short option.
+ usage(_("unknown option"), argv[i]);
+ return argc;
+}
+
+
+void
+Command_line::process(int argc, const char** argv)
+{
+ bool no_more_options = false;
+ int i = 0;
+ while (i < argc)
+ {
+ this->position_options_.copy_from_options(this->options());
+ if (no_more_options || argv[i][0] != '-')
+ {
+ Input_file_argument file(argv[i],
+ Input_file_argument::INPUT_FILE_TYPE_FILE,
+ "", false, this->position_options_);
+ this->inputs_.add_file(file);
+ ++i;
+ }
+ else
+ i = process_one_option(argc, argv, i, &no_more_options);
+ }
+
+ if (this->inputs_.in_group())
+ {
+ fprintf(stderr, _("%s: missing group end\n"), program_name);
+ usage();
+ }
+
+ // Normalize the options and ensure they don't contradict each other.
+ this->options_.finalize();
+}
+
+// Finalize the version script options and return them.
+
+const Version_script_info&
+Command_line::version_script()
+{
+ this->options_.finalize_dynamic_list();
+ Version_script_info* vsi = this->script_options_.version_script_info();
+ vsi->finalize();
+ return *vsi;
+}
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/options.h b/binutils-2.25/gold/options.h
new file mode 100644
index 00000000..a2f5a886
--- /dev/null
+++ b/binutils-2.25/gold/options.h
@@ -0,0 +1,2117 @@
+// options.h -- handle command line options for gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2013
+// Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+// General_options (from Command_line::options())
+// All the options (a.k.a. command-line flags)
+// Input_argument (from Command_line::inputs())
+// The list of input files, including -l options.
+// Command_line
+// Everything we get from the command line -- the General_options
+// plus the Input_arguments.
+//
+// There are also some smaller classes, such as
+// Position_dependent_options which hold a subset of General_options
+// that change as options are parsed (as opposed to the usual behavior
+// of the last instance of that option specified on the commandline wins).
+
+#ifndef GOLD_OPTIONS_H
+#define GOLD_OPTIONS_H
+
+#include <cstdlib>
+#include <cstring>
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "elfcpp.h"
+#include "script.h"
+
+namespace gold
+{
+
+class Command_line;
+class General_options;
+class Search_directory;
+class Input_file_group;
+class Input_file_lib;
+class Position_dependent_options;
+class Target;
+class Plugin_manager;
+class Script_info;
+
+// Incremental build action for a specific file, as selected by the user.
+
+enum Incremental_disposition
+{
+ // Startup files that appear before the first disposition option.
+ // These will default to INCREMENTAL_CHECK unless the
+ // --incremental-startup-unchanged option is given.
+ // (For files added implicitly by gcc before any user options.)
+ INCREMENTAL_STARTUP,
+ // Determine the status from the timestamp (default).
+ INCREMENTAL_CHECK,
+ // Assume the file changed from the previous build.
+ INCREMENTAL_CHANGED,
+ // Assume the file didn't change from the previous build.
+ INCREMENTAL_UNCHANGED
+};
+
+// The nested namespace is to contain all the global variables and
+// structs that need to be defined in the .h file, but do not need to
+// be used outside this class.
+namespace options
+{
+typedef std::vector<Search_directory> Dir_list;
+typedef Unordered_set<std::string> String_set;
+
+// These routines convert from a string option to various types.
+// Each gives a fatal error if it cannot parse the argument.
+
+extern void
+parse_bool(const char* option_name, const char* arg, bool* retval);
+
+extern void
+parse_int(const char* option_name, const char* arg, int* retval);
+
+extern void
+parse_uint(const char* option_name, const char* arg, int* retval);
+
+extern void
+parse_uint64(const char* option_name, const char* arg, uint64_t* retval);
+
+extern void
+parse_double(const char* option_name, const char* arg, double* retval);
+
+extern void
+parse_percent(const char* option_name, const char* arg, double* retval);
+
+extern void
+parse_string(const char* option_name, const char* arg, const char** retval);
+
+extern void
+parse_optional_string(const char* option_name, const char* arg,
+ const char** retval);
+
+extern void
+parse_dirlist(const char* option_name, const char* arg, Dir_list* retval);
+
+extern void
+parse_set(const char* option_name, const char* arg, String_set* retval);
+
+extern void
+parse_choices(const char* option_name, const char* arg, const char** retval,
+ const char* choices[], int num_choices);
+
+struct Struct_var;
+
+// Most options have both a shortname (one letter) and a longname.
+// This enum controls how many dashes are expected for longname access
+// -- shortnames always use one dash. Most longnames will accept
+// either one dash or two; the only difference between ONE_DASH and
+// TWO_DASHES is how we print the option in --help. However, some
+// longnames require two dashes, and some require only one. The
+// special value DASH_Z means that the option is preceded by "-z".
+enum Dashes
+{
+ ONE_DASH, TWO_DASHES, EXACTLY_ONE_DASH, EXACTLY_TWO_DASHES, DASH_Z
+};
+
+// LONGNAME is the long-name of the option with dashes converted to
+// underscores, or else the short-name if the option has no long-name.
+// It is never the empty string.
+// DASHES is an instance of the Dashes enum: ONE_DASH, TWO_DASHES, etc.
+// SHORTNAME is the short-name of the option, as a char, or '\0' if the
+// option has no short-name. If the option has no long-name, you
+// should specify the short-name in *both* VARNAME and here.
+// DEFAULT_VALUE is the value of the option if not specified on the
+// commandline, as a string.
+// HELPSTRING is the descriptive text used with the option via --help
+// HELPARG is how you define the argument to the option.
+// --help output is "-shortname HELPARG, --longname HELPARG: HELPSTRING"
+// HELPARG should be NULL iff the option is a bool and takes no arg.
+// OPTIONAL_ARG is true if this option takes an optional argument. An
+// optional argument must be specifid as --OPTION=VALUE, not
+// --OPTION VALUE.
+// READER provides parse_to_value, which is a function that will convert
+// a char* argument into the proper type and store it in some variable.
+// A One_option struct initializes itself with the global list of options
+// at constructor time, so be careful making one of these.
+struct One_option
+{
+ std::string longname;
+ Dashes dashes;
+ char shortname;
+ const char* default_value;
+ const char* helpstring;
+ const char* helparg;
+ bool optional_arg;
+ Struct_var* reader;
+
+ One_option(const char* ln, Dashes d, char sn, const char* dv,
+ const char* hs, const char* ha, bool oa, Struct_var* r)
+ : longname(ln), dashes(d), shortname(sn), default_value(dv ? dv : ""),
+ helpstring(hs), helparg(ha), optional_arg(oa), reader(r)
+ {
+ // In longname, we convert all underscores to dashes, since GNU
+ // style uses dashes in option names. longname is likely to have
+ // underscores in it because it's also used to declare a C++
+ // function.
+ const char* pos = strchr(this->longname.c_str(), '_');
+ for (; pos; pos = strchr(pos, '_'))
+ this->longname[pos - this->longname.c_str()] = '-';
+
+ // We only register ourselves if our helpstring is not NULL. This
+ // is to support the "no-VAR" boolean variables, which we
+ // conditionally turn on by defining "no-VAR" help text.
+ if (this->helpstring)
+ this->register_option();
+ }
+
+ // This option takes an argument iff helparg is not NULL.
+ bool
+ takes_argument() const
+ { return this->helparg != NULL; }
+
+ // Whether the argument is optional.
+ bool
+ takes_optional_argument() const
+ { return this->optional_arg; }
+
+ // Register this option with the global list of options.
+ void
+ register_option();
+
+ // Print this option to stdout (used with --help).
+ void
+ print() const;
+};
+
+// All options have a Struct_##varname that inherits from this and
+// actually implements parse_to_value for that option.
+struct Struct_var
+{
+ // OPTION: the name of the option as specified on the commandline,
+ // including leading dashes, and any text following the option:
+ // "-O", "--defsym=mysym=0x1000", etc.
+ // ARG: the arg associated with this option, or NULL if the option
+ // takes no argument: "2", "mysym=0x1000", etc.
+ // CMDLINE: the global Command_line object. Used by DEFINE_special.
+ // OPTIONS: the global General_options object. Used by DEFINE_special.
+ virtual void
+ parse_to_value(const char* option, const char* arg,
+ Command_line* cmdline, General_options* options) = 0;
+ virtual
+ ~Struct_var() // To make gcc happy.
+ { }
+};
+
+// This is for "special" options that aren't of any predefined type.
+struct Struct_special : public Struct_var
+{
+ // If you change this, change the parse-fn in DEFINE_special as well.
+ typedef void (General_options::*Parse_function)(const char*, const char*,
+ Command_line*);
+ Struct_special(const char* varname, Dashes dashes, char shortname,
+ Parse_function parse_function,
+ const char* helpstring, const char* helparg)
+ : option(varname, dashes, shortname, "", helpstring, helparg, false, this),
+ parse(parse_function)
+ { }
+
+ void parse_to_value(const char* option, const char* arg,
+ Command_line* cmdline, General_options* options)
+ { (options->*(this->parse))(option, arg, cmdline); }
+
+ One_option option;
+ Parse_function parse;
+};
+
+} // End namespace options.
+
+
+// These are helper macros use by DEFINE_uint64/etc below.
+// This macro is used inside the General_options_ class, so defines
+// var() and set_var() as General_options methods. Arguments as are
+// for the constructor for One_option. param_type__ is the same as
+// type__ for built-in types, and "const type__ &" otherwise.
+//
+// When we define the linker command option "assert", the macro argument
+// varname__ of DEFINE_var below will be replaced by "assert". On Mac OSX
+// assert.h is included implicitly by one of the library headers we use. To
+// avoid unintended macro substitution of "assert()", we need to enclose
+// varname__ with parenthese.
+#define DEFINE_var(varname__, dashes__, shortname__, default_value__, \
+ default_value_as_string__, helpstring__, helparg__, \
+ optional_arg__, type__, param_type__, parse_fn__) \
+ public: \
+ param_type__ \
+ (varname__)() const \
+ { return this->varname__##_.value; } \
+ \
+ bool \
+ user_set_##varname__() const \
+ { return this->varname__##_.user_set_via_option; } \
+ \
+ void \
+ set_user_set_##varname__() \
+ { this->varname__##_.user_set_via_option = true; } \
+ \
+ private: \
+ struct Struct_##varname__ : public options::Struct_var \
+ { \
+ Struct_##varname__() \
+ : option(#varname__, dashes__, shortname__, default_value_as_string__, \
+ helpstring__, helparg__, optional_arg__, this), \
+ user_set_via_option(false), value(default_value__) \
+ { } \
+ \
+ void \
+ parse_to_value(const char* option_name, const char* arg, \
+ Command_line*, General_options*) \
+ { \
+ parse_fn__(option_name, arg, &this->value); \
+ this->user_set_via_option = true; \
+ } \
+ \
+ options::One_option option; \
+ bool user_set_via_option; \
+ type__ value; \
+ }; \
+ Struct_##varname__ varname__##_; \
+ void \
+ set_##varname__(param_type__ value) \
+ { this->varname__##_.value = value; }
+
+// These macros allow for easy addition of a new commandline option.
+
+// If no_helpstring__ is not NULL, then in addition to creating
+// VARNAME, we also create an option called no-VARNAME (or, for a -z
+// option, noVARNAME).
+#define DEFINE_bool(varname__, dashes__, shortname__, default_value__, \
+ helpstring__, no_helpstring__) \
+ DEFINE_var(varname__, dashes__, shortname__, default_value__, \
+ default_value__ ? "true" : "false", helpstring__, NULL, \
+ false, bool, bool, options::parse_bool) \
+ struct Struct_no_##varname__ : public options::Struct_var \
+ { \
+ Struct_no_##varname__() : option((dashes__ == options::DASH_Z \
+ ? "no" #varname__ \
+ : "no-" #varname__), \
+ dashes__, '\0', \
+ default_value__ ? "false" : "true", \
+ no_helpstring__, NULL, false, this) \
+ { } \
+ \
+ void \
+ parse_to_value(const char*, const char*, \
+ Command_line*, General_options* options) \
+ { \
+ options->set_##varname__(false); \
+ options->set_user_set_##varname__(); \
+ } \
+ \
+ options::One_option option; \
+ }; \
+ Struct_no_##varname__ no_##varname__##_initializer_
+
+#define DEFINE_enable(varname__, dashes__, shortname__, default_value__, \
+ helpstring__, no_helpstring__) \
+ DEFINE_var(enable_##varname__, dashes__, shortname__, default_value__, \
+ default_value__ ? "true" : "false", helpstring__, NULL, \
+ false, bool, bool, options::parse_bool) \
+ struct Struct_disable_##varname__ : public options::Struct_var \
+ { \
+ Struct_disable_##varname__() : option("disable-" #varname__, \
+ dashes__, '\0', \
+ default_value__ ? "false" : "true", \
+ no_helpstring__, NULL, false, this) \
+ { } \
+ \
+ void \
+ parse_to_value(const char*, const char*, \
+ Command_line*, General_options* options) \
+ { options->set_enable_##varname__(false); } \
+ \
+ options::One_option option; \
+ }; \
+ Struct_disable_##varname__ disable_##varname__##_initializer_
+
+#define DEFINE_int(varname__, dashes__, shortname__, default_value__, \
+ helpstring__, helparg__) \
+ DEFINE_var(varname__, dashes__, shortname__, default_value__, \
+ #default_value__, helpstring__, helparg__, false, \
+ int, int, options::parse_int)
+
+#define DEFINE_uint(varname__, dashes__, shortname__, default_value__, \
+ helpstring__, helparg__) \
+ DEFINE_var(varname__, dashes__, shortname__, default_value__, \
+ #default_value__, helpstring__, helparg__, false, \
+ int, int, options::parse_uint)
+
+#define DEFINE_uint64(varname__, dashes__, shortname__, default_value__, \
+ helpstring__, helparg__) \
+ DEFINE_var(varname__, dashes__, shortname__, default_value__, \
+ #default_value__, helpstring__, helparg__, false, \
+ uint64_t, uint64_t, options::parse_uint64)
+
+#define DEFINE_double(varname__, dashes__, shortname__, default_value__, \
+ helpstring__, helparg__) \
+ DEFINE_var(varname__, dashes__, shortname__, default_value__, \
+ #default_value__, helpstring__, helparg__, false, \
+ double, double, options::parse_double)
+
+#define DEFINE_percent(varname__, dashes__, shortname__, default_value__, \
+ helpstring__, helparg__) \
+ DEFINE_var(varname__, dashes__, shortname__, default_value__ / 100.0, \
+ #default_value__, helpstring__, helparg__, false, \
+ double, double, options::parse_percent)
+
+#define DEFINE_string(varname__, dashes__, shortname__, default_value__, \
+ helpstring__, helparg__) \
+ DEFINE_var(varname__, dashes__, shortname__, default_value__, \
+ default_value__, helpstring__, helparg__, false, \
+ const char*, const char*, options::parse_string)
+
+// This is like DEFINE_string, but we convert each occurrence to a
+// Search_directory and store it in a vector. Thus we also have the
+// add_to_VARNAME() method, to append to the vector.
+#define DEFINE_dirlist(varname__, dashes__, shortname__, \
+ helpstring__, helparg__) \
+ DEFINE_var(varname__, dashes__, shortname__, , \
+ "", helpstring__, helparg__, false, options::Dir_list, \
+ const options::Dir_list&, options::parse_dirlist) \
+ void \
+ add_to_##varname__(const char* new_value) \
+ { options::parse_dirlist(NULL, new_value, &this->varname__##_.value); } \
+ void \
+ add_search_directory_to_##varname__(const Search_directory& dir) \
+ { this->varname__##_.value.push_back(dir); }
+
+// This is like DEFINE_string, but we store a set of strings.
+#define DEFINE_set(varname__, dashes__, shortname__, \
+ helpstring__, helparg__) \
+ DEFINE_var(varname__, dashes__, shortname__, , \
+ "", helpstring__, helparg__, false, options::String_set, \
+ const options::String_set&, options::parse_set) \
+ public: \
+ bool \
+ any_##varname__() const \
+ { return !this->varname__##_.value.empty(); } \
+ \
+ bool \
+ is_##varname__(const char* symbol) const \
+ { \
+ return (!this->varname__##_.value.empty() \
+ && (this->varname__##_.value.find(std::string(symbol)) \
+ != this->varname__##_.value.end())); \
+ } \
+ \
+ options::String_set::const_iterator \
+ varname__##_begin() const \
+ { return this->varname__##_.value.begin(); } \
+ \
+ options::String_set::const_iterator \
+ varname__##_end() const \
+ { return this->varname__##_.value.end(); }
+
+// When you have a list of possible values (expressed as string)
+// After helparg__ should come an initializer list, like
+// {"foo", "bar", "baz"}
+#define DEFINE_enum(varname__, dashes__, shortname__, default_value__, \
+ helpstring__, helparg__, ...) \
+ DEFINE_var(varname__, dashes__, shortname__, default_value__, \
+ default_value__, helpstring__, helparg__, false, \
+ const char*, const char*, parse_choices_##varname__) \
+ private: \
+ static void parse_choices_##varname__(const char* option_name, \
+ const char* arg, \
+ const char** retval) { \
+ const char* choices[] = __VA_ARGS__; \
+ options::parse_choices(option_name, arg, retval, \
+ choices, sizeof(choices) / sizeof(*choices)); \
+ }
+
+// This is like DEFINE_bool, but VARNAME is the name of a different
+// option. This option becomes an alias for that one. INVERT is true
+// if this option is an inversion of the other one.
+#define DEFINE_bool_alias(option__, varname__, dashes__, shortname__, \
+ helpstring__, no_helpstring__, invert__) \
+ private: \
+ struct Struct_##option__ : public options::Struct_var \
+ { \
+ Struct_##option__() \
+ : option(#option__, dashes__, shortname__, "", helpstring__, \
+ NULL, false, this) \
+ { } \
+ \
+ void \
+ parse_to_value(const char*, const char*, \
+ Command_line*, General_options* options) \
+ { \
+ options->set_##varname__(!invert__); \
+ options->set_user_set_##varname__(); \
+ } \
+ \
+ options::One_option option; \
+ }; \
+ Struct_##option__ option__##_; \
+ \
+ struct Struct_no_##option__ : public options::Struct_var \
+ { \
+ Struct_no_##option__() \
+ : option((dashes__ == options::DASH_Z \
+ ? "no" #option__ \
+ : "no-" #option__), \
+ dashes__, '\0', "", no_helpstring__, \
+ NULL, false, this) \
+ { } \
+ \
+ void \
+ parse_to_value(const char*, const char*, \
+ Command_line*, General_options* options) \
+ { \
+ options->set_##varname__(invert__); \
+ options->set_user_set_##varname__(); \
+ } \
+ \
+ options::One_option option; \
+ }; \
+ Struct_no_##option__ no_##option__##_initializer_
+
+// This is like DEFINE_uint64, but VARNAME is the name of a different
+// option. This option becomes an alias for that one.
+#define DEFINE_uint64_alias(option__, varname__, dashes__, shortname__, \
+ helpstring__, helparg__) \
+ private: \
+ struct Struct_##option__ : public options::Struct_var \
+ { \
+ Struct_##option__() \
+ : option(#option__, dashes__, shortname__, "", helpstring__, \
+ helparg__, false, this) \
+ { } \
+ \
+ void \
+ parse_to_value(const char* option_name, const char* arg, \
+ Command_line*, General_options* options) \
+ { \
+ uint64_t value; \
+ options::parse_uint64(option_name, arg, &value); \
+ options->set_##varname__(value); \
+ options->set_user_set_##varname__(); \
+ } \
+ \
+ options::One_option option; \
+ }; \
+ Struct_##option__ option__##_;
+
+// This is used for non-standard flags. It defines no functions; it
+// just calls General_options::parse_VARNAME whenever the flag is
+// seen. We declare parse_VARNAME as a static member of
+// General_options; you are responsible for defining it there.
+// helparg__ should be NULL iff this special-option is a boolean.
+#define DEFINE_special(varname__, dashes__, shortname__, \
+ helpstring__, helparg__) \
+ private: \
+ void parse_##varname__(const char* option, const char* arg, \
+ Command_line* inputs); \
+ struct Struct_##varname__ : public options::Struct_special \
+ { \
+ Struct_##varname__() \
+ : options::Struct_special(#varname__, dashes__, shortname__, \
+ &General_options::parse_##varname__, \
+ helpstring__, helparg__) \
+ { } \
+ }; \
+ Struct_##varname__ varname__##_initializer_
+
+// An option that takes an optional string argument. If the option is
+// used with no argument, the value will be the default, and
+// user_set_via_option will be true.
+#define DEFINE_optional_string(varname__, dashes__, shortname__, \
+ default_value__, \
+ helpstring__, helparg__) \
+ DEFINE_var(varname__, dashes__, shortname__, default_value__, \
+ default_value__, helpstring__, helparg__, true, \
+ const char*, const char*, options::parse_optional_string)
+
+// A directory to search. For each directory we record whether it is
+// in the sysroot. We need to know this so that, if a linker script
+// is found within the sysroot, we will apply the sysroot to any files
+// named by that script.
+
+class Search_directory
+{
+ public:
+ // We need a default constructor because we put this in a
+ // std::vector.
+ Search_directory()
+ : name_(NULL), put_in_sysroot_(false), is_in_sysroot_(false)
+ { }
+
+ // This is the usual constructor.
+ Search_directory(const std::string& name, bool put_in_sysroot)
+ : name_(name), put_in_sysroot_(put_in_sysroot), is_in_sysroot_(false)
+ {
+ if (this->name_.empty())
+ this->name_ = ".";
+ }
+
+ // This is called if we have a sysroot. The sysroot is prefixed to
+ // any entries for which put_in_sysroot_ is true. is_in_sysroot_ is
+ // set to true for any enries which are in the sysroot (this will
+ // naturally include any entries for which put_in_sysroot_ is true).
+ // SYSROOT is the sysroot, CANONICAL_SYSROOT is the result of
+ // passing SYSROOT to lrealpath.
+ void
+ add_sysroot(const char* sysroot, const char* canonical_sysroot);
+
+ // Get the directory name.
+ const std::string&
+ name() const
+ { return this->name_; }
+
+ // Return whether this directory is in the sysroot.
+ bool
+ is_in_sysroot() const
+ { return this->is_in_sysroot_; }
+
+ // Return whether this is considered a system directory.
+ bool
+ is_system_directory() const
+ { return this->put_in_sysroot_ || this->is_in_sysroot_; }
+
+ private:
+ // The directory name.
+ std::string name_;
+ // True if the sysroot should be added as a prefix for this
+ // directory (if there is a sysroot). This is true for system
+ // directories that we search by default.
+ bool put_in_sysroot_;
+ // True if this directory is in the sysroot (if there is a sysroot).
+ // This is true if there is a sysroot and either 1) put_in_sysroot_
+ // is true, or 2) the directory happens to be in the sysroot based
+ // on a pathname comparison.
+ bool is_in_sysroot_;
+};
+
+class General_options
+{
+ private:
+ // NOTE: For every option that you add here, also consider if you
+ // should add it to Position_dependent_options.
+ DEFINE_special(help, options::TWO_DASHES, '\0',
+ N_("Report usage information"), NULL);
+ DEFINE_special(version, options::TWO_DASHES, 'v',
+ N_("Report version information"), NULL);
+ DEFINE_special(V, options::EXACTLY_ONE_DASH, '\0',
+ N_("Report version and target information"), NULL);
+
+ // These options are sorted approximately so that for each letter in
+ // the alphabet, we show the option whose shortname is that letter
+ // (if any) and then every longname that starts with that letter (in
+ // alphabetical order). For both, lowercase sorts before uppercase.
+ // The -z options come last.
+
+ DEFINE_bool(add_needed, options::TWO_DASHES, '\0', false,
+ N_("Not supported"),
+ N_("Do not copy DT_NEEDED tags from shared libraries"));
+
+ DEFINE_bool_alias(allow_multiple_definition, muldefs, options::TWO_DASHES,
+ '\0', N_("Allow multiple definitions of symbols"),
+ N_("Do not allow multiple definitions"), false);
+
+ DEFINE_bool(allow_shlib_undefined, options::TWO_DASHES, '\0', false,
+ N_("Allow unresolved references in shared libraries"),
+ N_("Do not allow unresolved references in shared libraries"));
+
+ DEFINE_bool(as_needed, options::TWO_DASHES, '\0', false,
+ N_("Only set DT_NEEDED for shared libraries if used"),
+ N_("Always DT_NEEDED for shared libraries"));
+
+ DEFINE_enum(assert, options::ONE_DASH, '\0', NULL,
+ N_("Ignored"), N_("[ignored]"),
+ {"definitions", "nodefinitions", "nosymbolic", "pure-text"});
+
+ // This should really be an "enum", but it's too easy for folks to
+ // forget to update the list as they add new targets. So we just
+ // accept any string. We'll fail later (when the string is parsed),
+ // if the target isn't actually supported.
+ DEFINE_string(format, options::TWO_DASHES, 'b', "elf",
+ N_("Set input format"), ("[elf,binary]"));
+
+ DEFINE_bool(Bdynamic, options::ONE_DASH, '\0', true,
+ N_("-l searches for shared libraries"), NULL);
+ DEFINE_bool_alias(Bstatic, Bdynamic, options::ONE_DASH, '\0',
+ N_("-l does not search for shared libraries"), NULL,
+ true);
+ DEFINE_bool_alias(dy, Bdynamic, options::ONE_DASH, '\0',
+ N_("alias for -Bdynamic"), NULL, false);
+ DEFINE_bool_alias(dn, Bdynamic, options::ONE_DASH, '\0',
+ N_("alias for -Bstatic"), NULL, true);
+
+ DEFINE_bool(Bgroup, options::ONE_DASH, '\0', false,
+ N_("Use group name lookup rules for shared library"), NULL);
+
+ DEFINE_bool(Bsymbolic, options::ONE_DASH, '\0', false,
+ N_("Bind defined symbols locally"), NULL);
+
+ DEFINE_bool(Bsymbolic_functions, options::ONE_DASH, '\0', false,
+ N_("Bind defined function symbols locally"), NULL);
+
+ DEFINE_optional_string(build_id, options::TWO_DASHES, '\0', "tree",
+ N_("Generate build ID note"),
+ N_("[=STYLE]"));
+
+ DEFINE_uint64(build_id_chunk_size_for_treehash,
+ options::TWO_DASHES, '\0', 2 << 20,
+ N_("Chunk size for '--build-id=tree'"), N_("SIZE"));
+
+ DEFINE_uint64(build_id_min_file_size_for_treehash, options::TWO_DASHES,
+ '\0', 40 << 20,
+ N_("Minimum output file size for '--build-id=tree' to work"
+ " differently than '--build-id=sha1'"), N_("SIZE"));
+
+ DEFINE_bool(check_sections, options::TWO_DASHES, '\0', true,
+ N_("Check segment addresses for overlaps (default)"),
+ N_("Do not check segment addresses for overlaps"));
+
+#ifdef HAVE_ZLIB_H
+ DEFINE_enum(compress_debug_sections, options::TWO_DASHES, '\0', "none",
+ N_("Compress .debug_* sections in the output file"),
+ ("[none,zlib]"),
+ {"none", "zlib"});
+#else
+ DEFINE_enum(compress_debug_sections, options::TWO_DASHES, '\0', "none",
+ N_("Compress .debug_* sections in the output file"),
+ N_("[none]"),
+ {"none"});
+#endif
+
+ DEFINE_bool(copy_dt_needed_entries, options::TWO_DASHES, '\0', false,
+ N_("Not supported"),
+ N_("Do not copy DT_NEEDED tags from shared libraries"));
+
+ DEFINE_bool(cref, options::TWO_DASHES, '\0', false,
+ N_("Output cross reference table"),
+ N_("Do not output cross reference table"));
+
+ DEFINE_bool(ctors_in_init_array, options::TWO_DASHES, '\0', true,
+ N_("Use DT_INIT_ARRAY for all constructors (default)"),
+ N_("Handle constructors as directed by compiler"));
+
+ DEFINE_bool(define_common, options::TWO_DASHES, 'd', false,
+ N_("Define common symbols"),
+ N_("Do not define common symbols"));
+ DEFINE_bool(dc, options::ONE_DASH, '\0', false,
+ N_("Alias for -d"), NULL);
+ DEFINE_bool(dp, options::ONE_DASH, '\0', false,
+ N_("Alias for -d"), NULL);
+
+ DEFINE_string(debug, options::TWO_DASHES, '\0', "",
+ N_("Turn on debugging"),
+ N_("[all,files,script,task][,...]"));
+
+ DEFINE_special(defsym, options::TWO_DASHES, '\0',
+ N_("Define a symbol"), N_("SYMBOL=EXPRESSION"));
+
+ DEFINE_optional_string(demangle, options::TWO_DASHES, '\0', NULL,
+ N_("Demangle C++ symbols in log messages"),
+ N_("[=STYLE]"));
+
+ DEFINE_bool(no_demangle, options::TWO_DASHES, '\0', false,
+ N_("Do not demangle C++ symbols in log messages"),
+ NULL);
+
+ DEFINE_bool(detect_odr_violations, options::TWO_DASHES, '\0', false,
+ N_("Look for violations of the C++ One Definition Rule"),
+ N_("Do not look for violations of the C++ One Definition Rule"));
+
+ DEFINE_bool(discard_all, options::TWO_DASHES, 'x', false,
+ N_("Delete all local symbols"), NULL);
+ DEFINE_bool(discard_locals, options::TWO_DASHES, 'X', false,
+ N_("Delete all temporary local symbols"), NULL);
+
+ DEFINE_bool(dynamic_list_data, options::TWO_DASHES, '\0', false,
+ N_("Add data symbols to dynamic symbols"), NULL);
+
+ DEFINE_bool(dynamic_list_cpp_new, options::TWO_DASHES, '\0', false,
+ N_("Add C++ operator new/delete to dynamic symbols"), NULL);
+
+ DEFINE_bool(dynamic_list_cpp_typeinfo, options::TWO_DASHES, '\0', false,
+ N_("Add C++ typeinfo to dynamic symbols"), NULL);
+
+ DEFINE_special(dynamic_list, options::TWO_DASHES, '\0',
+ N_("Read a list of dynamic symbols"), N_("FILE"));
+
+ DEFINE_string(entry, options::TWO_DASHES, 'e', NULL,
+ N_("Set program start address"), N_("ADDRESS"));
+
+ DEFINE_special(exclude_libs, options::TWO_DASHES, '\0',
+ N_("Exclude libraries from automatic export"),
+ N_(("lib,lib ...")));
+
+ DEFINE_bool(export_dynamic, options::TWO_DASHES, 'E', false,
+ N_("Export all dynamic symbols"),
+ N_("Do not export all dynamic symbols (default)"));
+
+ DEFINE_set(export_dynamic_symbol, options::TWO_DASHES, '\0',
+ N_("Export SYMBOL to dynamic symbol table"), N_("SYMBOL"));
+
+ DEFINE_special(EB, options::ONE_DASH, '\0',
+ N_("Link big-endian objects."), NULL);
+
+ DEFINE_special(EL, options::ONE_DASH, '\0',
+ N_("Link little-endian objects."), NULL);
+
+ DEFINE_bool(eh_frame_hdr, options::TWO_DASHES, '\0', false,
+ N_("Create exception frame header"), NULL);
+
+ DEFINE_bool(enum_size_warning, options::TWO_DASHES, '\0', true, NULL,
+ N_("(ARM only) Do not warn about objects with incompatible "
+ "enum sizes"));
+
+ DEFINE_set(auxiliary, options::TWO_DASHES, 'f',
+ N_("Auxiliary filter for shared object symbol table"),
+ N_("SHLIB"));
+
+ DEFINE_string(filter, options::TWO_DASHES, 'F', NULL,
+ N_("Filter for shared object symbol table"),
+ N_("SHLIB"));
+
+ DEFINE_bool(fatal_warnings, options::TWO_DASHES, '\0', false,
+ N_("Treat warnings as errors"),
+ N_("Do not treat warnings as errors"));
+
+ DEFINE_string(fini, options::ONE_DASH, '\0', "_fini",
+ N_("Call SYMBOL at unload-time"), N_("SYMBOL"));
+
+ DEFINE_bool(fix_cortex_a8, options::TWO_DASHES, '\0', false,
+ N_("(ARM only) Fix binaries for Cortex-A8 erratum."),
+ N_("(ARM only) Do not fix binaries for Cortex-A8 erratum."));
+
+ DEFINE_bool(fix_arm1176, options::TWO_DASHES, '\0', true,
+ N_("(ARM only) Fix binaries for ARM1176 erratum."),
+ N_("(ARM only) Do not fix binaries for ARM1176 erratum."));
+
+ DEFINE_bool(merge_exidx_entries, options::TWO_DASHES, '\0', true,
+ N_("(ARM only) Merge exidx entries in debuginfo."),
+ N_("(ARM only) Do not merge exidx entries in debuginfo."));
+
+ DEFINE_special(fix_v4bx, options::TWO_DASHES, '\0',
+ N_("(ARM only) Rewrite BX rn as MOV pc, rn for ARMv4"),
+ NULL);
+
+ DEFINE_special(fix_v4bx_interworking, options::TWO_DASHES, '\0',
+ N_("(ARM only) Rewrite BX rn branch to ARMv4 interworking "
+ "veneer"),
+ NULL);
+
+ DEFINE_bool(g, options::EXACTLY_ONE_DASH, '\0', false,
+ N_("Ignored"), NULL);
+
+ DEFINE_bool(gdb_index, options::TWO_DASHES, '\0', false,
+ N_("Generate .gdb_index section"),
+ N_("Do not generate .gdb_index section"));
+
+ DEFINE_bool(gnu_unique, options::TWO_DASHES, '\0', true,
+ N_("Enable STB_GNU_UNIQUE symbol binding (default)"),
+ N_("Disable STB_GNU_UNIQUE symbol binding"));
+
+ DEFINE_string(soname, options::ONE_DASH, 'h', NULL,
+ N_("Set shared library name"), N_("FILENAME"));
+
+ DEFINE_double(hash_bucket_empty_fraction, options::TWO_DASHES, '\0', 0.0,
+ N_("Min fraction of empty buckets in dynamic hash"),
+ N_("FRACTION"));
+
+ DEFINE_enum(hash_style, options::TWO_DASHES, '\0', "sysv",
+ N_("Dynamic hash style"), N_("[sysv,gnu,both]"),
+ {"sysv", "gnu", "both"});
+
+ DEFINE_string(dynamic_linker, options::TWO_DASHES, 'I', NULL,
+ N_("Set dynamic linker path"), N_("PROGRAM"));
+
+ DEFINE_special(incremental, options::TWO_DASHES, '\0',
+ N_("Do an incremental link if possible; "
+ "otherwise, do a full link and prepare output "
+ "for incremental linking"), NULL);
+
+ DEFINE_special(no_incremental, options::TWO_DASHES, '\0',
+ N_("Do a full link (default)"), NULL);
+
+ DEFINE_special(incremental_full, options::TWO_DASHES, '\0',
+ N_("Do a full link and "
+ "prepare output for incremental linking"), NULL);
+
+ DEFINE_special(incremental_update, options::TWO_DASHES, '\0',
+ N_("Do an incremental link; exit if not possible"), NULL);
+
+ DEFINE_string(incremental_base, options::TWO_DASHES, '\0', NULL,
+ N_("Set base file for incremental linking"
+ " (default is output file)"),
+ N_("FILE"));
+
+ DEFINE_special(incremental_changed, options::TWO_DASHES, '\0',
+ N_("Assume files changed"), NULL);
+
+ DEFINE_special(incremental_unchanged, options::TWO_DASHES, '\0',
+ N_("Assume files didn't change"), NULL);
+
+ DEFINE_special(incremental_unknown, options::TWO_DASHES, '\0',
+ N_("Use timestamps to check files (default)"), NULL);
+
+ DEFINE_special(incremental_startup_unchanged, options::TWO_DASHES, '\0',
+ N_("Assume startup files unchanged "
+ "(files preceding this option)"), NULL);
+
+ DEFINE_percent(incremental_patch, options::TWO_DASHES, '\0', 10,
+ N_("Amount of extra space to allocate for patches"),
+ N_("PERCENT"));
+
+ DEFINE_string(init, options::ONE_DASH, '\0', "_init",
+ N_("Call SYMBOL at load-time"), N_("SYMBOL"));
+
+ DEFINE_special(just_symbols, options::TWO_DASHES, '\0',
+ N_("Read only symbol values from FILE"), N_("FILE"));
+
+ DEFINE_bool(map_whole_files, options::TWO_DASHES, '\0',
+ sizeof(void*) >= 8,
+ N_("Map whole files to memory (default on 64-bit hosts)"),
+ N_("Map relevant file parts to memory (default on 32-bit "
+ "hosts)"));
+ DEFINE_bool(keep_files_mapped, options::TWO_DASHES, '\0', true,
+ N_("Keep files mapped across passes (default)"),
+ N_("Release mapped files after each pass"));
+
+ DEFINE_bool(ld_generated_unwind_info, options::TWO_DASHES, '\0', true,
+ N_("Generate unwind information for PLT (default)"),
+ N_("Do not generate unwind information for PLT"));
+
+ DEFINE_special(library, options::TWO_DASHES, 'l',
+ N_("Search for library LIBNAME"), N_("LIBNAME"));
+
+ DEFINE_dirlist(library_path, options::TWO_DASHES, 'L',
+ N_("Add directory to search path"), N_("DIR"));
+
+ DEFINE_bool(text_reorder, options::TWO_DASHES, '\0', true,
+ N_("Enable text section reordering for GCC section names "
+ "(default)"),
+ N_("Disable text section reordering for GCC section names"));
+
+ DEFINE_bool(nostdlib, options::ONE_DASH, '\0', false,
+ N_("Only search directories specified on the command line."),
+ NULL);
+
+ DEFINE_bool(rosegment, options::TWO_DASHES, '\0', false,
+ N_("Put read-only non-executable sections in their own segment"),
+ NULL);
+
+ DEFINE_uint64(rosegment_gap, options::TWO_DASHES, '\0', -1U,
+ N_("Set offset between executable and read-only segments"),
+ N_("OFFSET"));
+
+ DEFINE_string(m, options::EXACTLY_ONE_DASH, 'm', "",
+ N_("Set GNU linker emulation; obsolete"), N_("EMULATION"));
+
+ DEFINE_bool(mmap_output_file, options::TWO_DASHES, '\0', true,
+ N_("Map the output file for writing (default)."),
+ N_("Do not map the output file for writing."));
+
+ DEFINE_bool(print_map, options::TWO_DASHES, 'M', false,
+ N_("Write map file on standard output"), NULL);
+ DEFINE_string(Map, options::ONE_DASH, '\0', NULL, N_("Write map file"),
+ N_("MAPFILENAME"));
+
+ DEFINE_bool(nmagic, options::TWO_DASHES, 'n', false,
+ N_("Do not page align data"), NULL);
+ DEFINE_bool(omagic, options::EXACTLY_TWO_DASHES, 'N', false,
+ N_("Do not page align data, do not make text readonly"),
+ N_("Page align data, make text readonly"));
+
+ DEFINE_enable(new_dtags, options::EXACTLY_TWO_DASHES, '\0', true,
+ N_("Enable use of DT_RUNPATH and DT_FLAGS"),
+ N_("Disable use of DT_RUNPATH and DT_FLAGS"));
+
+ DEFINE_bool(noinhibit_exec, options::TWO_DASHES, '\0', false,
+ N_("Create an output file even if errors occur"), NULL);
+
+ DEFINE_bool_alias(no_undefined, defs, options::TWO_DASHES, '\0',
+ N_("Report undefined symbols (even with --shared)"),
+ NULL, false);
+
+ DEFINE_string(output, options::TWO_DASHES, 'o', "a.out",
+ N_("Set output file name"), N_("FILE"));
+
+ DEFINE_uint(optimize, options::EXACTLY_ONE_DASH, 'O', 0,
+ N_("Optimize output file size"), N_("LEVEL"));
+
+ DEFINE_string(oformat, options::EXACTLY_TWO_DASHES, '\0', "elf",
+ N_("Set output format"), N_("[binary]"));
+
+ DEFINE_bool(p, options::ONE_DASH, '\0', false,
+ N_("(ARM only) Ignore for backward compatibility"), NULL);
+
+ DEFINE_bool(pie, options::ONE_DASH, '\0', false,
+ N_("Create a position independent executable"), NULL);
+ DEFINE_bool_alias(pic_executable, pie, options::TWO_DASHES, '\0',
+ N_("Create a position independent executable"), NULL,
+ false);
+
+ DEFINE_bool(pipeline_knowledge, options::ONE_DASH, '\0', false,
+ NULL, N_("(ARM only) Ignore for backward compatibility"));
+
+ DEFINE_var(plt_align, options::TWO_DASHES, '\0', 0, "5",
+ N_("(PowerPC64 only) Align PLT call stubs to fit cache lines"),
+ N_("[=P2ALIGN]"), true, int, int, options::parse_uint);
+
+ DEFINE_bool(plt_static_chain, options::TWO_DASHES, '\0', false,
+ N_("(PowerPC64 only) PLT call stubs should load r11"),
+ N_("(PowerPC64 only) PLT call stubs should not load r11"));
+
+ DEFINE_bool(plt_thread_safe, options::TWO_DASHES, '\0', false,
+ N_("(PowerPC64 only) PLT call stubs with load-load barrier"),
+ N_("(PowerPC64 only) PLT call stubs without barrier"));
+
+#ifdef ENABLE_PLUGINS
+ DEFINE_special(plugin, options::TWO_DASHES, '\0',
+ N_("Load a plugin library"), N_("PLUGIN"));
+ DEFINE_special(plugin_opt, options::TWO_DASHES, '\0',
+ N_("Pass an option to the plugin"), N_("OPTION"));
+#endif
+
+ DEFINE_bool(posix_fallocate, options::TWO_DASHES, '\0', true,
+ N_("Use posix_fallocate to reserve space in the output file"
+ " (default)."),
+ N_("Use fallocate or ftruncate to reserve space."));
+
+ DEFINE_bool(preread_archive_symbols, options::TWO_DASHES, '\0', false,
+ N_("Preread archive symbols when multi-threaded"), NULL);
+
+ DEFINE_bool(print_output_format, options::TWO_DASHES, '\0', false,
+ N_("Print default output format"), NULL);
+
+ DEFINE_string(print_symbol_counts, options::TWO_DASHES, '\0', NULL,
+ N_("Print symbols defined and used for each input"),
+ N_("FILENAME"));
+
+ DEFINE_bool(Qy, options::EXACTLY_ONE_DASH, '\0', false,
+ N_("Ignored for SVR4 compatibility"), NULL);
+
+ DEFINE_bool(emit_relocs, options::TWO_DASHES, 'q', false,
+ N_("Generate relocations in output"), NULL);
+
+ DEFINE_bool(relocatable, options::EXACTLY_ONE_DASH, 'r', false,
+ N_("Generate relocatable output"), NULL);
+ DEFINE_bool_alias(i, relocatable, options::EXACTLY_ONE_DASH, '\0',
+ N_("Synonym for -r"), NULL, false);
+
+ DEFINE_bool(relax, options::TWO_DASHES, '\0', false,
+ N_("Relax branches on certain targets"), NULL);
+
+ DEFINE_string(retain_symbols_file, options::TWO_DASHES, '\0', NULL,
+ N_("keep only symbols listed in this file"), N_("FILE"));
+
+ // -R really means -rpath, but can mean --just-symbols for
+ // compatibility with GNU ld. -rpath is always -rpath, so we list
+ // it separately.
+ DEFINE_special(R, options::EXACTLY_ONE_DASH, 'R',
+ N_("Add DIR to runtime search path"), N_("DIR"));
+
+ DEFINE_dirlist(rpath, options::ONE_DASH, '\0',
+ N_("Add DIR to runtime search path"), N_("DIR"));
+
+ DEFINE_dirlist(rpath_link, options::TWO_DASHES, '\0',
+ N_("Add DIR to link time shared library search path"),
+ N_("DIR"));
+
+ DEFINE_string(section_ordering_file, options::TWO_DASHES, '\0', NULL,
+ N_("Layout sections in the order specified."),
+ N_("FILENAME"));
+
+ DEFINE_special(section_start, options::TWO_DASHES, '\0',
+ N_("Set address of section"), N_("SECTION=ADDRESS"));
+
+ DEFINE_optional_string(sort_common, options::TWO_DASHES, '\0', NULL,
+ N_("Sort common symbols by alignment"),
+ N_("[={ascending,descending}]"));
+
+ DEFINE_enum(sort_section, options::TWO_DASHES, '\0', "none",
+ N_("Sort sections by name. \'--no-text-reorder\'"
+ " will override \'--sort-section=name\' for .text"),
+ N_("[none,name]"),
+ {"none", "name"});
+
+ DEFINE_uint(spare_dynamic_tags, options::TWO_DASHES, '\0', 5,
+ N_("Dynamic tag slots to reserve (default 5)"),
+ N_("COUNT"));
+
+ DEFINE_bool(strip_all, options::TWO_DASHES, 's', false,
+ N_("Strip all symbols"), NULL);
+ DEFINE_bool(strip_debug, options::TWO_DASHES, 'S', false,
+ N_("Strip debugging information"), NULL);
+ DEFINE_bool(strip_debug_non_line, options::TWO_DASHES, '\0', false,
+ N_("Emit only debug line number information"), NULL);
+ DEFINE_bool(strip_debug_gdb, options::TWO_DASHES, '\0', false,
+ N_("Strip debug symbols that are unused by gdb "
+ "(at least versions <= 7.4)"), NULL);
+ DEFINE_bool(strip_lto_sections, options::TWO_DASHES, '\0', true,
+ N_("Strip LTO intermediate code sections"), NULL);
+
+ DEFINE_int(stub_group_size, options::TWO_DASHES , '\0', 1,
+ N_("(ARM, PowerPC only) The maximum distance from instructions "
+ "in a group of sections to their stubs. Negative values mean "
+ "stubs are always after (PowerPC before) the group. 1 means "
+ "use default size.\n"),
+ N_("SIZE"));
+
+ DEFINE_bool(no_keep_memory, options::TWO_DASHES, '\0', false,
+ N_("Use less memory and more disk I/O "
+ "(included only for compatibility with GNU ld)"), NULL);
+
+ DEFINE_bool(shared, options::ONE_DASH, 'G', false,
+ N_("Generate shared library"), NULL);
+
+ DEFINE_bool(Bshareable, options::ONE_DASH, '\0', false,
+ N_("Generate shared library"), NULL);
+
+ DEFINE_uint(split_stack_adjust_size, options::TWO_DASHES, '\0', 0x4000,
+ N_("Stack size when -fsplit-stack function calls non-split"),
+ N_("SIZE"));
+
+ // This is not actually special in any way, but I need to give it
+ // a non-standard accessor-function name because 'static' is a keyword.
+ DEFINE_special(static, options::ONE_DASH, '\0',
+ N_("Do not link against shared libraries"), NULL);
+
+ DEFINE_enum(icf, options::TWO_DASHES, '\0', "none",
+ N_("Identical Code Folding. "
+ "\'--icf=safe\' Folds ctors, dtors and functions whose"
+ " pointers are definitely not taken."),
+ ("[none,all,safe]"),
+ {"none", "all", "safe"});
+
+ DEFINE_uint(icf_iterations, options::TWO_DASHES , '\0', 0,
+ N_("Number of iterations of ICF (default 2)"), N_("COUNT"));
+
+ DEFINE_bool(print_icf_sections, options::TWO_DASHES, '\0', false,
+ N_("List folded identical sections on stderr"),
+ N_("Do not list folded identical sections"));
+
+ DEFINE_set(keep_unique, options::TWO_DASHES, '\0',
+ N_("Do not fold this symbol during ICF"), N_("SYMBOL"));
+
+ DEFINE_bool(gc_sections, options::TWO_DASHES, '\0', false,
+ N_("Remove unused sections"),
+ N_("Don't remove unused sections (default)"));
+
+ DEFINE_bool(print_gc_sections, options::TWO_DASHES, '\0', false,
+ N_("List removed unused sections on stderr"),
+ N_("Do not list removed unused sections"));
+
+ DEFINE_bool(stats, options::TWO_DASHES, '\0', false,
+ N_("Print resource usage statistics"), NULL);
+
+ DEFINE_string(sysroot, options::TWO_DASHES, '\0', "",
+ N_("Set target system root directory"), N_("DIR"));
+
+ DEFINE_bool(trace, options::TWO_DASHES, 't', false,
+ N_("Print the name of each input file"), NULL);
+
+ DEFINE_special(script, options::TWO_DASHES, 'T',
+ N_("Read linker script"), N_("FILE"));
+
+ DEFINE_bool(threads, options::TWO_DASHES, '\0', false,
+ N_("Run the linker multi-threaded"),
+ N_("Do not run the linker multi-threaded"));
+ DEFINE_uint(thread_count, options::TWO_DASHES, '\0', 0,
+ N_("Number of threads to use"), N_("COUNT"));
+ DEFINE_uint(thread_count_initial, options::TWO_DASHES, '\0', 0,
+ N_("Number of threads to use in initial pass"), N_("COUNT"));
+ DEFINE_uint(thread_count_middle, options::TWO_DASHES, '\0', 0,
+ N_("Number of threads to use in middle pass"), N_("COUNT"));
+ DEFINE_uint(thread_count_final, options::TWO_DASHES, '\0', 0,
+ N_("Number of threads to use in final pass"), N_("COUNT"));
+
+ DEFINE_uint64(Tbss, options::ONE_DASH, '\0', -1U,
+ N_("Set the address of the bss segment"), N_("ADDRESS"));
+ DEFINE_uint64(Tdata, options::ONE_DASH, '\0', -1U,
+ N_("Set the address of the data segment"), N_("ADDRESS"));
+ DEFINE_uint64(Ttext, options::ONE_DASH, '\0', -1U,
+ N_("Set the address of the text segment"), N_("ADDRESS"));
+ DEFINE_uint64_alias(Ttext_segment, Ttext, options::ONE_DASH, '\0',
+ N_("Set the address of the text segment"),
+ N_("ADDRESS"));
+ DEFINE_uint64(Trodata_segment, options::ONE_DASH, '\0', -1U,
+ N_("Set the address of the rodata segment"), N_("ADDRESS"));
+
+ DEFINE_bool(toc_optimize, options::TWO_DASHES, '\0', true,
+ N_("(PowerPC64 only) Optimize TOC code sequences"),
+ N_("(PowerPC64 only) Don't optimize TOC code sequences"));
+
+ DEFINE_bool(toc_sort, options::TWO_DASHES, '\0', true,
+ N_("(PowerPC64 only) Sort TOC and GOT sections"),
+ N_("(PowerPC64 only) Don't sort TOC and GOT sections"));
+
+ DEFINE_set(undefined, options::TWO_DASHES, 'u',
+ N_("Create undefined reference to SYMBOL"), N_("SYMBOL"));
+
+ DEFINE_enum(unresolved_symbols, options::TWO_DASHES, '\0', NULL,
+ N_("How to handle unresolved symbols"),
+ ("ignore-all,report-all,ignore-in-object-files,"
+ "ignore-in-shared-libs"),
+ {"ignore-all", "report-all", "ignore-in-object-files",
+ "ignore-in-shared-libs"});
+
+ DEFINE_bool(verbose, options::TWO_DASHES, '\0', false,
+ N_("Synonym for --debug=files"), NULL);
+
+ DEFINE_special(version_script, options::TWO_DASHES, '\0',
+ N_("Read version script"), N_("FILE"));
+
+ DEFINE_bool(warn_common, options::TWO_DASHES, '\0', false,
+ N_("Warn about duplicate common symbols"),
+ N_("Do not warn about duplicate common symbols (default)"));
+
+ DEFINE_bool(warn_constructors, options::TWO_DASHES, '\0', false,
+ N_("Ignored"), N_("Ignored"));
+
+ DEFINE_bool(warn_execstack, options::TWO_DASHES, '\0', false,
+ N_("Warn if the stack is executable"),
+ N_("Do not warn if the stack is executable (default)"));
+
+ DEFINE_bool(warn_mismatch, options::TWO_DASHES, '\0', true,
+ NULL, N_("Don't warn about mismatched input files"));
+
+ DEFINE_bool(warn_multiple_gp, options::TWO_DASHES, '\0', false,
+ N_("Ignored"), NULL);
+
+ DEFINE_bool(warn_search_mismatch, options::TWO_DASHES, '\0', true,
+ N_("Warn when skipping an incompatible library"),
+ N_("Don't warn when skipping an incompatible library"));
+
+ DEFINE_bool(warn_shared_textrel, options::TWO_DASHES, '\0', false,
+ N_("Warn if text segment is not shareable"),
+ N_("Do not warn if text segment is not shareable (default)"));
+
+ DEFINE_bool(warn_unresolved_symbols, options::TWO_DASHES, '\0', false,
+ N_("Report unresolved symbols as warnings"),
+ NULL);
+ DEFINE_bool_alias(error_unresolved_symbols, warn_unresolved_symbols,
+ options::TWO_DASHES, '\0',
+ N_("Report unresolved symbols as errors"),
+ NULL, true);
+
+ DEFINE_bool(wchar_size_warning, options::TWO_DASHES, '\0', true, NULL,
+ N_("(ARM only) Do not warn about objects with incompatible "
+ "wchar_t sizes"));
+
+ DEFINE_bool(whole_archive, options::TWO_DASHES, '\0', false,
+ N_("Include all archive contents"),
+ N_("Include only needed archive contents"));
+
+ DEFINE_set(wrap, options::TWO_DASHES, '\0',
+ N_("Use wrapper functions for SYMBOL"), N_("SYMBOL"));
+
+ DEFINE_set(trace_symbol, options::TWO_DASHES, 'y',
+ N_("Trace references to symbol"), N_("SYMBOL"));
+
+ DEFINE_bool(undefined_version, options::TWO_DASHES, '\0', true,
+ N_("Allow unused version in script (default)"),
+ N_("Do not allow unused version in script"));
+
+ DEFINE_string(Y, options::EXACTLY_ONE_DASH, 'Y', "",
+ N_("Default search path for Solaris compatibility"),
+ N_("PATH"));
+
+ DEFINE_special(start_group, options::TWO_DASHES, '(',
+ N_("Start a library search group"), NULL);
+ DEFINE_special(end_group, options::TWO_DASHES, ')',
+ N_("End a library search group"), NULL);
+
+
+ DEFINE_special(start_lib, options::TWO_DASHES, '\0',
+ N_("Start a library"), NULL);
+ DEFINE_special(end_lib, options::TWO_DASHES, '\0',
+ N_("End a library "), NULL);
+
+ DEFINE_string(fuse_ld, options::ONE_DASH, '\0', "",
+ N_("Ignored for GCC linker option compatibility"),
+ "");
+
+ // The -z options.
+
+ DEFINE_bool(combreloc, options::DASH_Z, '\0', true,
+ N_("Sort dynamic relocs"),
+ N_("Do not sort dynamic relocs"));
+ DEFINE_uint64(common_page_size, options::DASH_Z, '\0', 0,
+ N_("Set common page size to SIZE"), N_("SIZE"));
+ DEFINE_bool(defs, options::DASH_Z, '\0', false,
+ N_("Report undefined symbols (even with --shared)"),
+ NULL);
+ DEFINE_bool(execstack, options::DASH_Z, '\0', false,
+ N_("Mark output as requiring executable stack"), NULL);
+ DEFINE_bool(initfirst, options::DASH_Z, '\0', false,
+ N_("Mark DSO to be initialized first at runtime"),
+ NULL);
+ DEFINE_bool(interpose, options::DASH_Z, '\0', false,
+ N_("Mark object to interpose all DSOs but executable"),
+ NULL);
+ DEFINE_bool_alias(lazy, now, options::DASH_Z, '\0',
+ N_("Mark object for lazy runtime binding (default)"),
+ NULL, true);
+ DEFINE_bool(loadfltr, options::DASH_Z, '\0', false,
+ N_("Mark object requiring immediate process"),
+ NULL);
+ DEFINE_uint64(max_page_size, options::DASH_Z, '\0', 0,
+ N_("Set maximum page size to SIZE"), N_("SIZE"));
+ DEFINE_bool(muldefs, options::DASH_Z, '\0', false,
+ N_("Allow multiple definitions of symbols"),
+ NULL);
+ // copyreloc is here in the list because there is only -z
+ // nocopyreloc, not -z copyreloc.
+ DEFINE_bool(copyreloc, options::DASH_Z, '\0', true,
+ NULL,
+ N_("Do not create copy relocs"));
+ DEFINE_bool(nodefaultlib, options::DASH_Z, '\0', false,
+ N_("Mark object not to use default search paths"),
+ NULL);
+ DEFINE_bool(nodelete, options::DASH_Z, '\0', false,
+ N_("Mark DSO non-deletable at runtime"),
+ NULL);
+ DEFINE_bool(nodlopen, options::DASH_Z, '\0', false,
+ N_("Mark DSO not available to dlopen"),
+ NULL);
+ DEFINE_bool(nodump, options::DASH_Z, '\0', false,
+ N_("Mark DSO not available to dldump"),
+ NULL);
+ DEFINE_bool(noexecstack, options::DASH_Z, '\0', false,
+ N_("Mark output as not requiring executable stack"), NULL);
+ DEFINE_bool(now, options::DASH_Z, '\0', false,
+ N_("Mark object for immediate function binding"),
+ NULL);
+ DEFINE_bool(origin, options::DASH_Z, '\0', false,
+ N_("Mark DSO to indicate that needs immediate $ORIGIN "
+ "processing at runtime"), NULL);
+ DEFINE_bool(relro, options::DASH_Z, '\0', false,
+ N_("Where possible mark variables read-only after relocation"),
+ N_("Don't mark variables read-only after relocation"));
+ DEFINE_bool(text, options::DASH_Z, '\0', false,
+ N_("Do not permit relocations in read-only segments"),
+ N_("Permit relocations in read-only segments (default)"));
+ DEFINE_bool_alias(textoff, text, options::DASH_Z, '\0',
+ N_("Permit relocations in read-only segments (default)"),
+ NULL, true);
+
+ public:
+ typedef options::Dir_list Dir_list;
+
+ General_options();
+
+ // Does post-processing on flags, making sure they all have
+ // non-conflicting values. Also converts some flags from their
+ // "standard" types (string, etc), to another type (enum, DirList),
+ // which can be accessed via a separate method. Dies if it notices
+ // any problems.
+ void finalize();
+
+ // True if we printed the version information.
+ bool
+ printed_version() const
+ { return this->printed_version_; }
+
+ // The macro defines output() (based on --output), but that's a
+ // generic name. Provide this alternative name, which is clearer.
+ const char*
+ output_file_name() const
+ { return this->output(); }
+
+ // This is not defined via a flag, but combines flags to say whether
+ // the output is position-independent or not.
+ bool
+ output_is_position_independent() const
+ { return this->shared() || this->pie(); }
+
+ // Return true if the output is something that can be exec()ed, such
+ // as a static executable, or a position-dependent or
+ // position-independent executable, but not a dynamic library or an
+ // object file.
+ bool
+ output_is_executable() const
+ { return !this->shared() && !this->relocatable(); }
+
+ // This would normally be static(), and defined automatically, but
+ // since static is a keyword, we need to come up with our own name.
+ bool
+ is_static() const
+ { return static_; }
+
+ // In addition to getting the input and output formats as a string
+ // (via format() and oformat()), we also give access as an enum.
+ enum Object_format
+ {
+ // Ordinary ELF.
+ OBJECT_FORMAT_ELF,
+ // Straight binary format.
+ OBJECT_FORMAT_BINARY
+ };
+
+ // Convert a string to an Object_format. Gives an error if the
+ // string is not recognized.
+ static Object_format
+ string_to_object_format(const char* arg);
+
+ // Note: these functions are not very fast.
+ Object_format format_enum() const;
+ Object_format oformat_enum() const;
+
+ // Return whether FILENAME is in a system directory.
+ bool
+ is_in_system_directory(const std::string& name) const;
+
+ // RETURN whether SYMBOL_NAME should be kept, according to symbols_to_retain_.
+ bool
+ should_retain_symbol(const char* symbol_name) const
+ {
+ if (symbols_to_retain_.empty()) // means flag wasn't specified
+ return true;
+ return symbols_to_retain_.find(symbol_name) != symbols_to_retain_.end();
+ }
+
+ // These are the best way to get access to the execstack state,
+ // not execstack() and noexecstack() which are hard to use properly.
+ bool
+ is_execstack_set() const
+ { return this->execstack_status_ != EXECSTACK_FROM_INPUT; }
+
+ bool
+ is_stack_executable() const
+ { return this->execstack_status_ == EXECSTACK_YES; }
+
+ bool
+ icf_enabled() const
+ { return this->icf_status_ != ICF_NONE; }
+
+ bool
+ icf_safe_folding() const
+ { return this->icf_status_ == ICF_SAFE; }
+
+ // The --demangle option takes an optional string, and there is also
+ // a --no-demangle option. This is the best way to decide whether
+ // to demangle or not.
+ bool
+ do_demangle() const
+ { return this->do_demangle_; }
+
+ // Returns TRUE if any plugin libraries have been loaded.
+ bool
+ has_plugins() const
+ { return this->plugins_ != NULL; }
+
+ // Return a pointer to the plugin manager.
+ Plugin_manager*
+ plugins() const
+ { return this->plugins_; }
+
+ // True iff SYMBOL was found in the file specified by dynamic-list.
+ bool
+ in_dynamic_list(const char* symbol) const
+ { return this->dynamic_list_.version_script_info()->symbol_is_local(symbol); }
+
+ // Finalize the dynamic list.
+ void
+ finalize_dynamic_list()
+ { this->dynamic_list_.version_script_info()->finalize(); }
+
+ // The mode selected by the --incremental options.
+ enum Incremental_mode
+ {
+ // No incremental linking (--no-incremental).
+ INCREMENTAL_OFF,
+ // Incremental update only (--incremental-update).
+ INCREMENTAL_UPDATE,
+ // Force a full link, but prepare for subsequent incremental link
+ // (--incremental-full).
+ INCREMENTAL_FULL,
+ // Incremental update if possible, fallback to full link (--incremental).
+ INCREMENTAL_AUTO
+ };
+
+ // The incremental linking mode.
+ Incremental_mode
+ incremental_mode() const
+ { return this->incremental_mode_; }
+
+ // The disposition given by the --incremental-changed,
+ // --incremental-unchanged or --incremental-unknown option. The
+ // value may change as we proceed parsing the command line flags.
+ Incremental_disposition
+ incremental_disposition() const
+ { return this->incremental_disposition_; }
+
+ // The disposition to use for startup files (those that precede the
+ // first --incremental-changed, etc. option).
+ Incremental_disposition
+ incremental_startup_disposition() const
+ { return this->incremental_startup_disposition_; }
+
+ // Return true if S is the name of a library excluded from automatic
+ // symbol export.
+ bool
+ check_excluded_libs(const std::string &s) const;
+
+ // If an explicit start address was given for section SECNAME with
+ // the --section-start option, return true and set *PADDR to the
+ // address. Otherwise return false.
+ bool
+ section_start(const char* secname, uint64_t* paddr) const;
+
+ // Return whether any --section-start option was used.
+ bool
+ any_section_start() const
+ { return !this->section_starts_.empty(); }
+
+ enum Fix_v4bx
+ {
+ // Leave original instruction.
+ FIX_V4BX_NONE,
+ // Replace instruction.
+ FIX_V4BX_REPLACE,
+ // Generate an interworking veneer.
+ FIX_V4BX_INTERWORKING
+ };
+
+ Fix_v4bx
+ fix_v4bx() const
+ { return (this->fix_v4bx_); }
+
+ enum Endianness
+ {
+ ENDIANNESS_NOT_SET,
+ ENDIANNESS_BIG,
+ ENDIANNESS_LITTLE
+ };
+
+ Endianness
+ endianness() const
+ { return this->endianness_; }
+
+ private:
+ // Don't copy this structure.
+ General_options(const General_options&);
+ General_options& operator=(const General_options&);
+
+ // Whether to mark the stack as executable.
+ enum Execstack
+ {
+ // Not set on command line.
+ EXECSTACK_FROM_INPUT,
+ // Mark the stack as executable (-z execstack).
+ EXECSTACK_YES,
+ // Mark the stack as not executable (-z noexecstack).
+ EXECSTACK_NO
+ };
+
+ enum Icf_status
+ {
+ // Do not fold any functions (Default or --icf=none).
+ ICF_NONE,
+ // All functions are candidates for folding. (--icf=all).
+ ICF_ALL,
+ // Only ctors and dtors are candidates for folding. (--icf=safe).
+ ICF_SAFE
+ };
+
+ void
+ set_icf_status(Icf_status value)
+ { this->icf_status_ = value; }
+
+ void
+ set_execstack_status(Execstack value)
+ { this->execstack_status_ = value; }
+
+ void
+ set_do_demangle(bool value)
+ { this->do_demangle_ = value; }
+
+ void
+ set_static(bool value)
+ { static_ = value; }
+
+ // These are called by finalize() to set up the search-path correctly.
+ void
+ add_to_library_path_with_sysroot(const std::string& arg)
+ { this->add_search_directory_to_library_path(Search_directory(arg, true)); }
+
+ // Apply any sysroot to the directory lists.
+ void
+ add_sysroot();
+
+ // Add a plugin and its arguments to the list of plugins.
+ void
+ add_plugin(const char* filename);
+
+ // Add a plugin option.
+ void
+ add_plugin_option(const char* opt);
+
+ // Whether we printed version information.
+ bool printed_version_;
+ // Whether to mark the stack as executable.
+ Execstack execstack_status_;
+ // Whether to do code folding.
+ Icf_status icf_status_;
+ // Whether to do a static link.
+ bool static_;
+ // Whether to do demangling.
+ bool do_demangle_;
+ // List of plugin libraries.
+ Plugin_manager* plugins_;
+ // The parsed output of --dynamic-list files. For convenience in
+ // script.cc, we store this as a Script_options object, even though
+ // we only use a single Version_tree from it.
+ Script_options dynamic_list_;
+ // The incremental linking mode.
+ Incremental_mode incremental_mode_;
+ // The disposition given by the --incremental-changed,
+ // --incremental-unchanged or --incremental-unknown option. The
+ // value may change as we proceed parsing the command line flags.
+ Incremental_disposition incremental_disposition_;
+ // The disposition to use for startup files (those marked
+ // INCREMENTAL_STARTUP).
+ Incremental_disposition incremental_startup_disposition_;
+ // Whether we have seen one of the options that require incremental
+ // build (--incremental-changed, --incremental-unchanged,
+ // --incremental-unknown, or --incremental-startup-unchanged).
+ bool implicit_incremental_;
+ // Libraries excluded from automatic export, via --exclude-libs.
+ Unordered_set<std::string> excluded_libs_;
+ // List of symbol-names to keep, via -retain-symbol-info.
+ Unordered_set<std::string> symbols_to_retain_;
+ // Map from section name to address from --section-start.
+ std::map<std::string, uint64_t> section_starts_;
+ // Whether to process armv4 bx instruction relocation.
+ Fix_v4bx fix_v4bx_;
+ // Endianness.
+ Endianness endianness_;
+};
+
+// The position-dependent options. We use this to store the state of
+// the commandline at a particular point in parsing for later
+// reference. For instance, if we see "ld --whole-archive foo.a
+// --no-whole-archive," we want to store the whole-archive option with
+// foo.a, so when the time comes to parse foo.a we know we should do
+// it in whole-archive mode. We could store all of General_options,
+// but that's big, so we just pick the subset of flags that actually
+// change in a position-dependent way.
+
+#define DEFINE_posdep(varname__, type__) \
+ public: \
+ type__ \
+ varname__() const \
+ { return this->varname__##_; } \
+ \
+ void \
+ set_##varname__(type__ value) \
+ { this->varname__##_ = value; } \
+ private: \
+ type__ varname__##_
+
+class Position_dependent_options
+{
+ public:
+ Position_dependent_options(const General_options& options
+ = Position_dependent_options::default_options_)
+ { copy_from_options(options); }
+
+ void copy_from_options(const General_options& options)
+ {
+ this->set_as_needed(options.as_needed());
+ this->set_Bdynamic(options.Bdynamic());
+ this->set_format_enum(options.format_enum());
+ this->set_whole_archive(options.whole_archive());
+ this->set_incremental_disposition(options.incremental_disposition());
+ }
+
+ DEFINE_posdep(as_needed, bool);
+ DEFINE_posdep(Bdynamic, bool);
+ DEFINE_posdep(format_enum, General_options::Object_format);
+ DEFINE_posdep(whole_archive, bool);
+ DEFINE_posdep(incremental_disposition, Incremental_disposition);
+
+ private:
+ // This is a General_options with everything set to its default
+ // value. A Position_dependent_options created with no argument
+ // will take its values from here.
+ static General_options default_options_;
+};
+
+
+// A single file or library argument from the command line.
+
+class Input_file_argument
+{
+ public:
+ enum Input_file_type
+ {
+ // A regular file, name used as-is, not searched.
+ INPUT_FILE_TYPE_FILE,
+ // A library name. When used, "lib" will be prepended and ".so" or
+ // ".a" appended to make a filename, and that filename will be searched
+ // for using the -L paths.
+ INPUT_FILE_TYPE_LIBRARY,
+ // A regular file, name used as-is, but searched using the -L paths.
+ INPUT_FILE_TYPE_SEARCHED_FILE
+ };
+
+ // name: file name or library name
+ // type: the type of this input file.
+ // extra_search_path: an extra directory to look for the file, prior
+ // to checking the normal library search path. If this is "",
+ // then no extra directory is added.
+ // just_symbols: whether this file only defines symbols.
+ // options: The position dependent options at this point in the
+ // command line, such as --whole-archive.
+ Input_file_argument()
+ : name_(), type_(INPUT_FILE_TYPE_FILE), extra_search_path_(""),
+ just_symbols_(false), options_(), arg_serial_(0)
+ { }
+
+ Input_file_argument(const char* name, Input_file_type type,
+ const char* extra_search_path,
+ bool just_symbols,
+ const Position_dependent_options& options)
+ : name_(name), type_(type), extra_search_path_(extra_search_path),
+ just_symbols_(just_symbols), options_(options), arg_serial_(0)
+ { }
+
+ // You can also pass in a General_options instance instead of a
+ // Position_dependent_options. In that case, we extract the
+ // position-independent vars from the General_options and only store
+ // those.
+ Input_file_argument(const char* name, Input_file_type type,
+ const char* extra_search_path,
+ bool just_symbols,
+ const General_options& options)
+ : name_(name), type_(type), extra_search_path_(extra_search_path),
+ just_symbols_(just_symbols), options_(options), arg_serial_(0)
+ { }
+
+ const char*
+ name() const
+ { return this->name_.c_str(); }
+
+ const Position_dependent_options&
+ options() const
+ { return this->options_; }
+
+ bool
+ is_lib() const
+ { return type_ == INPUT_FILE_TYPE_LIBRARY; }
+
+ bool
+ is_searched_file() const
+ { return type_ == INPUT_FILE_TYPE_SEARCHED_FILE; }
+
+ const char*
+ extra_search_path() const
+ {
+ return (this->extra_search_path_.empty()
+ ? NULL
+ : this->extra_search_path_.c_str());
+ }
+
+ // Return whether we should only read symbols from this file.
+ bool
+ just_symbols() const
+ { return this->just_symbols_; }
+
+ // Return whether this file may require a search using the -L
+ // options.
+ bool
+ may_need_search() const
+ {
+ return (this->is_lib()
+ || this->is_searched_file()
+ || !this->extra_search_path_.empty());
+ }
+
+ // Set the serial number for this argument.
+ void
+ set_arg_serial(unsigned int arg_serial)
+ { this->arg_serial_ = arg_serial; }
+
+ // Get the serial number.
+ unsigned int
+ arg_serial() const
+ { return this->arg_serial_; }
+
+ private:
+ // We use std::string, not const char*, here for convenience when
+ // using script files, so that we do not have to preserve the string
+ // in that case.
+ std::string name_;
+ Input_file_type type_;
+ std::string extra_search_path_;
+ bool just_symbols_;
+ Position_dependent_options options_;
+ // A unique index for this file argument in the argument list.
+ unsigned int arg_serial_;
+};
+
+// A file or library, or a group, from the command line.
+
+class Input_argument
+{
+ public:
+ // Create a file or library argument.
+ explicit Input_argument(Input_file_argument file)
+ : is_file_(true), file_(file), group_(NULL), lib_(NULL), script_info_(NULL)
+ { }
+
+ // Create a group argument.
+ explicit Input_argument(Input_file_group* group)
+ : is_file_(false), group_(group), lib_(NULL), script_info_(NULL)
+ { }
+
+ // Create a lib argument.
+ explicit Input_argument(Input_file_lib* lib)
+ : is_file_(false), group_(NULL), lib_(lib), script_info_(NULL)
+ { }
+
+ // Return whether this is a file.
+ bool
+ is_file() const
+ { return this->is_file_; }
+
+ // Return whether this is a group.
+ bool
+ is_group() const
+ { return !this->is_file_ && this->lib_ == NULL; }
+
+ // Return whether this is a lib.
+ bool
+ is_lib() const
+ { return this->lib_ != NULL; }
+
+ // Return the information about the file.
+ const Input_file_argument&
+ file() const
+ {
+ gold_assert(this->is_file_);
+ return this->file_;
+ }
+
+ // Return the information about the group.
+ const Input_file_group*
+ group() const
+ {
+ gold_assert(!this->is_file_);
+ return this->group_;
+ }
+
+ Input_file_group*
+ group()
+ {
+ gold_assert(!this->is_file_);
+ return this->group_;
+ }
+
+ // Return the information about the lib.
+ const Input_file_lib*
+ lib() const
+ {
+ gold_assert(!this->is_file_);
+ gold_assert(this->lib_);
+ return this->lib_;
+ }
+
+ Input_file_lib*
+ lib()
+ {
+ gold_assert(!this->is_file_);
+ gold_assert(this->lib_);
+ return this->lib_;
+ }
+
+ // If a script generated this argument, store a pointer to the script info.
+ // Currently used only for recording incremental link information.
+ void
+ set_script_info(Script_info* info)
+ { this->script_info_ = info; }
+
+ Script_info*
+ script_info() const
+ { return this->script_info_; }
+
+ private:
+ bool is_file_;
+ Input_file_argument file_;
+ Input_file_group* group_;
+ Input_file_lib* lib_;
+ Script_info* script_info_;
+};
+
+typedef std::vector<Input_argument> Input_argument_list;
+
+// A group from the command line. This is a set of arguments within
+// --start-group ... --end-group.
+
+class Input_file_group
+{
+ public:
+ typedef Input_argument_list::const_iterator const_iterator;
+
+ Input_file_group()
+ : files_()
+ { }
+
+ // Add a file to the end of the group.
+ Input_argument&
+ add_file(const Input_file_argument& arg)
+ {
+ this->files_.push_back(Input_argument(arg));
+ return this->files_.back();
+ }
+
+ // Iterators to iterate over the group contents.
+
+ const_iterator
+ begin() const
+ { return this->files_.begin(); }
+
+ const_iterator
+ end() const
+ { return this->files_.end(); }
+
+ private:
+ Input_argument_list files_;
+};
+
+// A lib from the command line. This is a set of arguments within
+// --start-lib ... --end-lib.
+
+class Input_file_lib
+{
+ public:
+ typedef Input_argument_list::const_iterator const_iterator;
+
+ Input_file_lib(const Position_dependent_options& options)
+ : files_(), options_(options)
+ { }
+
+ // Add a file to the end of the lib.
+ Input_argument&
+ add_file(const Input_file_argument& arg)
+ {
+ this->files_.push_back(Input_argument(arg));
+ return this->files_.back();
+ }
+
+ const Position_dependent_options&
+ options() const
+ { return this->options_; }
+
+ // Iterators to iterate over the lib contents.
+
+ const_iterator
+ begin() const
+ { return this->files_.begin(); }
+
+ const_iterator
+ end() const
+ { return this->files_.end(); }
+
+ size_t
+ size() const
+ { return this->files_.size(); }
+
+ private:
+ Input_argument_list files_;
+ Position_dependent_options options_;
+};
+
+// A list of files from the command line or a script.
+
+class Input_arguments
+{
+ public:
+ typedef Input_argument_list::const_iterator const_iterator;
+
+ Input_arguments()
+ : input_argument_list_(), in_group_(false), in_lib_(false), file_count_(0)
+ { }
+
+ // Add a file.
+ Input_argument&
+ add_file(Input_file_argument& arg);
+
+ // Start a group (the --start-group option).
+ void
+ start_group();
+
+ // End a group (the --end-group option).
+ void
+ end_group();
+
+ // Start a lib (the --start-lib option).
+ void
+ start_lib(const Position_dependent_options&);
+
+ // End a lib (the --end-lib option).
+ void
+ end_lib();
+
+ // Return whether we are currently in a group.
+ bool
+ in_group() const
+ { return this->in_group_; }
+
+ // Return whether we are currently in a lib.
+ bool
+ in_lib() const
+ { return this->in_lib_; }
+
+ // The number of entries in the list.
+ int
+ size() const
+ { return this->input_argument_list_.size(); }
+
+ // Iterators to iterate over the list of input files.
+
+ const_iterator
+ begin() const
+ { return this->input_argument_list_.begin(); }
+
+ const_iterator
+ end() const
+ { return this->input_argument_list_.end(); }
+
+ // Return whether the list is empty.
+ bool
+ empty() const
+ { return this->input_argument_list_.empty(); }
+
+ // Return the number of input files. This may be larger than
+ // input_argument_list_.size(), because of files that are part
+ // of groups or libs.
+ int
+ number_of_input_files() const
+ { return this->file_count_; }
+
+ private:
+ Input_argument_list input_argument_list_;
+ bool in_group_;
+ bool in_lib_;
+ unsigned int file_count_;
+};
+
+
+// All the information read from the command line. These are held in
+// three separate structs: one to hold the options (--foo), one to
+// hold the filenames listed on the commandline, and one to hold
+// linker script information. This third is not a subset of the other
+// two because linker scripts can be specified either as options (via
+// -T) or as a file.
+
+class Command_line
+{
+ public:
+ typedef Input_arguments::const_iterator const_iterator;
+
+ Command_line();
+
+ // Process the command line options. This will exit with an
+ // appropriate error message if an unrecognized option is seen.
+ void
+ process(int argc, const char** argv);
+
+ // Process one command-line option. This takes the index of argv to
+ // process, and returns the index for the next option. no_more_options
+ // is set to true if argv[i] is "--".
+ int
+ process_one_option(int argc, const char** argv, int i,
+ bool* no_more_options);
+
+ // Get the general options.
+ const General_options&
+ options() const
+ { return this->options_; }
+
+ // Get the position dependent options.
+ const Position_dependent_options&
+ position_dependent_options() const
+ { return this->position_options_; }
+
+ // Get the linker-script options.
+ Script_options&
+ script_options()
+ { return this->script_options_; }
+
+ // Finalize the version-script options and return them.
+ const Version_script_info&
+ version_script();
+
+ // Get the input files.
+ Input_arguments&
+ inputs()
+ { return this->inputs_; }
+
+ // The number of input files.
+ int
+ number_of_input_files() const
+ { return this->inputs_.number_of_input_files(); }
+
+ // Iterators to iterate over the list of input files.
+
+ const_iterator
+ begin() const
+ { return this->inputs_.begin(); }
+
+ const_iterator
+ end() const
+ { return this->inputs_.end(); }
+
+ private:
+ Command_line(const Command_line&);
+ Command_line& operator=(const Command_line&);
+
+ // This is a dummy class to provide a constructor that runs before
+ // the constructor for the General_options. The Pre_options constructor
+ // is used as a hook to set the flag enabling the options to register
+ // themselves.
+ struct Pre_options {
+ Pre_options();
+ };
+
+ // This must come before options_!
+ Pre_options pre_options_;
+ General_options options_;
+ Position_dependent_options position_options_;
+ Script_options script_options_;
+ Input_arguments inputs_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_OPTIONS_H)
diff --git a/binutils-2.25/gold/output.cc b/binutils-2.25/gold/output.cc
new file mode 100644
index 00000000..348ad646
--- /dev/null
+++ b/binutils-2.25/gold/output.cc
@@ -0,0 +1,5568 @@
+// output.cc -- manage the output file for gold
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
+// Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <algorithm>
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include "libiberty.h"
+
+#include "dwarf.h"
+#include "parameters.h"
+#include "object.h"
+#include "symtab.h"
+#include "reloc.h"
+#include "merge.h"
+#include "descriptors.h"
+#include "layout.h"
+#include "output.h"
+
+// For systems without mmap support.
+#ifndef HAVE_MMAP
+# define mmap gold_mmap
+# define munmap gold_munmap
+# define mremap gold_mremap
+# ifndef MAP_FAILED
+# define MAP_FAILED (reinterpret_cast<void*>(-1))
+# endif
+# ifndef PROT_READ
+# define PROT_READ 0
+# endif
+# ifndef PROT_WRITE
+# define PROT_WRITE 0
+# endif
+# ifndef MAP_PRIVATE
+# define MAP_PRIVATE 0
+# endif
+# ifndef MAP_ANONYMOUS
+# define MAP_ANONYMOUS 0
+# endif
+# ifndef MAP_SHARED
+# define MAP_SHARED 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;
+}
+
+static void *
+gold_mremap(void *, size_t, size_t, int)
+{
+ errno = ENOSYS;
+ return MAP_FAILED;
+}
+
+#endif
+
+#if defined(HAVE_MMAP) && !defined(HAVE_MREMAP)
+# define mremap gold_mremap
+extern "C" void *gold_mremap(void *, size_t, size_t, int);
+#endif
+
+// Some BSD systems still use MAP_ANON instead of MAP_ANONYMOUS
+#ifndef MAP_ANONYMOUS
+# define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#ifndef MREMAP_MAYMOVE
+# define MREMAP_MAYMOVE 1
+#endif
+
+// Mingw does not have S_ISLNK.
+#ifndef S_ISLNK
+# define S_ISLNK(mode) 0
+#endif
+
+namespace gold
+{
+
+// A wrapper around posix_fallocate. If we don't have posix_fallocate,
+// or the --no-posix-fallocate option is set, we try the fallocate
+// system call directly. If that fails, we use ftruncate to set
+// the file size and hope that there is enough disk space.
+
+static int
+gold_fallocate(int o, off_t offset, off_t len)
+{
+#ifdef HAVE_POSIX_FALLOCATE
+ if (parameters->options().posix_fallocate())
+ return ::posix_fallocate(o, offset, len);
+#endif // defined(HAVE_POSIX_FALLOCATE)
+#ifdef HAVE_FALLOCATE
+ if (::fallocate(o, 0, offset, len) == 0)
+ return 0;
+#endif // defined(HAVE_FALLOCATE)
+ if (::ftruncate(o, offset + len) < 0)
+ return errno;
+ return 0;
+}
+
+// Output_data variables.
+
+bool Output_data::allocated_sizes_are_fixed;
+
+// Output_data methods.
+
+Output_data::~Output_data()
+{
+}
+
+// Return the default alignment for the target size.
+
+uint64_t
+Output_data::default_alignment()
+{
+ return Output_data::default_alignment_for_size(
+ parameters->target().get_size());
+}
+
+// Return the default alignment for a size--32 or 64.
+
+uint64_t
+Output_data::default_alignment_for_size(int size)
+{
+ if (size == 32)
+ return 4;
+ else if (size == 64)
+ return 8;
+ else
+ gold_unreachable();
+}
+
+// Output_section_header methods. This currently assumes that the
+// segment and section lists are complete at construction time.
+
+Output_section_headers::Output_section_headers(
+ const Layout* layout,
+ const Layout::Segment_list* segment_list,
+ const Layout::Section_list* section_list,
+ const Layout::Section_list* unattached_section_list,
+ const Stringpool* secnamepool,
+ const Output_section* shstrtab_section)
+ : layout_(layout),
+ segment_list_(segment_list),
+ section_list_(section_list),
+ unattached_section_list_(unattached_section_list),
+ secnamepool_(secnamepool),
+ shstrtab_section_(shstrtab_section)
+{
+}
+
+// Compute the current data size.
+
+off_t
+Output_section_headers::do_size() const
+{
+ // Count all the sections. Start with 1 for the null section.
+ off_t count = 1;
+ if (!parameters->options().relocatable())
+ {
+ for (Layout::Segment_list::const_iterator p =
+ this->segment_list_->begin();
+ p != this->segment_list_->end();
+ ++p)
+ if ((*p)->type() == elfcpp::PT_LOAD)
+ count += (*p)->output_section_count();
+ }
+ else
+ {
+ for (Layout::Section_list::const_iterator p =
+ this->section_list_->begin();
+ p != this->section_list_->end();
+ ++p)
+ if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0)
+ ++count;
+ }
+ count += this->unattached_section_list_->size();
+
+ const int size = parameters->target().get_size();
+ int shdr_size;
+ if (size == 32)
+ shdr_size = elfcpp::Elf_sizes<32>::shdr_size;
+ else if (size == 64)
+ shdr_size = elfcpp::Elf_sizes<64>::shdr_size;
+ else
+ gold_unreachable();
+
+ return count * shdr_size;
+}
+
+// Write out the section headers.
+
+void
+Output_section_headers::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();
+ }
+}
+
+template<int size, bool big_endian>
+void
+Output_section_headers::do_sized_write(Output_file* of)
+{
+ off_t all_shdrs_size = this->data_size();
+ unsigned char* view = of->get_output_view(this->offset(), all_shdrs_size);
+
+ const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+ unsigned char* v = view;
+
+ {
+ typename elfcpp::Shdr_write<size, big_endian> oshdr(v);
+ oshdr.put_sh_name(0);
+ oshdr.put_sh_type(elfcpp::SHT_NULL);
+ oshdr.put_sh_flags(0);
+ oshdr.put_sh_addr(0);
+ oshdr.put_sh_offset(0);
+
+ size_t section_count = (this->data_size()
+ / elfcpp::Elf_sizes<size>::shdr_size);
+ if (section_count < elfcpp::SHN_LORESERVE)
+ oshdr.put_sh_size(0);
+ else
+ oshdr.put_sh_size(section_count);
+
+ unsigned int shstrndx = this->shstrtab_section_->out_shndx();
+ if (shstrndx < elfcpp::SHN_LORESERVE)
+ oshdr.put_sh_link(0);
+ else
+ oshdr.put_sh_link(shstrndx);
+
+ size_t segment_count = this->segment_list_->size();
+ oshdr.put_sh_info(segment_count >= elfcpp::PN_XNUM ? segment_count : 0);
+
+ oshdr.put_sh_addralign(0);
+ oshdr.put_sh_entsize(0);
+ }
+
+ v += shdr_size;
+
+ unsigned int shndx = 1;
+ if (!parameters->options().relocatable())
+ {
+ for (Layout::Segment_list::const_iterator p =
+ this->segment_list_->begin();
+ p != this->segment_list_->end();
+ ++p)
+ v = (*p)->write_section_headers<size, big_endian>(this->layout_,
+ this->secnamepool_,
+ v,
+ &shndx);
+ }
+ else
+ {
+ for (Layout::Section_list::const_iterator p =
+ this->section_list_->begin();
+ p != this->section_list_->end();
+ ++p)
+ {
+ // We do unallocated sections below, except that group
+ // sections have to come first.
+ if (((*p)->flags() & elfcpp::SHF_ALLOC) == 0
+ && (*p)->type() != elfcpp::SHT_GROUP)
+ continue;
+ gold_assert(shndx == (*p)->out_shndx());
+ elfcpp::Shdr_write<size, big_endian> oshdr(v);
+ (*p)->write_header(this->layout_, this->secnamepool_, &oshdr);
+ v += shdr_size;
+ ++shndx;
+ }
+ }
+
+ for (Layout::Section_list::const_iterator p =
+ this->unattached_section_list_->begin();
+ p != this->unattached_section_list_->end();
+ ++p)
+ {
+ // For a relocatable link, we did unallocated group sections
+ // above, since they have to come first.
+ if ((*p)->type() == elfcpp::SHT_GROUP
+ && parameters->options().relocatable())
+ continue;
+ gold_assert(shndx == (*p)->out_shndx());
+ elfcpp::Shdr_write<size, big_endian> oshdr(v);
+ (*p)->write_header(this->layout_, this->secnamepool_, &oshdr);
+ v += shdr_size;
+ ++shndx;
+ }
+
+ of->write_output_view(this->offset(), all_shdrs_size, view);
+}
+
+// Output_segment_header methods.
+
+Output_segment_headers::Output_segment_headers(
+ const Layout::Segment_list& segment_list)
+ : segment_list_(segment_list)
+{
+ this->set_current_data_size_for_child(this->do_size());
+}
+
+void
+Output_segment_headers::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();
+ }
+}
+
+template<int size, bool big_endian>
+void
+Output_segment_headers::do_sized_write(Output_file* of)
+{
+ const int phdr_size = elfcpp::Elf_sizes<size>::phdr_size;
+ off_t all_phdrs_size = this->segment_list_.size() * phdr_size;
+ gold_assert(all_phdrs_size == this->data_size());
+ unsigned char* view = of->get_output_view(this->offset(),
+ all_phdrs_size);
+ unsigned char* v = view;
+ for (Layout::Segment_list::const_iterator p = this->segment_list_.begin();
+ p != this->segment_list_.end();
+ ++p)
+ {
+ elfcpp::Phdr_write<size, big_endian> ophdr(v);
+ (*p)->write_header(&ophdr);
+ v += phdr_size;
+ }
+
+ gold_assert(v - view == all_phdrs_size);
+
+ of->write_output_view(this->offset(), all_phdrs_size, view);
+}
+
+off_t
+Output_segment_headers::do_size() const
+{
+ const int size = parameters->target().get_size();
+ int phdr_size;
+ if (size == 32)
+ phdr_size = elfcpp::Elf_sizes<32>::phdr_size;
+ else if (size == 64)
+ phdr_size = elfcpp::Elf_sizes<64>::phdr_size;
+ else
+ gold_unreachable();
+
+ return this->segment_list_.size() * phdr_size;
+}
+
+// Output_file_header methods.
+
+Output_file_header::Output_file_header(Target* target,
+ const Symbol_table* symtab,
+ const Output_segment_headers* osh)
+ : target_(target),
+ symtab_(symtab),
+ segment_header_(osh),
+ section_header_(NULL),
+ shstrtab_(NULL)
+{
+ this->set_data_size(this->do_size());
+}
+
+// Set the section table information for a file header.
+
+void
+Output_file_header::set_section_info(const Output_section_headers* shdrs,
+ const Output_section* shstrtab)
+{
+ this->section_header_ = shdrs;
+ this->shstrtab_ = shstrtab;
+}
+
+// Write out the file header.
+
+void
+Output_file_header::do_write(Output_file* of)
+{
+ gold_assert(this->offset() == 0);
+
+ 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 out the file header with appropriate size and endianness.
+
+template<int size, bool big_endian>
+void
+Output_file_header::do_sized_write(Output_file* of)
+{
+ gold_assert(this->offset() == 0);
+
+ int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size;
+ unsigned char* view = of->get_output_view(0, ehdr_size);
+ elfcpp::Ehdr_write<size, big_endian> oehdr(view);
+
+ 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);
+
+ elfcpp::ET e_type;
+ if (parameters->options().relocatable())
+ e_type = elfcpp::ET_REL;
+ else if (parameters->options().output_is_position_independent())
+ e_type = elfcpp::ET_DYN;
+ else
+ e_type = elfcpp::ET_EXEC;
+ oehdr.put_e_type(e_type);
+
+ oehdr.put_e_machine(this->target_->machine_code());
+ oehdr.put_e_version(elfcpp::EV_CURRENT);
+
+ oehdr.put_e_entry(this->entry<size>());
+
+ if (this->segment_header_ == NULL)
+ oehdr.put_e_phoff(0);
+ else
+ oehdr.put_e_phoff(this->segment_header_->offset());
+
+ oehdr.put_e_shoff(this->section_header_->offset());
+ oehdr.put_e_flags(this->target_->processor_specific_flags());
+ oehdr.put_e_ehsize(elfcpp::Elf_sizes<size>::ehdr_size);
+
+ if (this->segment_header_ == NULL)
+ {
+ oehdr.put_e_phentsize(0);
+ oehdr.put_e_phnum(0);
+ }
+ else
+ {
+ oehdr.put_e_phentsize(elfcpp::Elf_sizes<size>::phdr_size);
+ size_t phnum = (this->segment_header_->data_size()
+ / elfcpp::Elf_sizes<size>::phdr_size);
+ if (phnum > elfcpp::PN_XNUM)
+ phnum = elfcpp::PN_XNUM;
+ oehdr.put_e_phnum(phnum);
+ }
+
+ oehdr.put_e_shentsize(elfcpp::Elf_sizes<size>::shdr_size);
+ size_t section_count = (this->section_header_->data_size()
+ / elfcpp::Elf_sizes<size>::shdr_size);
+
+ if (section_count < elfcpp::SHN_LORESERVE)
+ oehdr.put_e_shnum(this->section_header_->data_size()
+ / elfcpp::Elf_sizes<size>::shdr_size);
+ else
+ oehdr.put_e_shnum(0);
+
+ unsigned int shstrndx = this->shstrtab_->out_shndx();
+ if (shstrndx < elfcpp::SHN_LORESERVE)
+ oehdr.put_e_shstrndx(this->shstrtab_->out_shndx());
+ else
+ oehdr.put_e_shstrndx(elfcpp::SHN_XINDEX);
+
+ // Let the target adjust the ELF header, e.g., to set EI_OSABI in
+ // the e_ident field.
+ this->target_->adjust_elf_header(view, ehdr_size);
+
+ of->write_output_view(0, ehdr_size, view);
+}
+
+// Return the value to use for the entry address.
+
+template<int size>
+typename elfcpp::Elf_types<size>::Elf_Addr
+Output_file_header::entry()
+{
+ const bool should_issue_warning = (parameters->options().entry() != NULL
+ && !parameters->options().relocatable()
+ && !parameters->options().shared());
+ const char* entry = parameters->entry();
+ Symbol* sym = this->symtab_->lookup(entry);
+
+ typename Sized_symbol<size>::Value_type v;
+ if (sym != NULL)
+ {
+ Sized_symbol<size>* ssym;
+ ssym = this->symtab_->get_sized_symbol<size>(sym);
+ if (!ssym->is_defined() && should_issue_warning)
+ gold_warning("entry symbol '%s' exists but is not defined", entry);
+ v = ssym->value();
+ }
+ else
+ {
+ // We couldn't find the entry symbol. See if we can parse it as
+ // a number. This supports, e.g., -e 0x1000.
+ char* endptr;
+ v = strtoull(entry, &endptr, 0);
+ if (*endptr != '\0')
+ {
+ if (should_issue_warning)
+ gold_warning("cannot find entry symbol '%s'", entry);
+ v = 0;
+ }
+ }
+
+ return v;
+}
+
+// Compute the current data size.
+
+off_t
+Output_file_header::do_size() const
+{
+ const int size = parameters->target().get_size();
+ if (size == 32)
+ return elfcpp::Elf_sizes<32>::ehdr_size;
+ else if (size == 64)
+ return elfcpp::Elf_sizes<64>::ehdr_size;
+ else
+ gold_unreachable();
+}
+
+// Output_data_const methods.
+
+void
+Output_data_const::do_write(Output_file* of)
+{
+ of->write(this->offset(), this->data_.data(), this->data_.size());
+}
+
+// Output_data_const_buffer methods.
+
+void
+Output_data_const_buffer::do_write(Output_file* of)
+{
+ of->write(this->offset(), this->p_, this->data_size());
+}
+
+// Output_section_data methods.
+
+// Record the output section, and set the entry size and such.
+
+void
+Output_section_data::set_output_section(Output_section* os)
+{
+ gold_assert(this->output_section_ == NULL);
+ this->output_section_ = os;
+ this->do_adjust_output_section(os);
+}
+
+// Return the section index of the output section.
+
+unsigned int
+Output_section_data::do_out_shndx() const
+{
+ gold_assert(this->output_section_ != NULL);
+ return this->output_section_->out_shndx();
+}
+
+// Set the alignment, which means we may need to update the alignment
+// of the output section.
+
+void
+Output_section_data::set_addralign(uint64_t addralign)
+{
+ this->addralign_ = addralign;
+ if (this->output_section_ != NULL
+ && this->output_section_->addralign() < addralign)
+ this->output_section_->set_addralign(addralign);
+}
+
+// Output_data_strtab methods.
+
+// Set the final data size.
+
+void
+Output_data_strtab::set_final_data_size()
+{
+ this->strtab_->set_string_offsets();
+ this->set_data_size(this->strtab_->get_strtab_size());
+}
+
+// Write out a string table.
+
+void
+Output_data_strtab::do_write(Output_file* of)
+{
+ this->strtab_->write(of, this->offset());
+}
+
+// Output_reloc methods.
+
+// A reloc against a global symbol.
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ Symbol* gsym,
+ unsigned int type,
+ Output_data* od,
+ Address address,
+ bool is_relative,
+ bool is_symbolless,
+ bool use_plt_offset)
+ : address_(address), local_sym_index_(GSYM_CODE), type_(type),
+ is_relative_(is_relative), is_symbolless_(is_symbolless),
+ is_section_symbol_(false), use_plt_offset_(use_plt_offset), shndx_(INVALID_CODE)
+{
+ // this->type_ is a bitfield; make sure TYPE fits.
+ gold_assert(this->type_ == type);
+ this->u1_.gsym = gsym;
+ this->u2_.od = od;
+ if (dynamic)
+ this->set_needs_dynsym_index();
+}
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ Symbol* gsym,
+ unsigned int type,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx,
+ Address address,
+ bool is_relative,
+ bool is_symbolless,
+ bool use_plt_offset)
+ : address_(address), local_sym_index_(GSYM_CODE), type_(type),
+ is_relative_(is_relative), is_symbolless_(is_symbolless),
+ is_section_symbol_(false), use_plt_offset_(use_plt_offset), shndx_(shndx)
+{
+ gold_assert(shndx != INVALID_CODE);
+ // this->type_ is a bitfield; make sure TYPE fits.
+ gold_assert(this->type_ == type);
+ this->u1_.gsym = gsym;
+ this->u2_.relobj = relobj;
+ if (dynamic)
+ this->set_needs_dynsym_index();
+}
+
+// A reloc against a local symbol.
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index,
+ unsigned int type,
+ Output_data* od,
+ Address address,
+ bool is_relative,
+ bool is_symbolless,
+ bool is_section_symbol,
+ bool use_plt_offset)
+ : address_(address), local_sym_index_(local_sym_index), type_(type),
+ is_relative_(is_relative), is_symbolless_(is_symbolless),
+ is_section_symbol_(is_section_symbol), use_plt_offset_(use_plt_offset),
+ shndx_(INVALID_CODE)
+{
+ gold_assert(local_sym_index != GSYM_CODE
+ && local_sym_index != INVALID_CODE);
+ // this->type_ is a bitfield; make sure TYPE fits.
+ gold_assert(this->type_ == type);
+ this->u1_.relobj = relobj;
+ this->u2_.od = od;
+ if (dynamic)
+ this->set_needs_dynsym_index();
+}
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index,
+ unsigned int type,
+ unsigned int shndx,
+ Address address,
+ bool is_relative,
+ bool is_symbolless,
+ bool is_section_symbol,
+ bool use_plt_offset)
+ : address_(address), local_sym_index_(local_sym_index), type_(type),
+ is_relative_(is_relative), is_symbolless_(is_symbolless),
+ is_section_symbol_(is_section_symbol), use_plt_offset_(use_plt_offset),
+ shndx_(shndx)
+{
+ gold_assert(local_sym_index != GSYM_CODE
+ && local_sym_index != INVALID_CODE);
+ gold_assert(shndx != INVALID_CODE);
+ // this->type_ is a bitfield; make sure TYPE fits.
+ gold_assert(this->type_ == type);
+ this->u1_.relobj = relobj;
+ this->u2_.relobj = relobj;
+ if (dynamic)
+ this->set_needs_dynsym_index();
+}
+
+// A reloc against the STT_SECTION symbol of an output section.
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ Output_section* os,
+ unsigned int type,
+ Output_data* od,
+ Address address,
+ bool is_relative)
+ : address_(address), local_sym_index_(SECTION_CODE), type_(type),
+ is_relative_(is_relative), is_symbolless_(is_relative),
+ is_section_symbol_(true), use_plt_offset_(false), shndx_(INVALID_CODE)
+{
+ // this->type_ is a bitfield; make sure TYPE fits.
+ gold_assert(this->type_ == type);
+ this->u1_.os = os;
+ this->u2_.od = od;
+ if (dynamic)
+ this->set_needs_dynsym_index();
+ else
+ os->set_needs_symtab_index();
+}
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ Output_section* os,
+ unsigned int type,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx,
+ Address address,
+ bool is_relative)
+ : address_(address), local_sym_index_(SECTION_CODE), type_(type),
+ is_relative_(is_relative), is_symbolless_(is_relative),
+ is_section_symbol_(true), use_plt_offset_(false), shndx_(shndx)
+{
+ gold_assert(shndx != INVALID_CODE);
+ // this->type_ is a bitfield; make sure TYPE fits.
+ gold_assert(this->type_ == type);
+ this->u1_.os = os;
+ this->u2_.relobj = relobj;
+ if (dynamic)
+ this->set_needs_dynsym_index();
+ else
+ os->set_needs_symtab_index();
+}
+
+// An absolute or relative relocation.
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ unsigned int type,
+ Output_data* od,
+ Address address,
+ bool is_relative)
+ : address_(address), local_sym_index_(0), type_(type),
+ is_relative_(is_relative), is_symbolless_(false),
+ is_section_symbol_(false), use_plt_offset_(false), shndx_(INVALID_CODE)
+{
+ // this->type_ is a bitfield; make sure TYPE fits.
+ gold_assert(this->type_ == type);
+ this->u1_.relobj = NULL;
+ this->u2_.od = od;
+}
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ unsigned int type,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx,
+ Address address,
+ bool is_relative)
+ : address_(address), local_sym_index_(0), type_(type),
+ is_relative_(is_relative), is_symbolless_(false),
+ is_section_symbol_(false), use_plt_offset_(false), shndx_(shndx)
+{
+ gold_assert(shndx != INVALID_CODE);
+ // this->type_ is a bitfield; make sure TYPE fits.
+ gold_assert(this->type_ == type);
+ this->u1_.relobj = NULL;
+ this->u2_.relobj = relobj;
+}
+
+// A target specific relocation.
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ unsigned int type,
+ void* arg,
+ Output_data* od,
+ Address address)
+ : address_(address), local_sym_index_(TARGET_CODE), type_(type),
+ is_relative_(false), is_symbolless_(false),
+ is_section_symbol_(false), use_plt_offset_(false), shndx_(INVALID_CODE)
+{
+ // this->type_ is a bitfield; make sure TYPE fits.
+ gold_assert(this->type_ == type);
+ this->u1_.arg = arg;
+ this->u2_.od = od;
+}
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ unsigned int type,
+ void* arg,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx,
+ Address address)
+ : address_(address), local_sym_index_(TARGET_CODE), type_(type),
+ is_relative_(false), is_symbolless_(false),
+ is_section_symbol_(false), use_plt_offset_(false), shndx_(shndx)
+{
+ gold_assert(shndx != INVALID_CODE);
+ // this->type_ is a bitfield; make sure TYPE fits.
+ gold_assert(this->type_ == type);
+ this->u1_.arg = arg;
+ this->u2_.relobj = relobj;
+}
+
+// Record that we need a dynamic symbol index for this relocation.
+
+template<bool dynamic, int size, bool big_endian>
+void
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
+set_needs_dynsym_index()
+{
+ if (this->is_symbolless_)
+ return;
+ switch (this->local_sym_index_)
+ {
+ case INVALID_CODE:
+ gold_unreachable();
+
+ case GSYM_CODE:
+ this->u1_.gsym->set_needs_dynsym_entry();
+ break;
+
+ case SECTION_CODE:
+ this->u1_.os->set_needs_dynsym_index();
+ break;
+
+ case TARGET_CODE:
+ // The target must take care of this if necessary.
+ break;
+
+ case 0:
+ break;
+
+ default:
+ {
+ const unsigned int lsi = this->local_sym_index_;
+ Sized_relobj_file<size, big_endian>* relobj =
+ this->u1_.relobj->sized_relobj();
+ gold_assert(relobj != NULL);
+ if (!this->is_section_symbol_)
+ relobj->set_needs_output_dynsym_entry(lsi);
+ else
+ relobj->output_section(lsi)->set_needs_dynsym_index();
+ }
+ break;
+ }
+}
+
+// Get the symbol index of a relocation.
+
+template<bool dynamic, int size, bool big_endian>
+unsigned int
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
+ const
+{
+ unsigned int index;
+ if (this->is_symbolless_)
+ return 0;
+ switch (this->local_sym_index_)
+ {
+ case INVALID_CODE:
+ gold_unreachable();
+
+ case GSYM_CODE:
+ if (this->u1_.gsym == NULL)
+ index = 0;
+ else if (dynamic)
+ index = this->u1_.gsym->dynsym_index();
+ else
+ index = this->u1_.gsym->symtab_index();
+ break;
+
+ case SECTION_CODE:
+ if (dynamic)
+ index = this->u1_.os->dynsym_index();
+ else
+ index = this->u1_.os->symtab_index();
+ break;
+
+ case TARGET_CODE:
+ index = parameters->target().reloc_symbol_index(this->u1_.arg,
+ this->type_);
+ break;
+
+ case 0:
+ // Relocations without symbols use a symbol index of 0.
+ index = 0;
+ break;
+
+ default:
+ {
+ const unsigned int lsi = this->local_sym_index_;
+ Sized_relobj_file<size, big_endian>* relobj =
+ this->u1_.relobj->sized_relobj();
+ gold_assert(relobj != NULL);
+ if (!this->is_section_symbol_)
+ {
+ if (dynamic)
+ index = relobj->dynsym_index(lsi);
+ else
+ index = relobj->symtab_index(lsi);
+ }
+ else
+ {
+ Output_section* os = relobj->output_section(lsi);
+ gold_assert(os != NULL);
+ if (dynamic)
+ index = os->dynsym_index();
+ else
+ index = os->symtab_index();
+ }
+ }
+ break;
+ }
+ gold_assert(index != -1U);
+ return index;
+}
+
+// For a local section symbol, get the address of the offset ADDEND
+// within the input section.
+
+template<bool dynamic, int size, bool big_endian>
+typename elfcpp::Elf_types<size>::Elf_Addr
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
+ local_section_offset(Addend addend) const
+{
+ gold_assert(this->local_sym_index_ != GSYM_CODE
+ && this->local_sym_index_ != SECTION_CODE
+ && this->local_sym_index_ != TARGET_CODE
+ && this->local_sym_index_ != INVALID_CODE
+ && this->local_sym_index_ != 0
+ && this->is_section_symbol_);
+ const unsigned int lsi = this->local_sym_index_;
+ Output_section* os = this->u1_.relobj->output_section(lsi);
+ gold_assert(os != NULL);
+ Address offset = this->u1_.relobj->get_output_section_offset(lsi);
+ if (offset != invalid_address)
+ return offset + addend;
+ // This is a merge section.
+ Sized_relobj_file<size, big_endian>* relobj =
+ this->u1_.relobj->sized_relobj();
+ gold_assert(relobj != NULL);
+ offset = os->output_address(relobj, lsi, addend);
+ gold_assert(offset != invalid_address);
+ return offset;
+}
+
+// Get the output address of a relocation.
+
+template<bool dynamic, int size, bool big_endian>
+typename elfcpp::Elf_types<size>::Elf_Addr
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_address() const
+{
+ Address address = this->address_;
+ if (this->shndx_ != INVALID_CODE)
+ {
+ Output_section* os = this->u2_.relobj->output_section(this->shndx_);
+ gold_assert(os != NULL);
+ Address off = this->u2_.relobj->get_output_section_offset(this->shndx_);
+ if (off != invalid_address)
+ address += os->address() + off;
+ else
+ {
+ Sized_relobj_file<size, big_endian>* relobj =
+ this->u2_.relobj->sized_relobj();
+ gold_assert(relobj != NULL);
+ address = os->output_address(relobj, this->shndx_, address);
+ gold_assert(address != invalid_address);
+ }
+ }
+ else if (this->u2_.od != NULL)
+ address += this->u2_.od->address();
+ return address;
+}
+
+// Write out the offset and info fields of a Rel or Rela relocation
+// entry.
+
+template<bool dynamic, int size, bool big_endian>
+template<typename Write_rel>
+void
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write_rel(
+ Write_rel* wr) const
+{
+ wr->put_r_offset(this->get_address());
+ unsigned int sym_index = this->get_symbol_index();
+ wr->put_r_info(elfcpp::elf_r_info<size>(sym_index, this->type_));
+}
+
+// Write out a Rel relocation.
+
+template<bool dynamic, int size, bool big_endian>
+void
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write(
+ unsigned char* pov) const
+{
+ elfcpp::Rel_write<size, big_endian> orel(pov);
+ this->write_rel(&orel);
+}
+
+// Get the value of the symbol referred to by a Rel relocation.
+
+template<bool dynamic, int size, bool big_endian>
+typename elfcpp::Elf_types<size>::Elf_Addr
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::symbol_value(
+ Addend addend) const
+{
+ if (this->local_sym_index_ == GSYM_CODE)
+ {
+ const Sized_symbol<size>* sym;
+ sym = static_cast<const Sized_symbol<size>*>(this->u1_.gsym);
+ if (this->use_plt_offset_ && sym->has_plt_offset())
+ return parameters->target().plt_address_for_global(sym);
+ else
+ return sym->value() + addend;
+ }
+ if (this->local_sym_index_ == SECTION_CODE)
+ {
+ gold_assert(!this->use_plt_offset_);
+ return this->u1_.os->address() + addend;
+ }
+ gold_assert(this->local_sym_index_ != TARGET_CODE
+ && this->local_sym_index_ != INVALID_CODE
+ && this->local_sym_index_ != 0
+ && !this->is_section_symbol_);
+ const unsigned int lsi = this->local_sym_index_;
+ Sized_relobj_file<size, big_endian>* relobj =
+ this->u1_.relobj->sized_relobj();
+ gold_assert(relobj != NULL);
+ if (this->use_plt_offset_)
+ return parameters->target().plt_address_for_local(relobj, lsi);
+ const Symbol_value<size>* symval = relobj->local_symbol(lsi);
+ return symval->value(relobj, addend);
+}
+
+// Reloc comparison. This function sorts the dynamic relocs for the
+// benefit of the dynamic linker. First we sort all relative relocs
+// to the front. Among relative relocs, we sort by output address.
+// Among non-relative relocs, we sort by symbol index, then by output
+// address.
+
+template<bool dynamic, int size, bool big_endian>
+int
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
+ compare(const Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>& r2)
+ const
+{
+ if (this->is_relative_)
+ {
+ if (!r2.is_relative_)
+ return -1;
+ // Otherwise sort by reloc address below.
+ }
+ else if (r2.is_relative_)
+ return 1;
+ else
+ {
+ unsigned int sym1 = this->get_symbol_index();
+ unsigned int sym2 = r2.get_symbol_index();
+ if (sym1 < sym2)
+ return -1;
+ else if (sym1 > sym2)
+ return 1;
+ // Otherwise sort by reloc address.
+ }
+
+ section_offset_type addr1 = this->get_address();
+ section_offset_type addr2 = r2.get_address();
+ if (addr1 < addr2)
+ return -1;
+ else if (addr1 > addr2)
+ return 1;
+
+ // Final tie breaker, in order to generate the same output on any
+ // host: reloc type.
+ unsigned int type1 = this->type_;
+ unsigned int type2 = r2.type_;
+ if (type1 < type2)
+ return -1;
+ else if (type1 > type2)
+ return 1;
+
+ // These relocs appear to be exactly the same.
+ return 0;
+}
+
+// Write out a Rela relocation.
+
+template<bool dynamic, int size, bool big_endian>
+void
+Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>::write(
+ unsigned char* pov) const
+{
+ elfcpp::Rela_write<size, big_endian> orel(pov);
+ this->rel_.write_rel(&orel);
+ Addend addend = this->addend_;
+ if (this->rel_.is_target_specific())
+ addend = parameters->target().reloc_addend(this->rel_.target_arg(),
+ this->rel_.type(), addend);
+ else if (this->rel_.is_symbolless())
+ addend = this->rel_.symbol_value(addend);
+ else if (this->rel_.is_local_section_symbol())
+ addend = this->rel_.local_section_offset(addend);
+ orel.put_r_addend(addend);
+}
+
+// Output_data_reloc_base methods.
+
+// Adjust the output section.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+void
+Output_data_reloc_base<sh_type, dynamic, size, big_endian>
+ ::do_adjust_output_section(Output_section* os)
+{
+ if (sh_type == elfcpp::SHT_REL)
+ os->set_entsize(elfcpp::Elf_sizes<size>::rel_size);
+ else if (sh_type == elfcpp::SHT_RELA)
+ os->set_entsize(elfcpp::Elf_sizes<size>::rela_size);
+ else
+ gold_unreachable();
+
+ // A STT_GNU_IFUNC symbol may require a IRELATIVE reloc when doing a
+ // static link. The backends will generate a dynamic reloc section
+ // to hold this. In that case we don't want to link to the dynsym
+ // section, because there isn't one.
+ if (!dynamic)
+ os->set_should_link_to_symtab();
+ else if (parameters->doing_static_link())
+ ;
+ else
+ os->set_should_link_to_dynsym();
+}
+
+// Write out relocation data.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+void
+Output_data_reloc_base<sh_type, dynamic, size, big_endian>::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);
+
+ if (this->sort_relocs())
+ {
+ gold_assert(dynamic);
+ std::sort(this->relocs_.begin(), this->relocs_.end(),
+ Sort_relocs_comparison());
+ }
+
+ unsigned char* pov = oview;
+ for (typename Relocs::const_iterator p = this->relocs_.begin();
+ p != this->relocs_.end();
+ ++p)
+ {
+ p->write(pov);
+ pov += reloc_size;
+ }
+
+ gold_assert(pov - oview == oview_size);
+
+ of->write_output_view(off, oview_size, oview);
+
+ // We no longer need the relocation entries.
+ this->relocs_.clear();
+}
+
+// Class Output_relocatable_relocs.
+
+template<int sh_type, int size, bool big_endian>
+void
+Output_relocatable_relocs<sh_type, size, big_endian>::set_final_data_size()
+{
+ this->set_data_size(this->rr_->output_reloc_count()
+ * Reloc_types<sh_type, size, big_endian>::reloc_size);
+}
+
+// class Output_data_group.
+
+template<int size, bool big_endian>
+Output_data_group<size, big_endian>::Output_data_group(
+ Sized_relobj_file<size, big_endian>* relobj,
+ section_size_type entry_count,
+ elfcpp::Elf_Word flags,
+ std::vector<unsigned int>* input_shndxes)
+ : Output_section_data(entry_count * 4, 4, false),
+ relobj_(relobj),
+ flags_(flags)
+{
+ this->input_shndxes_.swap(*input_shndxes);
+}
+
+// Write out the section group, which means translating the section
+// indexes to apply to the output file.
+
+template<int size, bool big_endian>
+void
+Output_data_group<size, big_endian>::do_write(Output_file* of)
+{
+ const off_t off = this->offset();
+ const section_size_type oview_size =
+ convert_to_section_size_type(this->data_size());
+ unsigned char* const oview = of->get_output_view(off, oview_size);
+
+ elfcpp::Elf_Word* contents = reinterpret_cast<elfcpp::Elf_Word*>(oview);
+ elfcpp::Swap<32, big_endian>::writeval(contents, this->flags_);
+ ++contents;
+
+ for (std::vector<unsigned int>::const_iterator p =
+ this->input_shndxes_.begin();
+ p != this->input_shndxes_.end();
+ ++p, ++contents)
+ {
+ Output_section* os = this->relobj_->output_section(*p);
+
+ unsigned int output_shndx;
+ if (os != NULL)
+ output_shndx = os->out_shndx();
+ else
+ {
+ this->relobj_->error(_("section group retained but "
+ "group element discarded"));
+ output_shndx = 0;
+ }
+
+ elfcpp::Swap<32, big_endian>::writeval(contents, output_shndx);
+ }
+
+ size_t wrote = reinterpret_cast<unsigned char*>(contents) - oview;
+ gold_assert(wrote == oview_size);
+
+ of->write_output_view(off, oview_size, oview);
+
+ // We no longer need this information.
+ this->input_shndxes_.clear();
+}
+
+// Output_data_got::Got_entry methods.
+
+// Write out the entry.
+
+template<int got_size, bool big_endian>
+void
+Output_data_got<got_size, big_endian>::Got_entry::write(
+ unsigned int got_indx,
+ unsigned char* pov) const
+{
+ Valtype val = 0;
+
+ switch (this->local_sym_index_)
+ {
+ case GSYM_CODE:
+ {
+ // If the symbol is resolved locally, we need to write out the
+ // link-time value, which will be relocated dynamically by a
+ // RELATIVE relocation.
+ Symbol* gsym = this->u_.gsym;
+ if (this->use_plt_or_tls_offset_ && gsym->has_plt_offset())
+ val = parameters->target().plt_address_for_global(gsym);
+ else
+ {
+ switch (parameters->size_and_endianness())
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+ case Parameters::TARGET_32_LITTLE:
+ case Parameters::TARGET_32_BIG:
+ {
+ // This cast is ugly. We don't want to put a
+ // virtual method in Symbol, because we want Symbol
+ // to be as small as possible.
+ Sized_symbol<32>::Value_type v;
+ v = static_cast<Sized_symbol<32>*>(gsym)->value();
+ val = convert_types<Valtype, Sized_symbol<32>::Value_type>(v);
+ }
+ break;
+#endif
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+ case Parameters::TARGET_64_LITTLE:
+ case Parameters::TARGET_64_BIG:
+ {
+ Sized_symbol<64>::Value_type v;
+ v = static_cast<Sized_symbol<64>*>(gsym)->value();
+ val = convert_types<Valtype, Sized_symbol<64>::Value_type>(v);
+ }
+ break;
+#endif
+ default:
+ gold_unreachable();
+ }
+ if (this->use_plt_or_tls_offset_
+ && gsym->type() == elfcpp::STT_TLS)
+ val += parameters->target().tls_offset_for_global(gsym,
+ got_indx);
+ }
+ }
+ break;
+
+ case CONSTANT_CODE:
+ val = this->u_.constant;
+ break;
+
+ case RESERVED_CODE:
+ // If we're doing an incremental update, don't touch this GOT entry.
+ if (parameters->incremental_update())
+ return;
+ val = this->u_.constant;
+ break;
+
+ default:
+ {
+ const Relobj* object = this->u_.object;
+ const unsigned int lsi = this->local_sym_index_;
+ bool is_tls = object->local_is_tls(lsi);
+ if (this->use_plt_or_tls_offset_ && !is_tls)
+ val = parameters->target().plt_address_for_local(object, lsi);
+ else
+ {
+ uint64_t lval = object->local_symbol_value(lsi, 0);
+ val = convert_types<Valtype, uint64_t>(lval);
+ if (this->use_plt_or_tls_offset_ && is_tls)
+ val += parameters->target().tls_offset_for_local(object, lsi,
+ got_indx);
+ }
+ }
+ break;
+ }
+
+ elfcpp::Swap<got_size, big_endian>::writeval(pov, val);
+}
+
+// Output_data_got methods.
+
+// Add an entry for a global symbol to the GOT. This returns true if
+// this is a new GOT entry, false if the symbol already had a GOT
+// entry.
+
+template<int got_size, bool big_endian>
+bool
+Output_data_got<got_size, big_endian>::add_global(
+ Symbol* gsym,
+ unsigned int got_type)
+{
+ if (gsym->has_got_offset(got_type))
+ return false;
+
+ unsigned int got_offset = this->add_got_entry(Got_entry(gsym, false));
+ gsym->set_got_offset(got_type, got_offset);
+ return true;
+}
+
+// Like add_global, but use the PLT offset.
+
+template<int got_size, bool big_endian>
+bool
+Output_data_got<got_size, big_endian>::add_global_plt(Symbol* gsym,
+ unsigned int got_type)
+{
+ if (gsym->has_got_offset(got_type))
+ return false;
+
+ unsigned int got_offset = this->add_got_entry(Got_entry(gsym, true));
+ gsym->set_got_offset(got_type, got_offset);
+ return true;
+}
+
+// Add an entry for a global symbol to the GOT, and add a dynamic
+// relocation of type R_TYPE for the GOT entry.
+
+template<int got_size, bool big_endian>
+void
+Output_data_got<got_size, big_endian>::add_global_with_rel(
+ Symbol* gsym,
+ unsigned int got_type,
+ Output_data_reloc_generic* rel_dyn,
+ unsigned int r_type)
+{
+ if (gsym->has_got_offset(got_type))
+ return;
+
+ unsigned int got_offset = this->add_got_entry(Got_entry());
+ gsym->set_got_offset(got_type, got_offset);
+ rel_dyn->add_global_generic(gsym, r_type, this, got_offset, 0);
+}
+
+// Add a pair of entries for a global symbol to the GOT, and add
+// dynamic relocations of type R_TYPE_1 and R_TYPE_2, respectively.
+// If R_TYPE_2 == 0, add the second entry with no relocation.
+template<int got_size, bool big_endian>
+void
+Output_data_got<got_size, big_endian>::add_global_pair_with_rel(
+ Symbol* gsym,
+ unsigned int got_type,
+ Output_data_reloc_generic* rel_dyn,
+ unsigned int r_type_1,
+ unsigned int r_type_2)
+{
+ if (gsym->has_got_offset(got_type))
+ return;
+
+ unsigned int got_offset = this->add_got_entry_pair(Got_entry(), Got_entry());
+ gsym->set_got_offset(got_type, got_offset);
+ rel_dyn->add_global_generic(gsym, r_type_1, this, got_offset, 0);
+
+ if (r_type_2 != 0)
+ rel_dyn->add_global_generic(gsym, r_type_2, this,
+ got_offset + got_size / 8, 0);
+}
+
+// Add an entry for a local symbol to the GOT. This returns true if
+// this is a new GOT entry, false if the symbol already has a GOT
+// entry.
+
+template<int got_size, bool big_endian>
+bool
+Output_data_got<got_size, big_endian>::add_local(
+ Relobj* object,
+ unsigned int symndx,
+ unsigned int got_type)
+{
+ if (object->local_has_got_offset(symndx, got_type))
+ return false;
+
+ unsigned int got_offset = this->add_got_entry(Got_entry(object, symndx,
+ false));
+ object->set_local_got_offset(symndx, got_type, got_offset);
+ return true;
+}
+
+// Like add_local, but use the PLT offset.
+
+template<int got_size, bool big_endian>
+bool
+Output_data_got<got_size, big_endian>::add_local_plt(
+ Relobj* object,
+ unsigned int symndx,
+ unsigned int got_type)
+{
+ if (object->local_has_got_offset(symndx, got_type))
+ return false;
+
+ unsigned int got_offset = this->add_got_entry(Got_entry(object, symndx,
+ true));
+ object->set_local_got_offset(symndx, got_type, got_offset);
+ return true;
+}
+
+// Add an entry for a local symbol to the GOT, and add a dynamic
+// relocation of type R_TYPE for the GOT entry.
+
+template<int got_size, bool big_endian>
+void
+Output_data_got<got_size, big_endian>::add_local_with_rel(
+ Relobj* object,
+ unsigned int symndx,
+ unsigned int got_type,
+ Output_data_reloc_generic* rel_dyn,
+ unsigned int r_type)
+{
+ if (object->local_has_got_offset(symndx, got_type))
+ return;
+
+ unsigned int got_offset = this->add_got_entry(Got_entry());
+ object->set_local_got_offset(symndx, got_type, got_offset);
+ rel_dyn->add_local_generic(object, symndx, r_type, this, got_offset, 0);
+}
+
+// Add a pair of entries for a local symbol to the GOT, and add
+// a dynamic relocation of type R_TYPE using the section symbol of
+// the output section to which input section SHNDX maps, on the first.
+// The first got entry will have a value of zero, the second the
+// value of the local symbol.
+template<int got_size, bool big_endian>
+void
+Output_data_got<got_size, big_endian>::add_local_pair_with_rel(
+ Relobj* object,
+ unsigned int symndx,
+ unsigned int shndx,
+ unsigned int got_type,
+ Output_data_reloc_generic* rel_dyn,
+ unsigned int r_type)
+{
+ if (object->local_has_got_offset(symndx, got_type))
+ return;
+
+ unsigned int got_offset =
+ this->add_got_entry_pair(Got_entry(),
+ Got_entry(object, symndx, false));
+ object->set_local_got_offset(symndx, got_type, got_offset);
+ Output_section* os = object->output_section(shndx);
+ rel_dyn->add_output_section_generic(os, r_type, this, got_offset, 0);
+}
+
+// Add a pair of entries for a local symbol to the GOT, and add
+// a dynamic relocation of type R_TYPE using STN_UNDEF on the first.
+// The first got entry will have a value of zero, the second the
+// value of the local symbol offset by Target::tls_offset_for_local.
+template<int got_size, bool big_endian>
+void
+Output_data_got<got_size, big_endian>::add_local_tls_pair(
+ Relobj* object,
+ unsigned int symndx,
+ unsigned int got_type,
+ Output_data_reloc_generic* rel_dyn,
+ unsigned int r_type)
+{
+ if (object->local_has_got_offset(symndx, got_type))
+ return;
+
+ unsigned int got_offset
+ = this->add_got_entry_pair(Got_entry(),
+ Got_entry(object, symndx, true));
+ object->set_local_got_offset(symndx, got_type, got_offset);
+ rel_dyn->add_local_generic(object, 0, r_type, this, got_offset, 0);
+}
+
+// Reserve a slot in the GOT for a local symbol or the second slot of a pair.
+
+template<int got_size, bool big_endian>
+void
+Output_data_got<got_size, big_endian>::reserve_local(
+ unsigned int i,
+ Relobj* object,
+ unsigned int sym_index,
+ unsigned int got_type)
+{
+ this->do_reserve_slot(i);
+ object->set_local_got_offset(sym_index, got_type, this->got_offset(i));
+}
+
+// Reserve a slot in the GOT for a global symbol.
+
+template<int got_size, bool big_endian>
+void
+Output_data_got<got_size, big_endian>::reserve_global(
+ unsigned int i,
+ Symbol* gsym,
+ unsigned int got_type)
+{
+ this->do_reserve_slot(i);
+ gsym->set_got_offset(got_type, this->got_offset(i));
+}
+
+// Write out the GOT.
+
+template<int got_size, bool big_endian>
+void
+Output_data_got<got_size, big_endian>::do_write(Output_file* of)
+{
+ const int add = got_size / 8;
+
+ 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;
+ for (unsigned int i = 0; i < this->entries_.size(); ++i)
+ {
+ this->entries_[i].write(i, pov);
+ pov += add;
+ }
+
+ gold_assert(pov - oview == oview_size);
+
+ of->write_output_view(off, oview_size, oview);
+
+ // We no longer need the GOT entries.
+ this->entries_.clear();
+}
+
+// Create a new GOT entry and return its offset.
+
+template<int got_size, bool big_endian>
+unsigned int
+Output_data_got<got_size, big_endian>::add_got_entry(Got_entry got_entry)
+{
+ if (!this->is_data_size_valid())
+ {
+ this->entries_.push_back(got_entry);
+ this->set_got_size();
+ return this->last_got_offset();
+ }
+ else
+ {
+ // For an incremental update, find an available slot.
+ off_t got_offset = this->free_list_.allocate(got_size / 8,
+ got_size / 8, 0);
+ if (got_offset == -1)
+ gold_fallback(_("out of patch space (GOT);"
+ " relink with --incremental-full"));
+ unsigned int got_index = got_offset / (got_size / 8);
+ gold_assert(got_index < this->entries_.size());
+ this->entries_[got_index] = got_entry;
+ return static_cast<unsigned int>(got_offset);
+ }
+}
+
+// Create a pair of new GOT entries and return the offset of the first.
+
+template<int got_size, bool big_endian>
+unsigned int
+Output_data_got<got_size, big_endian>::add_got_entry_pair(
+ Got_entry got_entry_1,
+ Got_entry got_entry_2)
+{
+ if (!this->is_data_size_valid())
+ {
+ unsigned int got_offset;
+ this->entries_.push_back(got_entry_1);
+ got_offset = this->last_got_offset();
+ this->entries_.push_back(got_entry_2);
+ this->set_got_size();
+ return got_offset;
+ }
+ else
+ {
+ // For an incremental update, find an available pair of slots.
+ off_t got_offset = this->free_list_.allocate(2 * got_size / 8,
+ got_size / 8, 0);
+ if (got_offset == -1)
+ gold_fallback(_("out of patch space (GOT);"
+ " relink with --incremental-full"));
+ unsigned int got_index = got_offset / (got_size / 8);
+ gold_assert(got_index < this->entries_.size());
+ this->entries_[got_index] = got_entry_1;
+ this->entries_[got_index + 1] = got_entry_2;
+ return static_cast<unsigned int>(got_offset);
+ }
+}
+
+// Replace GOT entry I with a new value.
+
+template<int got_size, bool big_endian>
+void
+Output_data_got<got_size, big_endian>::replace_got_entry(
+ unsigned int i,
+ Got_entry got_entry)
+{
+ gold_assert(i < this->entries_.size());
+ this->entries_[i] = got_entry;
+}
+
+// Output_data_dynamic::Dynamic_entry methods.
+
+// Write out the entry.
+
+template<int size, bool big_endian>
+void
+Output_data_dynamic::Dynamic_entry::write(
+ unsigned char* pov,
+ const Stringpool* pool) const
+{
+ typename elfcpp::Elf_types<size>::Elf_WXword val;
+ switch (this->offset_)
+ {
+ case DYNAMIC_NUMBER:
+ val = this->u_.val;
+ break;
+
+ case DYNAMIC_SECTION_SIZE:
+ val = this->u_.od->data_size();
+ if (this->od2 != NULL)
+ val += this->od2->data_size();
+ break;
+
+ case DYNAMIC_SYMBOL:
+ {
+ const Sized_symbol<size>* s =
+ static_cast<const Sized_symbol<size>*>(this->u_.sym);
+ val = s->value();
+ }
+ break;
+
+ case DYNAMIC_STRING:
+ val = pool->get_offset(this->u_.str);
+ break;
+
+ default:
+ val = this->u_.od->address() + this->offset_;
+ break;
+ }
+
+ elfcpp::Dyn_write<size, big_endian> dw(pov);
+ dw.put_d_tag(this->tag_);
+ dw.put_d_val(val);
+}
+
+// Output_data_dynamic methods.
+
+// Adjust the output section to set the entry size.
+
+void
+Output_data_dynamic::do_adjust_output_section(Output_section* os)
+{
+ if (parameters->target().get_size() == 32)
+ os->set_entsize(elfcpp::Elf_sizes<32>::dyn_size);
+ else if (parameters->target().get_size() == 64)
+ os->set_entsize(elfcpp::Elf_sizes<64>::dyn_size);
+ else
+ gold_unreachable();
+}
+
+// Set the final data size.
+
+void
+Output_data_dynamic::set_final_data_size()
+{
+ // Add the terminating entry if it hasn't been added.
+ // Because of relaxation, we can run this multiple times.
+ if (this->entries_.empty() || this->entries_.back().tag() != elfcpp::DT_NULL)
+ {
+ int extra = parameters->options().spare_dynamic_tags();
+ for (int i = 0; i < extra; ++i)
+ this->add_constant(elfcpp::DT_NULL, 0);
+ this->add_constant(elfcpp::DT_NULL, 0);
+ }
+
+ int dyn_size;
+ if (parameters->target().get_size() == 32)
+ dyn_size = elfcpp::Elf_sizes<32>::dyn_size;
+ else if (parameters->target().get_size() == 64)
+ dyn_size = elfcpp::Elf_sizes<64>::dyn_size;
+ else
+ gold_unreachable();
+ this->set_data_size(this->entries_.size() * dyn_size);
+}
+
+// Write out the dynamic entries.
+
+void
+Output_data_dynamic::do_write(Output_file* of)
+{
+ switch (parameters->size_and_endianness())
+ {
+#ifdef HAVE_TARGET_32_LITTLE
+ case Parameters::TARGET_32_LITTLE:
+ this->sized_write<32, false>(of);
+ break;
+#endif
+#ifdef HAVE_TARGET_32_BIG
+ case Parameters::TARGET_32_BIG:
+ this->sized_write<32, true>(of);
+ break;
+#endif
+#ifdef HAVE_TARGET_64_LITTLE
+ case Parameters::TARGET_64_LITTLE:
+ this->sized_write<64, false>(of);
+ break;
+#endif
+#ifdef HAVE_TARGET_64_BIG
+ case Parameters::TARGET_64_BIG:
+ this->sized_write<64, true>(of);
+ break;
+#endif
+ default:
+ gold_unreachable();
+ }
+}
+
+template<int size, bool big_endian>
+void
+Output_data_dynamic::sized_write(Output_file* of)
+{
+ const int dyn_size = elfcpp::Elf_sizes<size>::dyn_size;
+
+ 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);
+
+ unsigned char* pov = oview;
+ for (typename Dynamic_entries::const_iterator p = this->entries_.begin();
+ p != this->entries_.end();
+ ++p)
+ {
+ p->write<size, big_endian>(pov, this->pool_);
+ pov += dyn_size;
+ }
+
+ gold_assert(pov - oview == oview_size);
+
+ of->write_output_view(offset, oview_size, oview);
+
+ // We no longer need the dynamic entries.
+ this->entries_.clear();
+}
+
+// Class Output_symtab_xindex.
+
+void
+Output_symtab_xindex::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);
+
+ memset(oview, 0, oview_size);
+
+ if (parameters->target().is_big_endian())
+ this->endian_do_write<true>(oview);
+ else
+ this->endian_do_write<false>(oview);
+
+ of->write_output_view(offset, oview_size, oview);
+
+ // We no longer need the data.
+ this->entries_.clear();
+}
+
+template<bool big_endian>
+void
+Output_symtab_xindex::endian_do_write(unsigned char* const oview)
+{
+ for (Xindex_entries::const_iterator p = this->entries_.begin();
+ p != this->entries_.end();
+ ++p)
+ {
+ unsigned int symndx = p->first;
+ gold_assert(static_cast<off_t>(symndx) * 4 < this->data_size());
+ elfcpp::Swap<32, big_endian>::writeval(oview + symndx * 4, p->second);
+ }
+}
+
+// Output_fill_debug_info methods.
+
+// Return the minimum size needed for a dummy compilation unit header.
+
+size_t
+Output_fill_debug_info::do_minimum_hole_size() const
+{
+ // Compile unit header fields: unit_length, version, debug_abbrev_offset,
+ // address_size.
+ const size_t len = 4 + 2 + 4 + 1;
+ // For type units, add type_signature, type_offset.
+ if (this->is_debug_types_)
+ return len + 8 + 4;
+ return len;
+}
+
+// Write a dummy compilation unit header to fill a hole in the
+// .debug_info or .debug_types section.
+
+void
+Output_fill_debug_info::do_write(Output_file* of, off_t off, size_t len) const
+{
+ gold_debug(DEBUG_INCREMENTAL, "fill_debug_info(%08lx, %08lx)",
+ static_cast<long>(off), static_cast<long>(len));
+
+ gold_assert(len >= this->do_minimum_hole_size());
+
+ unsigned char* const oview = of->get_output_view(off, len);
+ unsigned char* pov = oview;
+
+ // Write header fields: unit_length, version, debug_abbrev_offset,
+ // address_size.
+ if (this->is_big_endian())
+ {
+ elfcpp::Swap_unaligned<32, true>::writeval(pov, len - 4);
+ elfcpp::Swap_unaligned<16, true>::writeval(pov + 4, this->version);
+ elfcpp::Swap_unaligned<32, true>::writeval(pov + 6, 0);
+ }
+ else
+ {
+ elfcpp::Swap_unaligned<32, false>::writeval(pov, len - 4);
+ elfcpp::Swap_unaligned<16, false>::writeval(pov + 4, this->version);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 6, 0);
+ }
+ pov += 4 + 2 + 4;
+ *pov++ = 4;
+
+ // For type units, the additional header fields -- type_signature,
+ // type_offset -- can be filled with zeroes.
+
+ // Fill the remainder of the free space with zeroes. The first
+ // zero should tell the consumer there are no DIEs to read in this
+ // compilation unit.
+ if (pov < oview + len)
+ memset(pov, 0, oview + len - pov);
+
+ of->write_output_view(off, len, oview);
+}
+
+// Output_fill_debug_line methods.
+
+// Return the minimum size needed for a dummy line number program header.
+
+size_t
+Output_fill_debug_line::do_minimum_hole_size() const
+{
+ // Line number program header fields: unit_length, version, header_length,
+ // minimum_instruction_length, default_is_stmt, line_base, line_range,
+ // opcode_base, standard_opcode_lengths[], include_directories, filenames.
+ const size_t len = 4 + 2 + 4 + this->header_length;
+ return len;
+}
+
+// Write a dummy line number program header to fill a hole in the
+// .debug_line section.
+
+void
+Output_fill_debug_line::do_write(Output_file* of, off_t off, size_t len) const
+{
+ gold_debug(DEBUG_INCREMENTAL, "fill_debug_line(%08lx, %08lx)",
+ static_cast<long>(off), static_cast<long>(len));
+
+ gold_assert(len >= this->do_minimum_hole_size());
+
+ unsigned char* const oview = of->get_output_view(off, len);
+ unsigned char* pov = oview;
+
+ // Write header fields: unit_length, version, header_length,
+ // minimum_instruction_length, default_is_stmt, line_base, line_range,
+ // opcode_base, standard_opcode_lengths[], include_directories, filenames.
+ // We set the header_length field to cover the entire hole, so the
+ // line number program is empty.
+ if (this->is_big_endian())
+ {
+ elfcpp::Swap_unaligned<32, true>::writeval(pov, len - 4);
+ elfcpp::Swap_unaligned<16, true>::writeval(pov + 4, this->version);
+ elfcpp::Swap_unaligned<32, true>::writeval(pov + 6, len - (4 + 2 + 4));
+ }
+ else
+ {
+ elfcpp::Swap_unaligned<32, false>::writeval(pov, len - 4);
+ elfcpp::Swap_unaligned<16, false>::writeval(pov + 4, this->version);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 6, len - (4 + 2 + 4));
+ }
+ pov += 4 + 2 + 4;
+ *pov++ = 1; // minimum_instruction_length
+ *pov++ = 0; // default_is_stmt
+ *pov++ = 0; // line_base
+ *pov++ = 5; // line_range
+ *pov++ = 13; // opcode_base
+ *pov++ = 0; // standard_opcode_lengths[1]
+ *pov++ = 1; // standard_opcode_lengths[2]
+ *pov++ = 1; // standard_opcode_lengths[3]
+ *pov++ = 1; // standard_opcode_lengths[4]
+ *pov++ = 1; // standard_opcode_lengths[5]
+ *pov++ = 0; // standard_opcode_lengths[6]
+ *pov++ = 0; // standard_opcode_lengths[7]
+ *pov++ = 0; // standard_opcode_lengths[8]
+ *pov++ = 1; // standard_opcode_lengths[9]
+ *pov++ = 0; // standard_opcode_lengths[10]
+ *pov++ = 0; // standard_opcode_lengths[11]
+ *pov++ = 1; // standard_opcode_lengths[12]
+ *pov++ = 0; // include_directories (empty)
+ *pov++ = 0; // filenames (empty)
+
+ // Some consumers don't check the header_length field, and simply
+ // start reading the line number program immediately following the
+ // header. For those consumers, we fill the remainder of the free
+ // space with DW_LNS_set_basic_block opcodes. These are effectively
+ // no-ops: the resulting line table program will not create any rows.
+ if (pov < oview + len)
+ memset(pov, elfcpp::DW_LNS_set_basic_block, oview + len - pov);
+
+ of->write_output_view(off, len, oview);
+}
+
+// Output_section::Input_section methods.
+
+// Return the current data size. For an input section we store the size here.
+// For an Output_section_data, we have to ask it for the size.
+
+off_t
+Output_section::Input_section::current_data_size() const
+{
+ if (this->is_input_section())
+ return this->u1_.data_size;
+ else
+ {
+ this->u2_.posd->pre_finalize_data_size();
+ return this->u2_.posd->current_data_size();
+ }
+}
+
+// Return the data size. For an input section we store the size here.
+// For an Output_section_data, we have to ask it for the size.
+
+off_t
+Output_section::Input_section::data_size() const
+{
+ if (this->is_input_section())
+ return this->u1_.data_size;
+ else
+ return this->u2_.posd->data_size();
+}
+
+// Return the object for an input section.
+
+Relobj*
+Output_section::Input_section::relobj() const
+{
+ if (this->is_input_section())
+ return this->u2_.object;
+ else if (this->is_merge_section())
+ {
+ gold_assert(this->u2_.pomb->first_relobj() != NULL);
+ return this->u2_.pomb->first_relobj();
+ }
+ else if (this->is_relaxed_input_section())
+ return this->u2_.poris->relobj();
+ else
+ gold_unreachable();
+}
+
+// Return the input section index for an input section.
+
+unsigned int
+Output_section::Input_section::shndx() const
+{
+ if (this->is_input_section())
+ return this->shndx_;
+ else if (this->is_merge_section())
+ {
+ gold_assert(this->u2_.pomb->first_relobj() != NULL);
+ return this->u2_.pomb->first_shndx();
+ }
+ else if (this->is_relaxed_input_section())
+ return this->u2_.poris->shndx();
+ else
+ gold_unreachable();
+}
+
+// Set the address and file offset.
+
+void
+Output_section::Input_section::set_address_and_file_offset(
+ uint64_t address,
+ off_t file_offset,
+ off_t section_file_offset)
+{
+ if (this->is_input_section())
+ this->u2_.object->set_section_offset(this->shndx_,
+ file_offset - section_file_offset);
+ else
+ this->u2_.posd->set_address_and_file_offset(address, file_offset);
+}
+
+// Reset the address and file offset.
+
+void
+Output_section::Input_section::reset_address_and_file_offset()
+{
+ if (!this->is_input_section())
+ this->u2_.posd->reset_address_and_file_offset();
+}
+
+// Finalize the data size.
+
+void
+Output_section::Input_section::finalize_data_size()
+{
+ if (!this->is_input_section())
+ this->u2_.posd->finalize_data_size();
+}
+
+// Try to turn an input offset into an output offset. We want to
+// return the output offset relative to the start of this
+// Input_section in the output section.
+
+inline bool
+Output_section::Input_section::output_offset(
+ const Relobj* object,
+ unsigned int shndx,
+ section_offset_type offset,
+ section_offset_type* poutput) const
+{
+ if (!this->is_input_section())
+ return this->u2_.posd->output_offset(object, shndx, offset, poutput);
+ else
+ {
+ if (this->shndx_ != shndx || this->u2_.object != object)
+ return false;
+ *poutput = offset;
+ return true;
+ }
+}
+
+// Return whether this is the merge section for the input section
+// SHNDX in OBJECT.
+
+inline bool
+Output_section::Input_section::is_merge_section_for(const Relobj* object,
+ unsigned int shndx) const
+{
+ if (this->is_input_section())
+ return false;
+ return this->u2_.posd->is_merge_section_for(object, shndx);
+}
+
+// Write out the data. We don't have to do anything for an input
+// section--they are handled via Object::relocate--but this is where
+// we write out the data for an Output_section_data.
+
+void
+Output_section::Input_section::write(Output_file* of)
+{
+ if (!this->is_input_section())
+ this->u2_.posd->write(of);
+}
+
+// Write the data to a buffer. As for write(), we don't have to do
+// anything for an input section.
+
+void
+Output_section::Input_section::write_to_buffer(unsigned char* buffer)
+{
+ if (!this->is_input_section())
+ this->u2_.posd->write_to_buffer(buffer);
+}
+
+// Print to a map file.
+
+void
+Output_section::Input_section::print_to_mapfile(Mapfile* mapfile) const
+{
+ switch (this->shndx_)
+ {
+ case OUTPUT_SECTION_CODE:
+ case MERGE_DATA_SECTION_CODE:
+ case MERGE_STRING_SECTION_CODE:
+ this->u2_.posd->print_to_mapfile(mapfile);
+ break;
+
+ case RELAXED_INPUT_SECTION_CODE:
+ {
+ Output_relaxed_input_section* relaxed_section =
+ this->relaxed_input_section();
+ mapfile->print_input_section(relaxed_section->relobj(),
+ relaxed_section->shndx());
+ }
+ break;
+ default:
+ mapfile->print_input_section(this->u2_.object, this->shndx_);
+ break;
+ }
+}
+
+// Output_section methods.
+
+// Construct an Output_section. NAME will point into a Stringpool.
+
+Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
+ elfcpp::Elf_Xword flags)
+ : name_(name),
+ addralign_(0),
+ entsize_(0),
+ load_address_(0),
+ link_section_(NULL),
+ link_(0),
+ info_section_(NULL),
+ info_symndx_(NULL),
+ info_(0),
+ type_(type),
+ flags_(flags),
+ order_(ORDER_INVALID),
+ out_shndx_(-1U),
+ symtab_index_(0),
+ dynsym_index_(0),
+ input_sections_(),
+ first_input_offset_(0),
+ fills_(),
+ postprocessing_buffer_(NULL),
+ needs_symtab_index_(false),
+ needs_dynsym_index_(false),
+ should_link_to_symtab_(false),
+ should_link_to_dynsym_(false),
+ after_input_sections_(false),
+ requires_postprocessing_(false),
+ found_in_sections_clause_(false),
+ has_load_address_(false),
+ info_uses_section_index_(false),
+ input_section_order_specified_(false),
+ may_sort_attached_input_sections_(false),
+ must_sort_attached_input_sections_(false),
+ attached_input_sections_are_sorted_(false),
+ is_relro_(false),
+ is_small_section_(false),
+ is_large_section_(false),
+ generate_code_fills_at_write_(false),
+ is_entsize_zero_(false),
+ section_offsets_need_adjustment_(false),
+ is_noload_(false),
+ always_keeps_input_sections_(false),
+ has_fixed_layout_(false),
+ is_patch_space_allowed_(false),
+ is_unique_segment_(false),
+ tls_offset_(0),
+ extra_segment_flags_(0),
+ segment_alignment_(0),
+ checkpoint_(NULL),
+ lookup_maps_(new Output_section_lookup_maps),
+ free_list_(),
+ free_space_fill_(NULL),
+ patch_space_(0)
+{
+ // An unallocated section has no address. Forcing this means that
+ // we don't need special treatment for symbols defined in debug
+ // sections.
+ if ((flags & elfcpp::SHF_ALLOC) == 0)
+ this->set_address(0);
+}
+
+Output_section::~Output_section()
+{
+ delete this->checkpoint_;
+}
+
+// Set the entry size.
+
+void
+Output_section::set_entsize(uint64_t v)
+{
+ if (this->is_entsize_zero_)
+ ;
+ else if (this->entsize_ == 0)
+ this->entsize_ = v;
+ else if (this->entsize_ != v)
+ {
+ this->entsize_ = 0;
+ this->is_entsize_zero_ = 1;
+ }
+}
+
+// Add the input section SHNDX, with header SHDR, named SECNAME, in
+// OBJECT, to the Output_section. RELOC_SHNDX is the index of a
+// relocation section which applies to this section, or 0 if none, or
+// -1U if more than one. Return the offset of the input section
+// within the output section. Return -1 if the input section will
+// receive special handling. In the normal case we don't always keep
+// track of input sections for an Output_section. Instead, each
+// Object keeps track of the Output_section for each of its input
+// sections. However, if HAVE_SECTIONS_SCRIPT is true, we do keep
+// track of input sections here; this is used when SECTIONS appears in
+// a linker script.
+
+template<int size, bool big_endian>
+off_t
+Output_section::add_input_section(Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int shndx,
+ const char* secname,
+ const elfcpp::Shdr<size, big_endian>& shdr,
+ unsigned int reloc_shndx,
+ bool have_sections_script)
+{
+ elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
+ if ((addralign & (addralign - 1)) != 0)
+ {
+ object->error(_("invalid alignment %lu for section \"%s\""),
+ static_cast<unsigned long>(addralign), secname);
+ addralign = 1;
+ }
+
+ if (addralign > this->addralign_)
+ this->addralign_ = addralign;
+
+ typename elfcpp::Elf_types<size>::Elf_WXword sh_flags = shdr.get_sh_flags();
+ uint64_t entsize = shdr.get_sh_entsize();
+
+ // .debug_str is a mergeable string section, but is not always so
+ // marked by compilers. Mark manually here so we can optimize.
+ if (strcmp(secname, ".debug_str") == 0)
+ {
+ sh_flags |= (elfcpp::SHF_MERGE | elfcpp::SHF_STRINGS);
+ entsize = 1;
+ }
+
+ this->update_flags_for_input_section(sh_flags);
+ this->set_entsize(entsize);
+
+ // If this is a SHF_MERGE section, we pass all the input sections to
+ // a Output_data_merge. We don't try to handle relocations for such
+ // a section. We don't try to handle empty merge sections--they
+ // mess up the mappings, and are useless anyhow.
+ // FIXME: Need to handle merge sections during incremental update.
+ if ((sh_flags & elfcpp::SHF_MERGE) != 0
+ && reloc_shndx == 0
+ && shdr.get_sh_size() > 0
+ && !parameters->incremental())
+ {
+ // Keep information about merged input sections for rebuilding fast
+ // lookup maps if we have sections-script or we do relaxation.
+ bool keeps_input_sections = (this->always_keeps_input_sections_
+ || have_sections_script
+ || parameters->target().may_relax());
+
+ if (this->add_merge_input_section(object, shndx, sh_flags, entsize,
+ addralign, keeps_input_sections))
+ {
+ // Tell the relocation routines that they need to call the
+ // output_offset method to determine the final address.
+ return -1;
+ }
+ }
+
+ section_size_type input_section_size = shdr.get_sh_size();
+ section_size_type uncompressed_size;
+ if (object->section_is_compressed(shndx, &uncompressed_size))
+ input_section_size = uncompressed_size;
+
+ off_t offset_in_section;
+
+ if (this->has_fixed_layout())
+ {
+ // For incremental updates, find a chunk of unused space in the section.
+ offset_in_section = this->free_list_.allocate(input_section_size,
+ addralign, 0);
+ if (offset_in_section == -1)
+ gold_fallback(_("out of patch space in section %s; "
+ "relink with --incremental-full"),
+ this->name());
+ return offset_in_section;
+ }
+
+ offset_in_section = this->current_data_size_for_child();
+ off_t aligned_offset_in_section = align_address(offset_in_section,
+ addralign);
+ this->set_current_data_size_for_child(aligned_offset_in_section
+ + input_section_size);
+
+ // Determine if we want to delay code-fill generation until the output
+ // section is written. When the target is relaxing, we want to delay fill
+ // generating to avoid adjusting them during relaxation. Also, if we are
+ // sorting input sections we must delay fill generation.
+ if (!this->generate_code_fills_at_write_
+ && !have_sections_script
+ && (sh_flags & elfcpp::SHF_EXECINSTR) != 0
+ && parameters->target().has_code_fill()
+ && (parameters->target().may_relax()
+ || layout->is_section_ordering_specified()))
+ {
+ gold_assert(this->fills_.empty());
+ this->generate_code_fills_at_write_ = true;
+ }
+
+ if (aligned_offset_in_section > offset_in_section
+ && !this->generate_code_fills_at_write_
+ && !have_sections_script
+ && (sh_flags & elfcpp::SHF_EXECINSTR) != 0
+ && parameters->target().has_code_fill())
+ {
+ // We need to add some fill data. Using fill_list_ when
+ // possible is an optimization, since we will often have fill
+ // sections without input sections.
+ off_t fill_len = aligned_offset_in_section - offset_in_section;
+ if (this->input_sections_.empty())
+ this->fills_.push_back(Fill(offset_in_section, fill_len));
+ else
+ {
+ std::string fill_data(parameters->target().code_fill(fill_len));
+ Output_data_const* odc = new Output_data_const(fill_data, 1);
+ this->input_sections_.push_back(Input_section(odc));
+ }
+ }
+
+ // We need to keep track of this section if we are already keeping
+ // track of sections, or if we are relaxing. Also, if this is a
+ // section which requires sorting, or which may require sorting in
+ // the future, we keep track of the sections. If the
+ // --section-ordering-file option is used to specify the order of
+ // sections, we need to keep track of sections.
+ if (this->always_keeps_input_sections_
+ || have_sections_script
+ || !this->input_sections_.empty()
+ || this->may_sort_attached_input_sections()
+ || this->must_sort_attached_input_sections()
+ || parameters->options().user_set_Map()
+ || parameters->target().may_relax()
+ || layout->is_section_ordering_specified())
+ {
+ Input_section isecn(object, shndx, input_section_size, addralign);
+ /* If section ordering is requested by specifying a ordering file,
+ using --section-ordering-file, match the section name with
+ a pattern. */
+ if (parameters->options().section_ordering_file())
+ {
+ unsigned int section_order_index =
+ layout->find_section_order_index(std::string(secname));
+ if (section_order_index != 0)
+ {
+ isecn.set_section_order_index(section_order_index);
+ this->set_input_section_order_specified();
+ }
+ }
+ this->input_sections_.push_back(isecn);
+ }
+
+ return aligned_offset_in_section;
+}
+
+// Add arbitrary data to an output section.
+
+void
+Output_section::add_output_section_data(Output_section_data* posd)
+{
+ Input_section inp(posd);
+ this->add_output_section_data(&inp);
+
+ if (posd->is_data_size_valid())
+ {
+ off_t offset_in_section;
+ if (this->has_fixed_layout())
+ {
+ // For incremental updates, find a chunk of unused space.
+ offset_in_section = this->free_list_.allocate(posd->data_size(),
+ posd->addralign(), 0);
+ if (offset_in_section == -1)
+ gold_fallback(_("out of patch space in section %s; "
+ "relink with --incremental-full"),
+ this->name());
+ // Finalize the address and offset now.
+ uint64_t addr = this->address();
+ off_t offset = this->offset();
+ posd->set_address_and_file_offset(addr + offset_in_section,
+ offset + offset_in_section);
+ }
+ else
+ {
+ offset_in_section = this->current_data_size_for_child();
+ off_t aligned_offset_in_section = align_address(offset_in_section,
+ posd->addralign());
+ this->set_current_data_size_for_child(aligned_offset_in_section
+ + posd->data_size());
+ }
+ }
+ else if (this->has_fixed_layout())
+ {
+ // For incremental updates, arrange for the data to have a fixed layout.
+ // This will mean that additions to the data must be allocated from
+ // free space within the containing output section.
+ uint64_t addr = this->address();
+ posd->set_address(addr);
+ posd->set_file_offset(0);
+ // FIXME: This should eventually be unreachable.
+ // gold_unreachable();
+ }
+}
+
+// Add a relaxed input section.
+
+void
+Output_section::add_relaxed_input_section(Layout* layout,
+ Output_relaxed_input_section* poris,
+ const std::string& name)
+{
+ Input_section inp(poris);
+
+ // If the --section-ordering-file option is used to specify the order of
+ // sections, we need to keep track of sections.
+ if (layout->is_section_ordering_specified())
+ {
+ unsigned int section_order_index =
+ layout->find_section_order_index(name);
+ if (section_order_index != 0)
+ {
+ inp.set_section_order_index(section_order_index);
+ this->set_input_section_order_specified();
+ }
+ }
+
+ this->add_output_section_data(&inp);
+ if (this->lookup_maps_->is_valid())
+ this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
+ poris->shndx(), poris);
+
+ // For a relaxed section, we use the current data size. Linker scripts
+ // get all the input sections, including relaxed one from an output
+ // section and add them back to the same output section to compute the
+ // output section size. If we do not account for sizes of relaxed input
+ // sections, an output section would be incorrectly sized.
+ off_t offset_in_section = this->current_data_size_for_child();
+ off_t aligned_offset_in_section = align_address(offset_in_section,
+ poris->addralign());
+ this->set_current_data_size_for_child(aligned_offset_in_section
+ + poris->current_data_size());
+}
+
+// Add arbitrary data to an output section by Input_section.
+
+void
+Output_section::add_output_section_data(Input_section* inp)
+{
+ if (this->input_sections_.empty())
+ this->first_input_offset_ = this->current_data_size_for_child();
+
+ this->input_sections_.push_back(*inp);
+
+ uint64_t addralign = inp->addralign();
+ if (addralign > this->addralign_)
+ this->addralign_ = addralign;
+
+ inp->set_output_section(this);
+}
+
+// Add a merge section to an output section.
+
+void
+Output_section::add_output_merge_section(Output_section_data* posd,
+ bool is_string, uint64_t entsize)
+{
+ Input_section inp(posd, is_string, entsize);
+ this->add_output_section_data(&inp);
+}
+
+// Add an input section to a SHF_MERGE section.
+
+bool
+Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
+ uint64_t flags, uint64_t entsize,
+ uint64_t addralign,
+ bool keeps_input_sections)
+{
+ bool is_string = (flags & elfcpp::SHF_STRINGS) != 0;
+
+ // We cannot restore merged input section states.
+ gold_assert(this->checkpoint_ == NULL);
+
+ // Look up merge sections by required properties.
+ // Currently, we only invalidate the lookup maps in script processing
+ // and relaxation. We should not have done either when we reach here.
+ // So we assume that the lookup maps are valid to simply code.
+ gold_assert(this->lookup_maps_->is_valid());
+ Merge_section_properties msp(is_string, entsize, addralign);
+ Output_merge_base* pomb = this->lookup_maps_->find_merge_section(msp);
+ bool is_new = false;
+ if (pomb != NULL)
+ {
+ gold_assert(pomb->is_string() == is_string
+ && pomb->entsize() == entsize
+ && pomb->addralign() == addralign);
+ }
+ else
+ {
+ // Create a new Output_merge_data or Output_merge_string_data.
+ if (!is_string)
+ pomb = new Output_merge_data(entsize, addralign);
+ else
+ {
+ switch (entsize)
+ {
+ case 1:
+ pomb = new Output_merge_string<char>(addralign);
+ break;
+ case 2:
+ pomb = new Output_merge_string<uint16_t>(addralign);
+ break;
+ case 4:
+ pomb = new Output_merge_string<uint32_t>(addralign);
+ break;
+ default:
+ return false;
+ }
+ }
+ // If we need to do script processing or relaxation, we need to keep
+ // the original input sections to rebuild the fast lookup maps.
+ if (keeps_input_sections)
+ pomb->set_keeps_input_sections();
+ is_new = true;
+ }
+
+ if (pomb->add_input_section(object, shndx))
+ {
+ // Add new merge section to this output section and link merge
+ // section properties to new merge section in map.
+ if (is_new)
+ {
+ this->add_output_merge_section(pomb, is_string, entsize);
+ this->lookup_maps_->add_merge_section(msp, pomb);
+ }
+
+ // Add input section to new merge section and link input section to new
+ // merge section in map.
+ this->lookup_maps_->add_merge_input_section(object, shndx, pomb);
+ return true;
+ }
+ else
+ {
+ // If add_input_section failed, delete new merge section to avoid
+ // exporting empty merge sections in Output_section::get_input_section.
+ if (is_new)
+ delete pomb;
+ return false;
+ }
+}
+
+// Build a relaxation map to speed up relaxation of existing input sections.
+// Look up to the first LIMIT elements in INPUT_SECTIONS.
+
+void
+Output_section::build_relaxation_map(
+ const Input_section_list& input_sections,
+ size_t limit,
+ Relaxation_map* relaxation_map) const
+{
+ for (size_t i = 0; i < limit; ++i)
+ {
+ const Input_section& is(input_sections[i]);
+ if (is.is_input_section() || is.is_relaxed_input_section())
+ {
+ Section_id sid(is.relobj(), is.shndx());
+ (*relaxation_map)[sid] = i;
+ }
+ }
+}
+
+// Convert regular input sections in INPUT_SECTIONS into relaxed input
+// sections in RELAXED_SECTIONS. MAP is a prebuilt map from section id
+// indices of INPUT_SECTIONS.
+
+void
+Output_section::convert_input_sections_in_list_to_relaxed_sections(
+ const std::vector<Output_relaxed_input_section*>& relaxed_sections,
+ const Relaxation_map& map,
+ Input_section_list* input_sections)
+{
+ for (size_t i = 0; i < relaxed_sections.size(); ++i)
+ {
+ Output_relaxed_input_section* poris = relaxed_sections[i];
+ Section_id sid(poris->relobj(), poris->shndx());
+ Relaxation_map::const_iterator p = map.find(sid);
+ gold_assert(p != map.end());
+ gold_assert((*input_sections)[p->second].is_input_section());
+
+ // Remember section order index of original input section
+ // if it is set. Copy it to the relaxed input section.
+ unsigned int soi =
+ (*input_sections)[p->second].section_order_index();
+ (*input_sections)[p->second] = Input_section(poris);
+ (*input_sections)[p->second].set_section_order_index(soi);
+ }
+}
+
+// Convert regular input sections into relaxed input sections. RELAXED_SECTIONS
+// is a vector of pointers to Output_relaxed_input_section or its derived
+// classes. The relaxed sections must correspond to existing input sections.
+
+void
+Output_section::convert_input_sections_to_relaxed_sections(
+ const std::vector<Output_relaxed_input_section*>& relaxed_sections)
+{
+ gold_assert(parameters->target().may_relax());
+
+ // We want to make sure that restore_states does not undo the effect of
+ // this. If there is no checkpoint active, just search the current
+ // input section list and replace the sections there. If there is
+ // a checkpoint, also replace the sections there.
+
+ // By default, we look at the whole list.
+ size_t limit = this->input_sections_.size();
+
+ if (this->checkpoint_ != NULL)
+ {
+ // Replace input sections with relaxed input section in the saved
+ // copy of the input section list.
+ if (this->checkpoint_->input_sections_saved())
+ {
+ Relaxation_map map;
+ this->build_relaxation_map(
+ *(this->checkpoint_->input_sections()),
+ this->checkpoint_->input_sections()->size(),
+ &map);
+ this->convert_input_sections_in_list_to_relaxed_sections(
+ relaxed_sections,
+ map,
+ this->checkpoint_->input_sections());
+ }
+ else
+ {
+ // We have not copied the input section list yet. Instead, just
+ // look at the portion that would be saved.
+ limit = this->checkpoint_->input_sections_size();
+ }
+ }
+
+ // Convert input sections in input_section_list.
+ Relaxation_map map;
+ this->build_relaxation_map(this->input_sections_, limit, &map);
+ this->convert_input_sections_in_list_to_relaxed_sections(
+ relaxed_sections,
+ map,
+ &this->input_sections_);
+
+ // Update fast look-up map.
+ if (this->lookup_maps_->is_valid())
+ for (size_t i = 0; i < relaxed_sections.size(); ++i)
+ {
+ Output_relaxed_input_section* poris = relaxed_sections[i];
+ this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
+ poris->shndx(), poris);
+ }
+}
+
+// Update the output section flags based on input section flags.
+
+void
+Output_section::update_flags_for_input_section(elfcpp::Elf_Xword flags)
+{
+ // If we created the section with SHF_ALLOC clear, we set the
+ // address. If we are now setting the SHF_ALLOC flag, we need to
+ // undo that.
+ if ((this->flags_ & elfcpp::SHF_ALLOC) == 0
+ && (flags & elfcpp::SHF_ALLOC) != 0)
+ this->mark_address_invalid();
+
+ this->flags_ |= (flags
+ & (elfcpp::SHF_WRITE
+ | elfcpp::SHF_ALLOC
+ | elfcpp::SHF_EXECINSTR));
+
+ if ((flags & elfcpp::SHF_MERGE) == 0)
+ this->flags_ &=~ elfcpp::SHF_MERGE;
+ else
+ {
+ if (this->current_data_size_for_child() == 0)
+ this->flags_ |= elfcpp::SHF_MERGE;
+ }
+
+ if ((flags & elfcpp::SHF_STRINGS) == 0)
+ this->flags_ &=~ elfcpp::SHF_STRINGS;
+ else
+ {
+ if (this->current_data_size_for_child() == 0)
+ this->flags_ |= elfcpp::SHF_STRINGS;
+ }
+}
+
+// Find the merge section into which an input section with index SHNDX in
+// OBJECT has been added. Return NULL if none found.
+
+Output_section_data*
+Output_section::find_merge_section(const Relobj* object,
+ unsigned int shndx) const
+{
+ if (!this->lookup_maps_->is_valid())
+ this->build_lookup_maps();
+ return this->lookup_maps_->find_merge_section(object, shndx);
+}
+
+// Build the lookup maps for merge and relaxed sections. This is needs
+// to be declared as a const methods so that it is callable with a const
+// Output_section pointer. The method only updates states of the maps.
+
+void
+Output_section::build_lookup_maps() const
+{
+ this->lookup_maps_->clear();
+ for (Input_section_list::const_iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ if (p->is_merge_section())
+ {
+ Output_merge_base* pomb = p->output_merge_base();
+ Merge_section_properties msp(pomb->is_string(), pomb->entsize(),
+ pomb->addralign());
+ this->lookup_maps_->add_merge_section(msp, pomb);
+ for (Output_merge_base::Input_sections::const_iterator is =
+ pomb->input_sections_begin();
+ is != pomb->input_sections_end();
+ ++is)
+ {
+ const Const_section_id& csid = *is;
+ this->lookup_maps_->add_merge_input_section(csid.first,
+ csid.second, pomb);
+ }
+
+ }
+ else if (p->is_relaxed_input_section())
+ {
+ Output_relaxed_input_section* poris = p->relaxed_input_section();
+ this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
+ poris->shndx(), poris);
+ }
+ }
+}
+
+// Find an relaxed input section corresponding to an input section
+// in OBJECT with index SHNDX.
+
+const Output_relaxed_input_section*
+Output_section::find_relaxed_input_section(const Relobj* object,
+ unsigned int shndx) const
+{
+ if (!this->lookup_maps_->is_valid())
+ this->build_lookup_maps();
+ return this->lookup_maps_->find_relaxed_input_section(object, shndx);
+}
+
+// Given an address OFFSET relative to the start of input section
+// SHNDX in OBJECT, return whether this address is being included in
+// the final link. This should only be called if SHNDX in OBJECT has
+// a special mapping.
+
+bool
+Output_section::is_input_address_mapped(const Relobj* object,
+ unsigned int shndx,
+ off_t offset) const
+{
+ // Look at the Output_section_data_maps first.
+ const Output_section_data* posd = this->find_merge_section(object, shndx);
+ if (posd == NULL)
+ posd = this->find_relaxed_input_section(object, shndx);
+
+ if (posd != NULL)
+ {
+ section_offset_type output_offset;
+ bool found = posd->output_offset(object, shndx, offset, &output_offset);
+ gold_assert(found);
+ return output_offset != -1;
+ }
+
+ // Fall back to the slow look-up.
+ for (Input_section_list::const_iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ section_offset_type output_offset;
+ if (p->output_offset(object, shndx, offset, &output_offset))
+ return output_offset != -1;
+ }
+
+ // By default we assume that the address is mapped. This should
+ // only be called after we have passed all sections to Layout. At
+ // that point we should know what we are discarding.
+ return true;
+}
+
+// Given an address OFFSET relative to the start of input section
+// SHNDX in object OBJECT, return the output offset relative to the
+// start of the input section in the output section. This should only
+// be called if SHNDX in OBJECT has a special mapping.
+
+section_offset_type
+Output_section::output_offset(const Relobj* object, unsigned int shndx,
+ section_offset_type offset) const
+{
+ // This can only be called meaningfully when we know the data size
+ // of this.
+ gold_assert(this->is_data_size_valid());
+
+ // Look at the Output_section_data_maps first.
+ const Output_section_data* posd = this->find_merge_section(object, shndx);
+ if (posd == NULL)
+ posd = this->find_relaxed_input_section(object, shndx);
+ if (posd != NULL)
+ {
+ section_offset_type output_offset;
+ bool found = posd->output_offset(object, shndx, offset, &output_offset);
+ gold_assert(found);
+ return output_offset;
+ }
+
+ // Fall back to the slow look-up.
+ for (Input_section_list::const_iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ section_offset_type output_offset;
+ if (p->output_offset(object, shndx, offset, &output_offset))
+ return output_offset;
+ }
+ gold_unreachable();
+}
+
+// Return the output virtual address of OFFSET relative to the start
+// of input section SHNDX in object OBJECT.
+
+uint64_t
+Output_section::output_address(const Relobj* object, unsigned int shndx,
+ off_t offset) const
+{
+ uint64_t addr = this->address() + this->first_input_offset_;
+
+ // Look at the Output_section_data_maps first.
+ const Output_section_data* posd = this->find_merge_section(object, shndx);
+ if (posd == NULL)
+ posd = this->find_relaxed_input_section(object, shndx);
+ if (posd != NULL && posd->is_address_valid())
+ {
+ section_offset_type output_offset;
+ bool found = posd->output_offset(object, shndx, offset, &output_offset);
+ gold_assert(found);
+ return posd->address() + output_offset;
+ }
+
+ // Fall back to the slow look-up.
+ for (Input_section_list::const_iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ addr = align_address(addr, p->addralign());
+ section_offset_type output_offset;
+ if (p->output_offset(object, shndx, offset, &output_offset))
+ {
+ if (output_offset == -1)
+ return -1ULL;
+ return addr + output_offset;
+ }
+ addr += p->data_size();
+ }
+
+ // If we get here, it means that we don't know the mapping for this
+ // input section. This might happen in principle if
+ // add_input_section were called before add_output_section_data.
+ // But it should never actually happen.
+
+ gold_unreachable();
+}
+
+// Find the output address of the start of the merged section for
+// input section SHNDX in object OBJECT.
+
+bool
+Output_section::find_starting_output_address(const Relobj* object,
+ unsigned int shndx,
+ uint64_t* paddr) const
+{
+ // FIXME: This becomes a bottle-neck if we have many relaxed sections.
+ // Looking up the merge section map does not always work as we sometimes
+ // find a merge section without its address set.
+ uint64_t addr = this->address() + this->first_input_offset_;
+ for (Input_section_list::const_iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ addr = align_address(addr, p->addralign());
+
+ // It would be nice if we could use the existing output_offset
+ // method to get the output offset of input offset 0.
+ // Unfortunately we don't know for sure that input offset 0 is
+ // mapped at all.
+ if (p->is_merge_section_for(object, shndx))
+ {
+ *paddr = addr;
+ return true;
+ }
+
+ addr += p->data_size();
+ }
+
+ // We couldn't find a merge output section for this input section.
+ return false;
+}
+
+// Update the data size of an Output_section.
+
+void
+Output_section::update_data_size()
+{
+ if (this->input_sections_.empty())
+ return;
+
+ if (this->must_sort_attached_input_sections()
+ || this->input_section_order_specified())
+ this->sort_attached_input_sections();
+
+ off_t off = this->first_input_offset_;
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ off = align_address(off, p->addralign());
+ off += p->current_data_size();
+ }
+
+ this->set_current_data_size_for_child(off);
+}
+
+// Set the data size of an Output_section. This is where we handle
+// setting the addresses of any Output_section_data objects.
+
+void
+Output_section::set_final_data_size()
+{
+ off_t data_size;
+
+ if (this->input_sections_.empty())
+ data_size = this->current_data_size_for_child();
+ else
+ {
+ if (this->must_sort_attached_input_sections()
+ || this->input_section_order_specified())
+ this->sort_attached_input_sections();
+
+ uint64_t address = this->address();
+ off_t startoff = this->offset();
+ off_t off = startoff + this->first_input_offset_;
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ off = align_address(off, p->addralign());
+ p->set_address_and_file_offset(address + (off - startoff), off,
+ startoff);
+ off += p->data_size();
+ }
+ data_size = off - startoff;
+ }
+
+ // For full incremental links, we want to allocate some patch space
+ // in most sections for subsequent incremental updates.
+ if (this->is_patch_space_allowed_ && parameters->incremental_full())
+ {
+ double pct = parameters->options().incremental_patch();
+ size_t extra = static_cast<size_t>(data_size * pct);
+ if (this->free_space_fill_ != NULL
+ && this->free_space_fill_->minimum_hole_size() > extra)
+ extra = this->free_space_fill_->minimum_hole_size();
+ off_t new_size = align_address(data_size + extra, this->addralign());
+ this->patch_space_ = new_size - data_size;
+ gold_debug(DEBUG_INCREMENTAL,
+ "set_final_data_size: %08lx + %08lx: section %s",
+ static_cast<long>(data_size),
+ static_cast<long>(this->patch_space_),
+ this->name());
+ data_size = new_size;
+ }
+
+ this->set_data_size(data_size);
+}
+
+// Reset the address and file offset.
+
+void
+Output_section::do_reset_address_and_file_offset()
+{
+ // An unallocated section has no address. Forcing this means that
+ // we don't need special treatment for symbols defined in debug
+ // sections. We do the same in the constructor. This does not
+ // apply to NOLOAD sections though.
+ if (((this->flags_ & elfcpp::SHF_ALLOC) == 0) && !this->is_noload_)
+ this->set_address(0);
+
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ p->reset_address_and_file_offset();
+
+ // Remove any patch space that was added in set_final_data_size.
+ if (this->patch_space_ > 0)
+ {
+ this->set_current_data_size_for_child(this->current_data_size_for_child()
+ - this->patch_space_);
+ this->patch_space_ = 0;
+ }
+}
+
+// Return true if address and file offset have the values after reset.
+
+bool
+Output_section::do_address_and_file_offset_have_reset_values() const
+{
+ if (this->is_offset_valid())
+ return false;
+
+ // An unallocated section has address 0 after its construction or a reset.
+ if ((this->flags_ & elfcpp::SHF_ALLOC) == 0)
+ return this->is_address_valid() && this->address() == 0;
+ else
+ return !this->is_address_valid();
+}
+
+// Set the TLS offset. Called only for SHT_TLS sections.
+
+void
+Output_section::do_set_tls_offset(uint64_t tls_base)
+{
+ this->tls_offset_ = this->address() - tls_base;
+}
+
+// In a few cases we need to sort the input sections attached to an
+// output section. This is used to implement the type of constructor
+// priority ordering implemented by the GNU linker, in which the
+// priority becomes part of the section name and the sections are
+// sorted by name. We only do this for an output section if we see an
+// attached input section matching ".ctors.*", ".dtors.*",
+// ".init_array.*" or ".fini_array.*".
+
+class Output_section::Input_section_sort_entry
+{
+ public:
+ Input_section_sort_entry()
+ : input_section_(), index_(-1U), section_has_name_(false),
+ section_name_()
+ { }
+
+ Input_section_sort_entry(const Input_section& input_section,
+ unsigned int index,
+ bool must_sort_attached_input_sections)
+ : input_section_(input_section), index_(index),
+ section_has_name_(input_section.is_input_section()
+ || input_section.is_relaxed_input_section())
+ {
+ if (this->section_has_name_
+ && must_sort_attached_input_sections)
+ {
+ // This is only called single-threaded from Layout::finalize,
+ // so it is OK to lock. Unfortunately we have no way to pass
+ // in a Task token.
+ const Task* dummy_task = reinterpret_cast<const Task*>(-1);
+ Object* obj = (input_section.is_input_section()
+ ? input_section.relobj()
+ : input_section.relaxed_input_section()->relobj());
+ Task_lock_obj<Object> tl(dummy_task, obj);
+
+ // This is a slow operation, which should be cached in
+ // Layout::layout if this becomes a speed problem.
+ this->section_name_ = obj->section_name(input_section.shndx());
+ }
+ }
+
+ // Return the Input_section.
+ const Input_section&
+ input_section() const
+ {
+ gold_assert(this->index_ != -1U);
+ return this->input_section_;
+ }
+
+ // The index of this entry in the original list. This is used to
+ // make the sort stable.
+ unsigned int
+ index() const
+ {
+ gold_assert(this->index_ != -1U);
+ return this->index_;
+ }
+
+ // Whether there is a section name.
+ bool
+ section_has_name() const
+ { return this->section_has_name_; }
+
+ // The section name.
+ const std::string&
+ section_name() const
+ {
+ gold_assert(this->section_has_name_);
+ return this->section_name_;
+ }
+
+ // Return true if the section name has a priority. This is assumed
+ // to be true if it has a dot after the initial dot.
+ bool
+ has_priority() const
+ {
+ gold_assert(this->section_has_name_);
+ return this->section_name_.find('.', 1) != std::string::npos;
+ }
+
+ // Return the priority. Believe it or not, gcc encodes the priority
+ // differently for .ctors/.dtors and .init_array/.fini_array
+ // sections.
+ unsigned int
+ get_priority() const
+ {
+ gold_assert(this->section_has_name_);
+ bool is_ctors;
+ if (is_prefix_of(".ctors.", this->section_name_.c_str())
+ || is_prefix_of(".dtors.", this->section_name_.c_str()))
+ is_ctors = true;
+ else if (is_prefix_of(".init_array.", this->section_name_.c_str())
+ || is_prefix_of(".fini_array.", this->section_name_.c_str()))
+ is_ctors = false;
+ else
+ return 0;
+ char* end;
+ unsigned long prio = strtoul((this->section_name_.c_str()
+ + (is_ctors ? 7 : 12)),
+ &end, 10);
+ if (*end != '\0')
+ return 0;
+ else if (is_ctors)
+ return 65535 - prio;
+ else
+ return prio;
+ }
+
+ // Return true if this 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
+ match_file_name(const char* file_name) const
+ {
+ if (this->input_section_.is_output_section_data())
+ return false;
+ return Layout::match_file_name(this->input_section_.relobj(), file_name);
+ }
+
+ // Returns 1 if THIS should appear before S in section order, -1 if S
+ // appears before THIS and 0 if they are not comparable.
+ int
+ compare_section_ordering(const Input_section_sort_entry& s) const
+ {
+ unsigned int this_secn_index = this->input_section_.section_order_index();
+ unsigned int s_secn_index = s.input_section().section_order_index();
+ if (this_secn_index > 0 && s_secn_index > 0)
+ {
+ if (this_secn_index < s_secn_index)
+ return 1;
+ else if (this_secn_index > s_secn_index)
+ return -1;
+ }
+ return 0;
+ }
+
+ private:
+ // The Input_section we are sorting.
+ Input_section input_section_;
+ // The index of this Input_section in the original list.
+ unsigned int index_;
+ // Whether this Input_section has a section name--it won't if this
+ // is some random Output_section_data.
+ bool section_has_name_;
+ // The section name if there is one.
+ std::string section_name_;
+};
+
+// Return true if S1 should come before S2 in the output section.
+
+bool
+Output_section::Input_section_sort_compare::operator()(
+ const Output_section::Input_section_sort_entry& s1,
+ const Output_section::Input_section_sort_entry& s2) const
+{
+ // crtbegin.o must come first.
+ bool s1_begin = s1.match_file_name("crtbegin");
+ bool s2_begin = s2.match_file_name("crtbegin");
+ if (s1_begin || s2_begin)
+ {
+ if (!s1_begin)
+ return false;
+ if (!s2_begin)
+ return true;
+ return s1.index() < s2.index();
+ }
+
+ // crtend.o must come last.
+ bool s1_end = s1.match_file_name("crtend");
+ bool s2_end = s2.match_file_name("crtend");
+ if (s1_end || s2_end)
+ {
+ if (!s1_end)
+ return true;
+ if (!s2_end)
+ return false;
+ return s1.index() < s2.index();
+ }
+
+ // We sort all the sections with no names to the end.
+ if (!s1.section_has_name() || !s2.section_has_name())
+ {
+ if (s1.section_has_name())
+ return true;
+ if (s2.section_has_name())
+ return false;
+ return s1.index() < s2.index();
+ }
+
+ // A section with a priority follows a section without a priority.
+ bool s1_has_priority = s1.has_priority();
+ bool s2_has_priority = s2.has_priority();
+ if (s1_has_priority && !s2_has_priority)
+ return false;
+ if (!s1_has_priority && s2_has_priority)
+ return true;
+
+ // Check if a section order exists for these sections through a section
+ // ordering file. If sequence_num is 0, an order does not exist.
+ int sequence_num = s1.compare_section_ordering(s2);
+ if (sequence_num != 0)
+ return sequence_num == 1;
+
+ // Otherwise we sort by name.
+ int compare = s1.section_name().compare(s2.section_name());
+ if (compare != 0)
+ return compare < 0;
+
+ // Otherwise we keep the input order.
+ return s1.index() < s2.index();
+}
+
+// Return true if S1 should come before S2 in an .init_array or .fini_array
+// output section.
+
+bool
+Output_section::Input_section_sort_init_fini_compare::operator()(
+ const Output_section::Input_section_sort_entry& s1,
+ const Output_section::Input_section_sort_entry& s2) const
+{
+ // We sort all the sections with no names to the end.
+ if (!s1.section_has_name() || !s2.section_has_name())
+ {
+ if (s1.section_has_name())
+ return true;
+ if (s2.section_has_name())
+ return false;
+ return s1.index() < s2.index();
+ }
+
+ // A section without a priority follows a section with a priority.
+ // This is the reverse of .ctors and .dtors sections.
+ bool s1_has_priority = s1.has_priority();
+ bool s2_has_priority = s2.has_priority();
+ if (s1_has_priority && !s2_has_priority)
+ return true;
+ if (!s1_has_priority && s2_has_priority)
+ return false;
+
+ // .ctors and .dtors sections without priority come after
+ // .init_array and .fini_array sections without priority.
+ if (!s1_has_priority
+ && (s1.section_name() == ".ctors" || s1.section_name() == ".dtors")
+ && s1.section_name() != s2.section_name())
+ return false;
+ if (!s2_has_priority
+ && (s2.section_name() == ".ctors" || s2.section_name() == ".dtors")
+ && s2.section_name() != s1.section_name())
+ return true;
+
+ // Sort by priority if we can.
+ if (s1_has_priority)
+ {
+ unsigned int s1_prio = s1.get_priority();
+ unsigned int s2_prio = s2.get_priority();
+ if (s1_prio < s2_prio)
+ return true;
+ else if (s1_prio > s2_prio)
+ return false;
+ }
+
+ // Check if a section order exists for these sections through a section
+ // ordering file. If sequence_num is 0, an order does not exist.
+ int sequence_num = s1.compare_section_ordering(s2);
+ if (sequence_num != 0)
+ return sequence_num == 1;
+
+ // Otherwise we sort by name.
+ int compare = s1.section_name().compare(s2.section_name());
+ if (compare != 0)
+ return compare < 0;
+
+ // Otherwise we keep the input order.
+ return s1.index() < s2.index();
+}
+
+// Return true if S1 should come before S2. Sections that do not match
+// any pattern in the section ordering file are placed ahead of the sections
+// that match some pattern.
+
+bool
+Output_section::Input_section_sort_section_order_index_compare::operator()(
+ const Output_section::Input_section_sort_entry& s1,
+ const Output_section::Input_section_sort_entry& s2) const
+{
+ unsigned int s1_secn_index = s1.input_section().section_order_index();
+ unsigned int s2_secn_index = s2.input_section().section_order_index();
+
+ // Keep input order if section ordering cannot determine order.
+ if (s1_secn_index == s2_secn_index)
+ return s1.index() < s2.index();
+
+ return s1_secn_index < s2_secn_index;
+}
+
+// Return true if S1 should come before S2. This is the sort comparison
+// function for .text to sort sections with prefixes
+// .text.{unlikely,exit,startup,hot} before other sections.
+
+bool
+Output_section::Input_section_sort_section_prefix_special_ordering_compare
+ ::operator()(
+ const Output_section::Input_section_sort_entry& s1,
+ const Output_section::Input_section_sort_entry& s2) const
+{
+ // We sort all the sections with no names to the end.
+ if (!s1.section_has_name() || !s2.section_has_name())
+ {
+ if (s1.section_has_name())
+ return true;
+ if (s2.section_has_name())
+ return false;
+ return s1.index() < s2.index();
+ }
+
+ // Some input section names have special ordering requirements.
+ int o1 = Layout::special_ordering_of_input_section(s1.section_name().c_str());
+ int o2 = Layout::special_ordering_of_input_section(s2.section_name().c_str());
+ if (o1 != o2)
+ {
+ if (o1 < 0)
+ return false;
+ else if (o2 < 0)
+ return true;
+ else
+ return o1 < o2;
+ }
+
+ // Keep input order otherwise.
+ return s1.index() < s2.index();
+}
+
+// Return true if S1 should come before S2. This is the sort comparison
+// function for sections to sort them by name.
+
+bool
+Output_section::Input_section_sort_section_name_compare
+ ::operator()(
+ const Output_section::Input_section_sort_entry& s1,
+ const Output_section::Input_section_sort_entry& s2) const
+{
+ // We sort all the sections with no names to the end.
+ if (!s1.section_has_name() || !s2.section_has_name())
+ {
+ if (s1.section_has_name())
+ return true;
+ if (s2.section_has_name())
+ return false;
+ return s1.index() < s2.index();
+ }
+
+ // We sort by name.
+ int compare = s1.section_name().compare(s2.section_name());
+ if (compare != 0)
+ return compare < 0;
+
+ // Keep input order otherwise.
+ return s1.index() < s2.index();
+}
+
+// This updates the section order index of input sections according to the
+// the order specified in the mapping from Section id to order index.
+
+void
+Output_section::update_section_layout(
+ const Section_layout_order* order_map)
+{
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ if (p->is_input_section()
+ || p->is_relaxed_input_section())
+ {
+ Object* obj = (p->is_input_section()
+ ? p->relobj()
+ : p->relaxed_input_section()->relobj());
+ unsigned int shndx = p->shndx();
+ Section_layout_order::const_iterator it
+ = order_map->find(Section_id(obj, shndx));
+ if (it == order_map->end())
+ continue;
+ unsigned int section_order_index = it->second;
+ if (section_order_index != 0)
+ {
+ p->set_section_order_index(section_order_index);
+ this->set_input_section_order_specified();
+ }
+ }
+ }
+}
+
+// Sort the input sections attached to an output section.
+
+void
+Output_section::sort_attached_input_sections()
+{
+ if (this->attached_input_sections_are_sorted_)
+ return;
+
+ if (this->checkpoint_ != NULL
+ && !this->checkpoint_->input_sections_saved())
+ this->checkpoint_->save_input_sections();
+
+ // The only thing we know about an input section is the object and
+ // the section index. We need the section name. Recomputing this
+ // is slow but this is an unusual case. If this becomes a speed
+ // problem we can cache the names as required in Layout::layout.
+
+ // We start by building a larger vector holding a copy of each
+ // Input_section, plus its current index in the list and its name.
+ std::vector<Input_section_sort_entry> sort_list;
+
+ unsigned int i = 0;
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p, ++i)
+ sort_list.push_back(Input_section_sort_entry(*p, i,
+ this->must_sort_attached_input_sections()));
+
+ // Sort the input sections.
+ if (this->must_sort_attached_input_sections())
+ {
+ if (this->type() == elfcpp::SHT_PREINIT_ARRAY
+ || this->type() == elfcpp::SHT_INIT_ARRAY
+ || this->type() == elfcpp::SHT_FINI_ARRAY)
+ std::sort(sort_list.begin(), sort_list.end(),
+ Input_section_sort_init_fini_compare());
+ else if (strcmp(parameters->options().sort_section(), "name") == 0)
+ std::sort(sort_list.begin(), sort_list.end(),
+ Input_section_sort_section_name_compare());
+ else if (strcmp(this->name(), ".text") == 0)
+ std::sort(sort_list.begin(), sort_list.end(),
+ Input_section_sort_section_prefix_special_ordering_compare());
+ else
+ std::sort(sort_list.begin(), sort_list.end(),
+ Input_section_sort_compare());
+ }
+ else
+ {
+ gold_assert(this->input_section_order_specified());
+ std::sort(sort_list.begin(), sort_list.end(),
+ Input_section_sort_section_order_index_compare());
+ }
+
+ // Copy the sorted input sections back to our list.
+ this->input_sections_.clear();
+ for (std::vector<Input_section_sort_entry>::iterator p = sort_list.begin();
+ p != sort_list.end();
+ ++p)
+ this->input_sections_.push_back(p->input_section());
+ sort_list.clear();
+
+ // Remember that we sorted the input sections, since we might get
+ // called again.
+ this->attached_input_sections_are_sorted_ = true;
+}
+
+// Write the section header to *OSHDR.
+
+template<int size, bool big_endian>
+void
+Output_section::write_header(const Layout* layout,
+ const Stringpool* secnamepool,
+ elfcpp::Shdr_write<size, big_endian>* oshdr) const
+{
+ oshdr->put_sh_name(secnamepool->get_offset(this->name_));
+ oshdr->put_sh_type(this->type_);
+
+ elfcpp::Elf_Xword flags = this->flags_;
+ if (this->info_section_ != NULL && this->info_uses_section_index_)
+ flags |= elfcpp::SHF_INFO_LINK;
+ oshdr->put_sh_flags(flags);
+
+ oshdr->put_sh_addr(this->address());
+ oshdr->put_sh_offset(this->offset());
+ oshdr->put_sh_size(this->data_size());
+ if (this->link_section_ != NULL)
+ oshdr->put_sh_link(this->link_section_->out_shndx());
+ else if (this->should_link_to_symtab_)
+ oshdr->put_sh_link(layout->symtab_section_shndx());
+ else if (this->should_link_to_dynsym_)
+ oshdr->put_sh_link(layout->dynsym_section()->out_shndx());
+ else
+ oshdr->put_sh_link(this->link_);
+
+ elfcpp::Elf_Word info;
+ if (this->info_section_ != NULL)
+ {
+ if (this->info_uses_section_index_)
+ info = this->info_section_->out_shndx();
+ else
+ info = this->info_section_->symtab_index();
+ }
+ else if (this->info_symndx_ != NULL)
+ info = this->info_symndx_->symtab_index();
+ else
+ info = this->info_;
+ oshdr->put_sh_info(info);
+
+ oshdr->put_sh_addralign(this->addralign_);
+ oshdr->put_sh_entsize(this->entsize_);
+}
+
+// Write out the data. For input sections the data is written out by
+// Object::relocate, but we have to handle Output_section_data objects
+// here.
+
+void
+Output_section::do_write(Output_file* of)
+{
+ gold_assert(!this->requires_postprocessing());
+
+ // If the target performs relaxation, we delay filler generation until now.
+ gold_assert(!this->generate_code_fills_at_write_ || this->fills_.empty());
+
+ off_t output_section_file_offset = this->offset();
+ for (Fill_list::iterator p = this->fills_.begin();
+ p != this->fills_.end();
+ ++p)
+ {
+ std::string fill_data(parameters->target().code_fill(p->length()));
+ of->write(output_section_file_offset + p->section_offset(),
+ fill_data.data(), fill_data.size());
+ }
+
+ off_t off = this->offset() + this->first_input_offset_;
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ off_t aligned_off = align_address(off, p->addralign());
+ if (this->generate_code_fills_at_write_ && (off != aligned_off))
+ {
+ size_t fill_len = aligned_off - off;
+ std::string fill_data(parameters->target().code_fill(fill_len));
+ of->write(off, fill_data.data(), fill_data.size());
+ }
+
+ p->write(of);
+ off = aligned_off + p->data_size();
+ }
+
+ // For incremental links, fill in unused chunks in debug sections
+ // with dummy compilation unit headers.
+ if (this->free_space_fill_ != NULL)
+ {
+ for (Free_list::Const_iterator p = this->free_list_.begin();
+ p != this->free_list_.end();
+ ++p)
+ {
+ off_t off = p->start_;
+ size_t len = p->end_ - off;
+ this->free_space_fill_->write(of, this->offset() + off, len);
+ }
+ if (this->patch_space_ > 0)
+ {
+ off_t off = this->current_data_size_for_child() - this->patch_space_;
+ this->free_space_fill_->write(of, this->offset() + off,
+ this->patch_space_);
+ }
+ }
+}
+
+// If a section requires postprocessing, create the buffer to use.
+
+void
+Output_section::create_postprocessing_buffer()
+{
+ gold_assert(this->requires_postprocessing());
+
+ if (this->postprocessing_buffer_ != NULL)
+ return;
+
+ if (!this->input_sections_.empty())
+ {
+ off_t off = this->first_input_offset_;
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ off = align_address(off, p->addralign());
+ p->finalize_data_size();
+ off += p->data_size();
+ }
+ this->set_current_data_size_for_child(off);
+ }
+
+ off_t buffer_size = this->current_data_size_for_child();
+ this->postprocessing_buffer_ = new unsigned char[buffer_size];
+}
+
+// Write all the data of an Output_section into the postprocessing
+// buffer. This is used for sections which require postprocessing,
+// such as compression. Input sections are handled by
+// Object::Relocate.
+
+void
+Output_section::write_to_postprocessing_buffer()
+{
+ gold_assert(this->requires_postprocessing());
+
+ // If the target performs relaxation, we delay filler generation until now.
+ gold_assert(!this->generate_code_fills_at_write_ || this->fills_.empty());
+
+ unsigned char* buffer = this->postprocessing_buffer();
+ for (Fill_list::iterator p = this->fills_.begin();
+ p != this->fills_.end();
+ ++p)
+ {
+ std::string fill_data(parameters->target().code_fill(p->length()));
+ memcpy(buffer + p->section_offset(), fill_data.data(),
+ fill_data.size());
+ }
+
+ off_t off = this->first_input_offset_;
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ off_t aligned_off = align_address(off, p->addralign());
+ if (this->generate_code_fills_at_write_ && (off != aligned_off))
+ {
+ size_t fill_len = aligned_off - off;
+ std::string fill_data(parameters->target().code_fill(fill_len));
+ memcpy(buffer + off, fill_data.data(), fill_data.size());
+ }
+
+ p->write_to_buffer(buffer + aligned_off);
+ off = aligned_off + p->data_size();
+ }
+}
+
+// Get the input sections for linker script processing. We leave
+// behind the Output_section_data entries. Note that this may be
+// slightly incorrect for merge sections. We will leave them behind,
+// but it is possible that the script says that they should follow
+// some other input sections, as in:
+// .rodata { *(.rodata) *(.rodata.cst*) }
+// For that matter, we don't handle this correctly:
+// .rodata { foo.o(.rodata.cst*) *(.rodata.cst*) }
+// With luck this will never matter.
+
+uint64_t
+Output_section::get_input_sections(
+ uint64_t address,
+ const std::string& fill,
+ std::list<Input_section>* input_sections)
+{
+ if (this->checkpoint_ != NULL
+ && !this->checkpoint_->input_sections_saved())
+ this->checkpoint_->save_input_sections();
+
+ // Invalidate fast look-up maps.
+ this->lookup_maps_->invalidate();
+
+ uint64_t orig_address = address;
+
+ address = align_address(address, this->addralign());
+
+ Input_section_list remaining;
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ if (p->is_input_section()
+ || p->is_relaxed_input_section()
+ || p->is_merge_section())
+ input_sections->push_back(*p);
+ else
+ {
+ uint64_t aligned_address = align_address(address, p->addralign());
+ if (aligned_address != address && !fill.empty())
+ {
+ section_size_type length =
+ convert_to_section_size_type(aligned_address - address);
+ std::string this_fill;
+ this_fill.reserve(length);
+ while (this_fill.length() + fill.length() <= length)
+ this_fill += fill;
+ if (this_fill.length() < length)
+ this_fill.append(fill, 0, length - this_fill.length());
+
+ Output_section_data* posd = new Output_data_const(this_fill, 0);
+ remaining.push_back(Input_section(posd));
+ }
+ address = aligned_address;
+
+ remaining.push_back(*p);
+
+ p->finalize_data_size();
+ address += p->data_size();
+ }
+ }
+
+ this->input_sections_.swap(remaining);
+ this->first_input_offset_ = 0;
+
+ uint64_t data_size = address - orig_address;
+ this->set_current_data_size_for_child(data_size);
+ return data_size;
+}
+
+// Add a script input section. SIS is an Output_section::Input_section,
+// which can be either a plain input section or a special input section like
+// a relaxed input section. For a special input section, its size must be
+// finalized.
+
+void
+Output_section::add_script_input_section(const Input_section& sis)
+{
+ uint64_t data_size = sis.data_size();
+ uint64_t addralign = sis.addralign();
+ if (addralign > this->addralign_)
+ this->addralign_ = addralign;
+
+ off_t offset_in_section = this->current_data_size_for_child();
+ off_t aligned_offset_in_section = align_address(offset_in_section,
+ addralign);
+
+ this->set_current_data_size_for_child(aligned_offset_in_section
+ + data_size);
+
+ this->input_sections_.push_back(sis);
+
+ // Update fast lookup maps if necessary.
+ if (this->lookup_maps_->is_valid())
+ {
+ if (sis.is_merge_section())
+ {
+ Output_merge_base* pomb = sis.output_merge_base();
+ Merge_section_properties msp(pomb->is_string(), pomb->entsize(),
+ pomb->addralign());
+ this->lookup_maps_->add_merge_section(msp, pomb);
+ for (Output_merge_base::Input_sections::const_iterator p =
+ pomb->input_sections_begin();
+ p != pomb->input_sections_end();
+ ++p)
+ this->lookup_maps_->add_merge_input_section(p->first, p->second,
+ pomb);
+ }
+ else if (sis.is_relaxed_input_section())
+ {
+ Output_relaxed_input_section* poris = sis.relaxed_input_section();
+ this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
+ poris->shndx(), poris);
+ }
+ }
+}
+
+// Save states for relaxation.
+
+void
+Output_section::save_states()
+{
+ gold_assert(this->checkpoint_ == NULL);
+ Checkpoint_output_section* checkpoint =
+ new Checkpoint_output_section(this->addralign_, this->flags_,
+ this->input_sections_,
+ this->first_input_offset_,
+ this->attached_input_sections_are_sorted_);
+ this->checkpoint_ = checkpoint;
+ gold_assert(this->fills_.empty());
+}
+
+void
+Output_section::discard_states()
+{
+ gold_assert(this->checkpoint_ != NULL);
+ delete this->checkpoint_;
+ this->checkpoint_ = NULL;
+ gold_assert(this->fills_.empty());
+
+ // Simply invalidate the fast lookup maps since we do not keep
+ // track of them.
+ this->lookup_maps_->invalidate();
+}
+
+void
+Output_section::restore_states()
+{
+ gold_assert(this->checkpoint_ != NULL);
+ Checkpoint_output_section* checkpoint = this->checkpoint_;
+
+ this->addralign_ = checkpoint->addralign();
+ this->flags_ = checkpoint->flags();
+ this->first_input_offset_ = checkpoint->first_input_offset();
+
+ if (!checkpoint->input_sections_saved())
+ {
+ // If we have not copied the input sections, just resize it.
+ size_t old_size = checkpoint->input_sections_size();
+ gold_assert(this->input_sections_.size() >= old_size);
+ this->input_sections_.resize(old_size);
+ }
+ else
+ {
+ // We need to copy the whole list. This is not efficient for
+ // extremely large output with hundreads of thousands of input
+ // objects. We may need to re-think how we should pass sections
+ // to scripts.
+ this->input_sections_ = *checkpoint->input_sections();
+ }
+
+ this->attached_input_sections_are_sorted_ =
+ checkpoint->attached_input_sections_are_sorted();
+
+ // Simply invalidate the fast lookup maps since we do not keep
+ // track of them.
+ this->lookup_maps_->invalidate();
+}
+
+// Update the section offsets of input sections in this. This is required if
+// relaxation causes some input sections to change sizes.
+
+void
+Output_section::adjust_section_offsets()
+{
+ if (!this->section_offsets_need_adjustment_)
+ return;
+
+ off_t off = 0;
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ off = align_address(off, p->addralign());
+ if (p->is_input_section())
+ p->relobj()->set_section_offset(p->shndx(), off);
+ off += p->data_size();
+ }
+
+ this->section_offsets_need_adjustment_ = false;
+}
+
+// Print to the map file.
+
+void
+Output_section::do_print_to_mapfile(Mapfile* mapfile) const
+{
+ mapfile->print_output_section(this);
+
+ for (Input_section_list::const_iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ p->print_to_mapfile(mapfile);
+}
+
+// Print stats for merge sections to stderr.
+
+void
+Output_section::print_merge_stats()
+{
+ Input_section_list::iterator p;
+ for (p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ p->print_merge_stats(this->name_);
+}
+
+// Set a fixed layout for the section. Used for incremental update links.
+
+void
+Output_section::set_fixed_layout(uint64_t sh_addr, off_t sh_offset,
+ off_t sh_size, uint64_t sh_addralign)
+{
+ this->addralign_ = sh_addralign;
+ this->set_current_data_size(sh_size);
+ if ((this->flags_ & elfcpp::SHF_ALLOC) != 0)
+ this->set_address(sh_addr);
+ this->set_file_offset(sh_offset);
+ this->finalize_data_size();
+ this->free_list_.init(sh_size, false);
+ this->has_fixed_layout_ = true;
+}
+
+// Reserve space within the fixed layout for the section. Used for
+// incremental update links.
+
+void
+Output_section::reserve(uint64_t sh_offset, uint64_t sh_size)
+{
+ this->free_list_.remove(sh_offset, sh_offset + sh_size);
+}
+
+// Allocate space from the free list for the section. Used for
+// incremental update links.
+
+off_t
+Output_section::allocate(off_t len, uint64_t addralign)
+{
+ return this->free_list_.allocate(len, addralign, 0);
+}
+
+// Output segment methods.
+
+Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
+ : vaddr_(0),
+ paddr_(0),
+ memsz_(0),
+ max_align_(0),
+ min_p_align_(0),
+ offset_(0),
+ filesz_(0),
+ type_(type),
+ flags_(flags),
+ is_max_align_known_(false),
+ are_addresses_set_(false),
+ is_large_data_segment_(false),
+ is_unique_segment_(false)
+{
+ // The ELF ABI specifies that a PT_TLS segment always has PF_R as
+ // the flags.
+ if (type == elfcpp::PT_TLS)
+ this->flags_ = elfcpp::PF_R;
+}
+
+// Add an Output_section to a PT_LOAD Output_segment.
+
+void
+Output_segment::add_output_section_to_load(Layout* layout,
+ Output_section* os,
+ elfcpp::Elf_Word seg_flags)
+{
+ gold_assert(this->type() == elfcpp::PT_LOAD);
+ gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
+ gold_assert(!this->is_max_align_known_);
+ gold_assert(os->is_large_data_section() == this->is_large_data_segment());
+
+ this->update_flags_for_output_section(seg_flags);
+
+ // We don't want to change the ordering if we have a linker script
+ // with a SECTIONS clause.
+ Output_section_order order = os->order();
+ if (layout->script_options()->saw_sections_clause())
+ order = static_cast<Output_section_order>(0);
+ else
+ gold_assert(order != ORDER_INVALID);
+
+ this->output_lists_[order].push_back(os);
+}
+
+// Add an Output_section to a non-PT_LOAD Output_segment.
+
+void
+Output_segment::add_output_section_to_nonload(Output_section* os,
+ elfcpp::Elf_Word seg_flags)
+{
+ gold_assert(this->type() != elfcpp::PT_LOAD);
+ gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
+ gold_assert(!this->is_max_align_known_);
+
+ this->update_flags_for_output_section(seg_flags);
+
+ this->output_lists_[0].push_back(os);
+}
+
+// Remove an Output_section from this segment. It is an error if it
+// is not present.
+
+void
+Output_segment::remove_output_section(Output_section* os)
+{
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ {
+ Output_data_list* pdl = &this->output_lists_[i];
+ for (Output_data_list::iterator p = pdl->begin(); p != pdl->end(); ++p)
+ {
+ if (*p == os)
+ {
+ pdl->erase(p);
+ return;
+ }
+ }
+ }
+ gold_unreachable();
+}
+
+// Add an Output_data (which need not be an Output_section) to the
+// start of a segment.
+
+void
+Output_segment::add_initial_output_data(Output_data* od)
+{
+ gold_assert(!this->is_max_align_known_);
+ Output_data_list::iterator p = this->output_lists_[0].begin();
+ this->output_lists_[0].insert(p, od);
+}
+
+// Return true if this segment has any sections which hold actual
+// data, rather than being a BSS section.
+
+bool
+Output_segment::has_any_data_sections() const
+{
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ {
+ const Output_data_list* pdl = &this->output_lists_[i];
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if (!(*p)->is_section())
+ return true;
+ if ((*p)->output_section()->type() != elfcpp::SHT_NOBITS)
+ return true;
+ }
+ }
+ return false;
+}
+
+// Return whether the first data section (not counting TLS sections)
+// is a relro section.
+
+bool
+Output_segment::is_first_section_relro() const
+{
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ {
+ if (i == static_cast<int>(ORDER_TLS_DATA)
+ || i == static_cast<int>(ORDER_TLS_BSS))
+ continue;
+ const Output_data_list* pdl = &this->output_lists_[i];
+ if (!pdl->empty())
+ {
+ Output_data* p = pdl->front();
+ return p->is_section() && p->output_section()->is_relro();
+ }
+ }
+ return false;
+}
+
+// Return the maximum alignment of the Output_data in Output_segment.
+
+uint64_t
+Output_segment::maximum_alignment()
+{
+ if (!this->is_max_align_known_)
+ {
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ {
+ const Output_data_list* pdl = &this->output_lists_[i];
+ uint64_t addralign = Output_segment::maximum_alignment_list(pdl);
+ if (addralign > this->max_align_)
+ this->max_align_ = addralign;
+ }
+ this->is_max_align_known_ = true;
+ }
+
+ return this->max_align_;
+}
+
+// Return the maximum alignment of a list of Output_data.
+
+uint64_t
+Output_segment::maximum_alignment_list(const Output_data_list* pdl)
+{
+ uint64_t ret = 0;
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ uint64_t addralign = (*p)->addralign();
+ if (addralign > ret)
+ ret = addralign;
+ }
+ return ret;
+}
+
+// Return whether this segment has any dynamic relocs.
+
+bool
+Output_segment::has_dynamic_reloc() const
+{
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ if (this->has_dynamic_reloc_list(&this->output_lists_[i]))
+ return true;
+ return false;
+}
+
+// Return whether this Output_data_list has any dynamic relocs.
+
+bool
+Output_segment::has_dynamic_reloc_list(const Output_data_list* pdl) const
+{
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ if ((*p)->has_dynamic_reloc())
+ return true;
+ return false;
+}
+
+// Set the section addresses for an Output_segment. If RESET is true,
+// reset the addresses first. ADDR is the address and *POFF is the
+// file offset. Set the section indexes starting with *PSHNDX.
+// INCREASE_RELRO is the size of the portion of the first non-relro
+// section that should be included in the PT_GNU_RELRO segment.
+// If this segment has relro sections, and has been aligned for
+// that purpose, set *HAS_RELRO to TRUE. Return the address of
+// the immediately following segment. Update *HAS_RELRO, *POFF,
+// and *PSHNDX.
+
+uint64_t
+Output_segment::set_section_addresses(const Target* target,
+ Layout* layout, bool reset,
+ uint64_t addr,
+ unsigned int* increase_relro,
+ bool* has_relro,
+ off_t* poff,
+ unsigned int* pshndx)
+{
+ gold_assert(this->type_ == elfcpp::PT_LOAD);
+
+ uint64_t last_relro_pad = 0;
+ off_t orig_off = *poff;
+
+ bool in_tls = false;
+
+ // If we have relro sections, we need to pad forward now so that the
+ // relro sections plus INCREASE_RELRO end on an abi page boundary.
+ if (parameters->options().relro()
+ && this->is_first_section_relro()
+ && (!this->are_addresses_set_ || reset))
+ {
+ uint64_t relro_size = 0;
+ off_t off = *poff;
+ uint64_t max_align = 0;
+ for (int i = 0; i <= static_cast<int>(ORDER_RELRO_LAST); ++i)
+ {
+ Output_data_list* pdl = &this->output_lists_[i];
+ Output_data_list::iterator p;
+ for (p = pdl->begin(); p != pdl->end(); ++p)
+ {
+ if (!(*p)->is_section())
+ break;
+ uint64_t align = (*p)->addralign();
+ if (align > max_align)
+ max_align = align;
+ if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
+ in_tls = true;
+ else if (in_tls)
+ {
+ // Align the first non-TLS section to the alignment
+ // of the TLS segment.
+ align = max_align;
+ in_tls = false;
+ }
+ relro_size = align_address(relro_size, align);
+ // Ignore the size of the .tbss section.
+ if ((*p)->is_section_flag_set(elfcpp::SHF_TLS)
+ && (*p)->is_section_type(elfcpp::SHT_NOBITS))
+ continue;
+ if ((*p)->is_address_valid())
+ relro_size += (*p)->data_size();
+ else
+ {
+ // FIXME: This could be faster.
+ (*p)->set_address_and_file_offset(addr + relro_size,
+ off + relro_size);
+ relro_size += (*p)->data_size();
+ (*p)->reset_address_and_file_offset();
+ }
+ }
+ if (p != pdl->end())
+ break;
+ }
+ relro_size += *increase_relro;
+ // Pad the total relro size to a multiple of the maximum
+ // section alignment seen.
+ uint64_t aligned_size = align_address(relro_size, max_align);
+ // Note the amount of padding added after the last relro section.
+ last_relro_pad = aligned_size - relro_size;
+ *has_relro = true;
+
+ uint64_t page_align = parameters->target().abi_pagesize();
+
+ // Align to offset N such that (N + RELRO_SIZE) % PAGE_ALIGN == 0.
+ uint64_t desired_align = page_align - (aligned_size % page_align);
+ if (desired_align < *poff % page_align)
+ *poff += page_align - *poff % page_align;
+ *poff += desired_align - *poff % page_align;
+ addr += *poff - orig_off;
+ orig_off = *poff;
+ }
+
+ if (!reset && this->are_addresses_set_)
+ {
+ gold_assert(this->paddr_ == addr);
+ addr = this->vaddr_;
+ }
+ else
+ {
+ this->vaddr_ = addr;
+ this->paddr_ = addr;
+ this->are_addresses_set_ = true;
+ }
+
+ in_tls = false;
+
+ this->offset_ = orig_off;
+
+ off_t off = 0;
+ uint64_t ret;
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ {
+ if (i == static_cast<int>(ORDER_RELRO_LAST))
+ {
+ *poff += last_relro_pad;
+ addr += last_relro_pad;
+ if (this->output_lists_[i].empty())
+ {
+ // If there is nothing in the ORDER_RELRO_LAST list,
+ // the padding will occur at the end of the relro
+ // segment, and we need to add it to *INCREASE_RELRO.
+ *increase_relro += last_relro_pad;
+ }
+ }
+ addr = this->set_section_list_addresses(layout, reset,
+ &this->output_lists_[i],
+ addr, poff, pshndx, &in_tls);
+ if (i < static_cast<int>(ORDER_SMALL_BSS))
+ {
+ this->filesz_ = *poff - orig_off;
+ off = *poff;
+ }
+
+ ret = addr;
+ }
+
+ // If the last section was a TLS section, align upward to the
+ // alignment of the TLS segment, so that the overall size of the TLS
+ // segment is aligned.
+ if (in_tls)
+ {
+ uint64_t segment_align = layout->tls_segment()->maximum_alignment();
+ *poff = align_address(*poff, segment_align);
+ }
+
+ this->memsz_ = *poff - orig_off;
+
+ // Ignore the file offset adjustments made by the BSS Output_data
+ // objects.
+ *poff = off;
+
+ // If code segments must contain only code, and this code segment is
+ // page-aligned in the file, then fill it out to a whole page with
+ // code fill (the tail of the segment will not be within any section).
+ // Thus the entire code segment can be mapped from the file as whole
+ // pages and that mapping will contain only valid instructions.
+ if (target->isolate_execinstr() && (this->flags() & elfcpp::PF_X) != 0)
+ {
+ uint64_t abi_pagesize = target->abi_pagesize();
+ if (orig_off % abi_pagesize == 0 && off % abi_pagesize != 0)
+ {
+ size_t fill_size = abi_pagesize - (off % abi_pagesize);
+
+ std::string fill_data;
+ if (target->has_code_fill())
+ fill_data = target->code_fill(fill_size);
+ else
+ fill_data.resize(fill_size); // Zero fill.
+
+ Output_data_const* fill = new Output_data_const(fill_data, 0);
+ fill->set_address(this->vaddr_ + this->memsz_);
+ fill->set_file_offset(off);
+ layout->add_relax_output(fill);
+
+ off += fill_size;
+ gold_assert(off % abi_pagesize == 0);
+ ret += fill_size;
+ gold_assert(ret % abi_pagesize == 0);
+
+ gold_assert((uint64_t) this->filesz_ == this->memsz_);
+ this->memsz_ = this->filesz_ += fill_size;
+
+ *poff = off;
+ }
+ }
+
+ return ret;
+}
+
+// Set the addresses and file offsets in a list of Output_data
+// structures.
+
+uint64_t
+Output_segment::set_section_list_addresses(Layout* layout, bool reset,
+ Output_data_list* pdl,
+ uint64_t addr, off_t* poff,
+ unsigned int* pshndx,
+ bool* in_tls)
+{
+ off_t startoff = *poff;
+ // For incremental updates, we may allocate non-fixed sections from
+ // free space in the file. This keeps track of the high-water mark.
+ off_t maxoff = startoff;
+
+ off_t off = startoff;
+ for (Output_data_list::iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if (reset)
+ (*p)->reset_address_and_file_offset();
+
+ // When doing an incremental update or when using a linker script,
+ // the section will most likely already have an address.
+ if (!(*p)->is_address_valid())
+ {
+ uint64_t align = (*p)->addralign();
+
+ if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
+ {
+ // Give the first TLS section the alignment of the
+ // entire TLS segment. Otherwise the TLS segment as a
+ // whole may be misaligned.
+ if (!*in_tls)
+ {
+ Output_segment* tls_segment = layout->tls_segment();
+ gold_assert(tls_segment != NULL);
+ uint64_t segment_align = tls_segment->maximum_alignment();
+ gold_assert(segment_align >= align);
+ align = segment_align;
+
+ *in_tls = true;
+ }
+ }
+ else
+ {
+ // If this is the first section after the TLS segment,
+ // align it to at least the alignment of the TLS
+ // segment, so that the size of the overall TLS segment
+ // is aligned.
+ if (*in_tls)
+ {
+ uint64_t segment_align =
+ layout->tls_segment()->maximum_alignment();
+ if (segment_align > align)
+ align = segment_align;
+
+ *in_tls = false;
+ }
+ }
+
+ if (!parameters->incremental_update())
+ {
+ off = align_address(off, align);
+ (*p)->set_address_and_file_offset(addr + (off - startoff), off);
+ }
+ else
+ {
+ // Incremental update: allocate file space from free list.
+ (*p)->pre_finalize_data_size();
+ off_t current_size = (*p)->current_data_size();
+ off = layout->allocate(current_size, align, startoff);
+ if (off == -1)
+ {
+ 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_address_and_file_offset(addr + (off - startoff), off);
+ 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());
+ }
+ }
+ }
+ else if (parameters->incremental_update())
+ {
+ // For incremental updates, use the fixed offset for the
+ // high-water mark computation.
+ off = (*p)->offset();
+ }
+ else
+ {
+ // The script may have inserted a skip forward, but it
+ // better not have moved backward.
+ if ((*p)->address() >= addr + (off - startoff))
+ off += (*p)->address() - (addr + (off - startoff));
+ else
+ {
+ if (!layout->script_options()->saw_sections_clause())
+ gold_unreachable();
+ else
+ {
+ Output_section* os = (*p)->output_section();
+
+ // Cast to unsigned long long to avoid format warnings.
+ unsigned long long previous_dot =
+ static_cast<unsigned long long>(addr + (off - startoff));
+ unsigned long long dot =
+ static_cast<unsigned long long>((*p)->address());
+
+ if (os == NULL)
+ gold_error(_("dot moves backward in linker script "
+ "from 0x%llx to 0x%llx"), previous_dot, dot);
+ else
+ gold_error(_("address of section '%s' moves backward "
+ "from 0x%llx to 0x%llx"),
+ os->name(), previous_dot, dot);
+ }
+ }
+ (*p)->set_file_offset(off);
+ (*p)->finalize_data_size();
+ }
+
+ if (parameters->incremental_update())
+ gold_debug(DEBUG_INCREMENTAL,
+ "set_section_list_addresses: %08lx %08lx %s",
+ static_cast<long>(off),
+ static_cast<long>((*p)->data_size()),
+ ((*p)->output_section() != NULL
+ ? (*p)->output_section()->name() : "(special)"));
+
+ // We want to ignore the size of a SHF_TLS SHT_NOBITS
+ // section. Such a section does not affect the size of a
+ // PT_LOAD segment.
+ if (!(*p)->is_section_flag_set(elfcpp::SHF_TLS)
+ || !(*p)->is_section_type(elfcpp::SHT_NOBITS))
+ off += (*p)->data_size();
+
+ if (off > maxoff)
+ maxoff = off;
+
+ if ((*p)->is_section())
+ {
+ (*p)->set_out_shndx(*pshndx);
+ ++*pshndx;
+ }
+ }
+
+ *poff = maxoff;
+ return addr + (maxoff - startoff);
+}
+
+// For a non-PT_LOAD segment, set the offset from the sections, if
+// any. Add INCREASE to the file size and the memory size.
+
+void
+Output_segment::set_offset(unsigned int increase)
+{
+ gold_assert(this->type_ != elfcpp::PT_LOAD);
+
+ gold_assert(!this->are_addresses_set_);
+
+ // A non-load section only uses output_lists_[0].
+
+ Output_data_list* pdl = &this->output_lists_[0];
+
+ if (pdl->empty())
+ {
+ gold_assert(increase == 0);
+ this->vaddr_ = 0;
+ this->paddr_ = 0;
+ this->are_addresses_set_ = true;
+ this->memsz_ = 0;
+ this->min_p_align_ = 0;
+ this->offset_ = 0;
+ this->filesz_ = 0;
+ return;
+ }
+
+ // Find the first and last section by address.
+ const Output_data* first = NULL;
+ const Output_data* last_data = NULL;
+ const Output_data* last_bss = NULL;
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if (first == NULL
+ || (*p)->address() < first->address()
+ || ((*p)->address() == first->address()
+ && (*p)->data_size() < first->data_size()))
+ first = *p;
+ const Output_data** plast;
+ if ((*p)->is_section()
+ && (*p)->output_section()->type() == elfcpp::SHT_NOBITS)
+ plast = &last_bss;
+ else
+ plast = &last_data;
+ if (*plast == NULL
+ || (*p)->address() > (*plast)->address()
+ || ((*p)->address() == (*plast)->address()
+ && (*p)->data_size() > (*plast)->data_size()))
+ *plast = *p;
+ }
+
+ this->vaddr_ = first->address();
+ this->paddr_ = (first->has_load_address()
+ ? first->load_address()
+ : this->vaddr_);
+ this->are_addresses_set_ = true;
+ this->offset_ = first->offset();
+
+ if (last_data == NULL)
+ this->filesz_ = 0;
+ else
+ this->filesz_ = (last_data->address()
+ + last_data->data_size()
+ - this->vaddr_);
+
+ const Output_data* last = last_bss != NULL ? last_bss : last_data;
+ this->memsz_ = (last->address()
+ + last->data_size()
+ - this->vaddr_);
+
+ this->filesz_ += increase;
+ this->memsz_ += increase;
+
+ // If this is a RELRO segment, verify that the segment ends at a
+ // page boundary.
+ if (this->type_ == elfcpp::PT_GNU_RELRO)
+ {
+ uint64_t page_align = parameters->target().abi_pagesize();
+ uint64_t segment_end = this->vaddr_ + this->memsz_;
+ if (parameters->incremental_update())
+ {
+ // The INCREASE_RELRO calculation is bypassed for an incremental
+ // update, so we need to adjust the segment size manually here.
+ segment_end = align_address(segment_end, page_align);
+ this->memsz_ = segment_end - this->vaddr_;
+ }
+ else
+ gold_assert(segment_end == align_address(segment_end, page_align));
+ }
+
+ // If this is a TLS segment, align the memory size. The code in
+ // set_section_list ensures that the section after the TLS segment
+ // is aligned to give us room.
+ if (this->type_ == elfcpp::PT_TLS)
+ {
+ uint64_t segment_align = this->maximum_alignment();
+ gold_assert(this->vaddr_ == align_address(this->vaddr_, segment_align));
+ this->memsz_ = align_address(this->memsz_, segment_align);
+ }
+}
+
+// Set the TLS offsets of the sections in the PT_TLS segment.
+
+void
+Output_segment::set_tls_offsets()
+{
+ gold_assert(this->type_ == elfcpp::PT_TLS);
+
+ for (Output_data_list::iterator p = this->output_lists_[0].begin();
+ p != this->output_lists_[0].end();
+ ++p)
+ (*p)->set_tls_offset(this->vaddr_);
+}
+
+// Return the first section.
+
+Output_section*
+Output_segment::first_section() const
+{
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ {
+ const Output_data_list* pdl = &this->output_lists_[i];
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if ((*p)->is_section())
+ return (*p)->output_section();
+ }
+ }
+ gold_unreachable();
+}
+
+// Return the number of Output_sections in an Output_segment.
+
+unsigned int
+Output_segment::output_section_count() const
+{
+ unsigned int ret = 0;
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ ret += this->output_section_count_list(&this->output_lists_[i]);
+ return ret;
+}
+
+// Return the number of Output_sections in an Output_data_list.
+
+unsigned int
+Output_segment::output_section_count_list(const Output_data_list* pdl) const
+{
+ unsigned int count = 0;
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if ((*p)->is_section())
+ ++count;
+ }
+ return count;
+}
+
+// Return the section attached to the list segment with the lowest
+// load address. This is used when handling a PHDRS clause in a
+// linker script.
+
+Output_section*
+Output_segment::section_with_lowest_load_address() const
+{
+ Output_section* found = NULL;
+ uint64_t found_lma = 0;
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ this->lowest_load_address_in_list(&this->output_lists_[i], &found,
+ &found_lma);
+ return found;
+}
+
+// Look through a list for a section with a lower load address.
+
+void
+Output_segment::lowest_load_address_in_list(const Output_data_list* pdl,
+ Output_section** found,
+ uint64_t* found_lma) const
+{
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if (!(*p)->is_section())
+ continue;
+ Output_section* os = static_cast<Output_section*>(*p);
+ uint64_t lma = (os->has_load_address()
+ ? os->load_address()
+ : os->address());
+ if (*found == NULL || lma < *found_lma)
+ {
+ *found = os;
+ *found_lma = lma;
+ }
+ }
+}
+
+// Write the segment data into *OPHDR.
+
+template<int size, bool big_endian>
+void
+Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr)
+{
+ ophdr->put_p_type(this->type_);
+ ophdr->put_p_offset(this->offset_);
+ ophdr->put_p_vaddr(this->vaddr_);
+ ophdr->put_p_paddr(this->paddr_);
+ ophdr->put_p_filesz(this->filesz_);
+ ophdr->put_p_memsz(this->memsz_);
+ ophdr->put_p_flags(this->flags_);
+ ophdr->put_p_align(std::max(this->min_p_align_, this->maximum_alignment()));
+}
+
+// Write the section headers into V.
+
+template<int size, bool big_endian>
+unsigned char*
+Output_segment::write_section_headers(const Layout* layout,
+ const Stringpool* secnamepool,
+ unsigned char* v,
+ unsigned int* pshndx) const
+{
+ // Every section that is attached to a segment must be attached to a
+ // PT_LOAD segment, so we only write out section headers for PT_LOAD
+ // segments.
+ if (this->type_ != elfcpp::PT_LOAD)
+ return v;
+
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ {
+ const Output_data_list* pdl = &this->output_lists_[i];
+ v = this->write_section_headers_list<size, big_endian>(layout,
+ secnamepool,
+ pdl,
+ v, pshndx);
+ }
+
+ return v;
+}
+
+template<int size, bool big_endian>
+unsigned char*
+Output_segment::write_section_headers_list(const Layout* layout,
+ const Stringpool* secnamepool,
+ const Output_data_list* pdl,
+ unsigned char* v,
+ unsigned int* pshndx) const
+{
+ const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if ((*p)->is_section())
+ {
+ const Output_section* ps = static_cast<const Output_section*>(*p);
+ gold_assert(*pshndx == ps->out_shndx());
+ elfcpp::Shdr_write<size, big_endian> oshdr(v);
+ ps->write_header(layout, secnamepool, &oshdr);
+ v += shdr_size;
+ ++*pshndx;
+ }
+ }
+ return v;
+}
+
+// Print the output sections to the map file.
+
+void
+Output_segment::print_sections_to_mapfile(Mapfile* mapfile) const
+{
+ if (this->type() != elfcpp::PT_LOAD)
+ return;
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ this->print_section_list_to_mapfile(mapfile, &this->output_lists_[i]);
+}
+
+// Print an output section list to the map file.
+
+void
+Output_segment::print_section_list_to_mapfile(Mapfile* mapfile,
+ const Output_data_list* pdl) const
+{
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ (*p)->print_to_mapfile(mapfile);
+}
+
+// Output_file methods.
+
+Output_file::Output_file(const char* name)
+ : name_(name),
+ o_(-1),
+ file_size_(0),
+ base_(NULL),
+ map_is_anonymous_(false),
+ map_is_allocated_(false),
+ is_temporary_(false)
+{
+}
+
+// Try to open an existing file. Returns false if the file doesn't
+// exist, has a size of 0 or can't be mmapped. If BASE_NAME is not
+// NULL, open that file as the base for incremental linking, and
+// copy its contents to the new output file. This routine can
+// be called for incremental updates, in which case WRITABLE should
+// be true, or by the incremental-dump utility, in which case
+// WRITABLE should be false.
+
+bool
+Output_file::open_base_file(const char* base_name, bool writable)
+{
+ // The name "-" means "stdout".
+ if (strcmp(this->name_, "-") == 0)
+ return false;
+
+ bool use_base_file = base_name != NULL;
+ if (!use_base_file)
+ base_name = this->name_;
+ else if (strcmp(base_name, this->name_) == 0)
+ gold_fatal(_("%s: incremental base and output file name are the same"),
+ base_name);
+
+ // Don't bother opening files with a size of zero.
+ struct stat s;
+ if (::stat(base_name, &s) != 0)
+ {
+ gold_info(_("%s: stat: %s"), base_name, strerror(errno));
+ return false;
+ }
+ if (s.st_size == 0)
+ {
+ gold_info(_("%s: incremental base file is empty"), base_name);
+ return false;
+ }
+
+ // If we're using a base file, we want to open it read-only.
+ if (use_base_file)
+ writable = false;
+
+ int oflags = writable ? O_RDWR : O_RDONLY;
+ int o = open_descriptor(-1, base_name, oflags, 0);
+ if (o < 0)
+ {
+ gold_info(_("%s: open: %s"), base_name, strerror(errno));
+ return false;
+ }
+
+ // If the base file and the output file are different, open a
+ // new output file and read the contents from the base file into
+ // the newly-mapped region.
+ if (use_base_file)
+ {
+ this->open(s.st_size);
+ ssize_t bytes_to_read = s.st_size;
+ unsigned char* p = this->base_;
+ while (bytes_to_read > 0)
+ {
+ ssize_t len = ::read(o, p, bytes_to_read);
+ if (len < 0)
+ {
+ gold_info(_("%s: read failed: %s"), base_name, strerror(errno));
+ return false;
+ }
+ if (len == 0)
+ {
+ gold_info(_("%s: file too short: read only %lld of %lld bytes"),
+ base_name,
+ static_cast<long long>(s.st_size - bytes_to_read),
+ static_cast<long long>(s.st_size));
+ return false;
+ }
+ p += len;
+ bytes_to_read -= len;
+ }
+ ::close(o);
+ return true;
+ }
+
+ this->o_ = o;
+ this->file_size_ = s.st_size;
+
+ if (!this->map_no_anonymous(writable))
+ {
+ release_descriptor(o, true);
+ this->o_ = -1;
+ this->file_size_ = 0;
+ return false;
+ }
+
+ return true;
+}
+
+// Open the output file.
+
+void
+Output_file::open(off_t file_size)
+{
+ this->file_size_ = file_size;
+
+ // Unlink the file first; otherwise the open() may fail if the file
+ // is busy (e.g. it's an executable that's currently being executed).
+ //
+ // However, the linker may be part of a system where a zero-length
+ // file is created for it to write to, with tight permissions (gcc
+ // 2.95 did something like this). Unlinking the file would work
+ // around those permission controls, so we only unlink if the file
+ // has a non-zero size. We also unlink only regular files to avoid
+ // trouble with directories/etc.
+ //
+ // If we fail, continue; this command is merely a best-effort attempt
+ // to improve the odds for open().
+
+ // We let the name "-" mean "stdout"
+ if (!this->is_temporary_)
+ {
+ if (strcmp(this->name_, "-") == 0)
+ this->o_ = STDOUT_FILENO;
+ else
+ {
+ struct stat s;
+ if (::stat(this->name_, &s) == 0
+ && (S_ISREG (s.st_mode) || S_ISLNK (s.st_mode)))
+ {
+ if (s.st_size != 0)
+ ::unlink(this->name_);
+ else if (!parameters->options().relocatable())
+ {
+ // If we don't unlink the existing file, add execute
+ // permission where read permissions already exist
+ // and where the umask permits.
+ int mask = ::umask(0);
+ ::umask(mask);
+ s.st_mode |= (s.st_mode & 0444) >> 2;
+ ::chmod(this->name_, s.st_mode & ~mask);
+ }
+ }
+
+ int mode = parameters->options().relocatable() ? 0666 : 0777;
+ int o = open_descriptor(-1, this->name_, O_RDWR | O_CREAT | O_TRUNC,
+ mode);
+ if (o < 0)
+ gold_fatal(_("%s: open: %s"), this->name_, strerror(errno));
+ this->o_ = o;
+ }
+ }
+
+ this->map();
+}
+
+// Resize the output file.
+
+void
+Output_file::resize(off_t file_size)
+{
+ // If the mmap is mapping an anonymous memory buffer, this is easy:
+ // just mremap to the new size. If it's mapping to a file, we want
+ // to unmap to flush to the file, then remap after growing the file.
+ if (this->map_is_anonymous_)
+ {
+ void* base;
+ if (!this->map_is_allocated_)
+ {
+ base = ::mremap(this->base_, this->file_size_, file_size,
+ MREMAP_MAYMOVE);
+ if (base == MAP_FAILED)
+ gold_fatal(_("%s: mremap: %s"), this->name_, strerror(errno));
+ }
+ else
+ {
+ base = realloc(this->base_, file_size);
+ if (base == NULL)
+ gold_nomem();
+ if (file_size > this->file_size_)
+ memset(static_cast<char*>(base) + this->file_size_, 0,
+ file_size - this->file_size_);
+ }
+ this->base_ = static_cast<unsigned char*>(base);
+ this->file_size_ = file_size;
+ }
+ else
+ {
+ this->unmap();
+ this->file_size_ = file_size;
+ if (!this->map_no_anonymous(true))
+ gold_fatal(_("%s: mmap: %s"), this->name_, strerror(errno));
+ }
+}
+
+// Map an anonymous block of memory which will later be written to the
+// file. Return whether the map succeeded.
+
+bool
+Output_file::map_anonymous()
+{
+ void* base = ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (base == MAP_FAILED)
+ {
+ base = malloc(this->file_size_);
+ if (base == NULL)
+ return false;
+ memset(base, 0, this->file_size_);
+ this->map_is_allocated_ = true;
+ }
+ this->base_ = static_cast<unsigned char*>(base);
+ this->map_is_anonymous_ = true;
+ return true;
+}
+
+// Map the file into memory. Return whether the mapping succeeded.
+// If WRITABLE is true, map with write access.
+
+bool
+Output_file::map_no_anonymous(bool writable)
+{
+ const int o = this->o_;
+
+ // If the output file is not a regular file, don't try to mmap it;
+ // instead, we'll mmap a block of memory (an anonymous buffer), and
+ // then later write the buffer to the file.
+ void* base;
+ struct stat statbuf;
+ if (o == STDOUT_FILENO || o == STDERR_FILENO
+ || ::fstat(o, &statbuf) != 0
+ || !S_ISREG(statbuf.st_mode)
+ || this->is_temporary_)
+ return false;
+
+ // Ensure that we have disk space available for the file. If we
+ // don't do this, it is possible that we will call munmap, close,
+ // and exit with dirty buffers still in the cache with no assigned
+ // disk blocks. If the disk is out of space at that point, the
+ // output file will wind up incomplete, but we will have already
+ // exited. The alternative to fallocate would be to use fdatasync,
+ // but that would be a more significant performance hit.
+ if (writable)
+ {
+ int err = gold_fallocate(o, 0, this->file_size_);
+ if (err != 0)
+ gold_fatal(_("%s: %s"), this->name_, strerror(err));
+ }
+
+ // Map the file into memory.
+ int prot = PROT_READ;
+ if (writable)
+ prot |= PROT_WRITE;
+ base = ::mmap(NULL, this->file_size_, prot, MAP_SHARED, o, 0);
+
+ // The mmap call might fail because of file system issues: the file
+ // system might not support mmap at all, or it might not support
+ // mmap with PROT_WRITE.
+ if (base == MAP_FAILED)
+ return false;
+
+ this->map_is_anonymous_ = false;
+ this->base_ = static_cast<unsigned char*>(base);
+ return true;
+}
+
+// Map the file into memory.
+
+void
+Output_file::map()
+{
+ if (parameters->options().mmap_output_file()
+ && this->map_no_anonymous(true))
+ return;
+
+ // The mmap call might fail because of file system issues: the file
+ // system might not support mmap at all, or it might not support
+ // mmap with PROT_WRITE. I'm not sure which errno values we will
+ // see in all cases, so if the mmap fails for any reason and we
+ // don't care about file contents, try for an anonymous map.
+ if (this->map_anonymous())
+ return;
+
+ gold_fatal(_("%s: mmap: failed to allocate %lu bytes for output file: %s"),
+ this->name_, static_cast<unsigned long>(this->file_size_),
+ strerror(errno));
+}
+
+// Unmap the file from memory.
+
+void
+Output_file::unmap()
+{
+ if (this->map_is_anonymous_)
+ {
+ // We've already written out the data, so there is no reason to
+ // waste time unmapping or freeing the memory.
+ }
+ else
+ {
+ if (::munmap(this->base_, this->file_size_) < 0)
+ gold_error(_("%s: munmap: %s"), this->name_, strerror(errno));
+ }
+ this->base_ = NULL;
+}
+
+// Close the output file.
+
+void
+Output_file::close()
+{
+ // If the map isn't file-backed, we need to write it now.
+ if (this->map_is_anonymous_ && !this->is_temporary_)
+ {
+ size_t bytes_to_write = this->file_size_;
+ size_t offset = 0;
+ while (bytes_to_write > 0)
+ {
+ ssize_t bytes_written = ::write(this->o_, this->base_ + offset,
+ bytes_to_write);
+ if (bytes_written == 0)
+ gold_error(_("%s: write: unexpected 0 return-value"), this->name_);
+ else if (bytes_written < 0)
+ gold_error(_("%s: write: %s"), this->name_, strerror(errno));
+ else
+ {
+ bytes_to_write -= bytes_written;
+ offset += bytes_written;
+ }
+ }
+ }
+ this->unmap();
+
+ // We don't close stdout or stderr
+ if (this->o_ != STDOUT_FILENO
+ && this->o_ != STDERR_FILENO
+ && !this->is_temporary_)
+ if (::close(this->o_) < 0)
+ gold_error(_("%s: close: %s"), this->name_, strerror(errno));
+ this->o_ = -1;
+}
+
+// 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
+off_t
+Output_section::add_input_section<32, false>(
+ Layout* layout,
+ Sized_relobj_file<32, false>* object,
+ unsigned int shndx,
+ const char* secname,
+ const elfcpp::Shdr<32, false>& shdr,
+ unsigned int reloc_shndx,
+ bool have_sections_script);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+off_t
+Output_section::add_input_section<32, true>(
+ Layout* layout,
+ Sized_relobj_file<32, true>* object,
+ unsigned int shndx,
+ const char* secname,
+ const elfcpp::Shdr<32, true>& shdr,
+ unsigned int reloc_shndx,
+ bool have_sections_script);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+off_t
+Output_section::add_input_section<64, false>(
+ Layout* layout,
+ Sized_relobj_file<64, false>* object,
+ unsigned int shndx,
+ const char* secname,
+ const elfcpp::Shdr<64, false>& shdr,
+ unsigned int reloc_shndx,
+ bool have_sections_script);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+off_t
+Output_section::add_input_section<64, true>(
+ Layout* layout,
+ Sized_relobj_file<64, true>* object,
+ unsigned int shndx,
+ const char* secname,
+ const elfcpp::Shdr<64, true>& shdr,
+ unsigned int reloc_shndx,
+ bool have_sections_script);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_reloc<elfcpp::SHT_REL, false, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_reloc<elfcpp::SHT_REL, false, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_reloc<elfcpp::SHT_REL, false, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_reloc<elfcpp::SHT_REL, false, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_reloc<elfcpp::SHT_REL, true, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_reloc<elfcpp::SHT_REL, true, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_reloc<elfcpp::SHT_REL, true, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_reloc<elfcpp::SHT_REL, true, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_reloc<elfcpp::SHT_RELA, false, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_reloc<elfcpp::SHT_RELA, false, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_reloc<elfcpp::SHT_RELA, false, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_reloc<elfcpp::SHT_RELA, false, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_reloc<elfcpp::SHT_RELA, true, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_reloc<elfcpp::SHT_RELA, true, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_reloc<elfcpp::SHT_RELA, true, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_reloc<elfcpp::SHT_RELA, true, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_data_reloc<elfcpp::SHT_REL, false, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_data_reloc<elfcpp::SHT_REL, false, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_data_reloc<elfcpp::SHT_REL, false, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_data_reloc<elfcpp::SHT_REL, false, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_data_reloc<elfcpp::SHT_REL, true, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_data_reloc<elfcpp::SHT_REL, true, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_data_reloc<elfcpp::SHT_REL, true, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_data_reloc<elfcpp::SHT_REL, true, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_data_reloc<elfcpp::SHT_RELA, false, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_data_reloc<elfcpp::SHT_RELA, false, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_data_reloc<elfcpp::SHT_RELA, false, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_data_reloc<elfcpp::SHT_RELA, false, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_data_reloc<elfcpp::SHT_RELA, true, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_data_reloc<elfcpp::SHT_RELA, true, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_data_reloc<elfcpp::SHT_RELA, true, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_data_reloc<elfcpp::SHT_RELA, true, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_relocatable_relocs<elfcpp::SHT_REL, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_relocatable_relocs<elfcpp::SHT_REL, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_relocatable_relocs<elfcpp::SHT_REL, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_relocatable_relocs<elfcpp::SHT_REL, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_relocatable_relocs<elfcpp::SHT_RELA, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_relocatable_relocs<elfcpp::SHT_RELA, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_relocatable_relocs<elfcpp::SHT_RELA, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_relocatable_relocs<elfcpp::SHT_RELA, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_data_group<32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_data_group<32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_data_group<64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_data_group<64, true>;
+#endif
+
+template
+class Output_data_got<32, false>;
+
+template
+class Output_data_got<32, true>;
+
+template
+class Output_data_got<64, false>;
+
+template
+class Output_data_got<64, true>;
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/output.h b/binutils-2.25/gold/output.h
new file mode 100644
index 00000000..574d270c
--- /dev/null
+++ b/binutils-2.25/gold/output.h
@@ -0,0 +1,4866 @@
+// output.h -- manage the output file for gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2013
+// Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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_OUTPUT_H
+#define GOLD_OUTPUT_H
+
+#include <list>
+#include <vector>
+
+#include "elfcpp.h"
+#include "mapfile.h"
+#include "layout.h"
+#include "reloc-types.h"
+
+namespace gold
+{
+
+class General_options;
+class Object;
+class Symbol;
+class Output_file;
+class Output_merge_base;
+class Output_section;
+class Relocatable_relocs;
+class Target;
+template<int size, bool big_endian>
+class Sized_target;
+template<int size, bool big_endian>
+class Sized_relobj;
+template<int size, bool big_endian>
+class Sized_relobj_file;
+
+// An abtract class for data which has to go into the output file.
+
+class Output_data
+{
+ public:
+ explicit Output_data()
+ : address_(0), data_size_(0), offset_(-1),
+ is_address_valid_(false), is_data_size_valid_(false),
+ is_offset_valid_(false), is_data_size_fixed_(false),
+ has_dynamic_reloc_(false)
+ { }
+
+ virtual
+ ~Output_data();
+
+ // Return the address. For allocated sections, this is only valid
+ // after Layout::finalize is finished.
+ uint64_t
+ address() const
+ {
+ gold_assert(this->is_address_valid_);
+ return this->address_;
+ }
+
+ // Return the size of the data. For allocated sections, this must
+ // be valid after Layout::finalize calls set_address, but need not
+ // be valid before then.
+ off_t
+ data_size() const
+ {
+ gold_assert(this->is_data_size_valid_);
+ return this->data_size_;
+ }
+
+ // Get the current data size.
+ off_t
+ current_data_size() const
+ { return this->current_data_size_for_child(); }
+
+ // Return true if data size is fixed.
+ bool
+ is_data_size_fixed() const
+ { return this->is_data_size_fixed_; }
+
+ // Return the file offset. This is only valid after
+ // Layout::finalize is finished. For some non-allocated sections,
+ // it may not be valid until near the end of the link.
+ off_t
+ offset() const
+ {
+ gold_assert(this->is_offset_valid_);
+ return this->offset_;
+ }
+
+ // Reset the address, file offset and data size. This essentially
+ // disables the sanity testing about duplicate and unknown settings.
+ void
+ reset_address_and_file_offset()
+ {
+ this->is_address_valid_ = false;
+ this->is_offset_valid_ = false;
+ if (!this->is_data_size_fixed_)
+ this->is_data_size_valid_ = false;
+ this->do_reset_address_and_file_offset();
+ }
+
+ // As above, but just for data size.
+ void
+ reset_data_size()
+ {
+ if (!this->is_data_size_fixed_)
+ this->is_data_size_valid_ = false;
+ }
+
+ // Return true if address and file offset already have reset values. In
+ // other words, calling reset_address_and_file_offset will not change them.
+ bool
+ address_and_file_offset_have_reset_values() const
+ { return this->do_address_and_file_offset_have_reset_values(); }
+
+ // Return the required alignment.
+ uint64_t
+ addralign() const
+ { return this->do_addralign(); }
+
+ // Return whether this has a load address.
+ bool
+ has_load_address() const
+ { return this->do_has_load_address(); }
+
+ // Return the load address.
+ uint64_t
+ load_address() const
+ { return this->do_load_address(); }
+
+ // Return whether this is an Output_section.
+ bool
+ is_section() const
+ { return this->do_is_section(); }
+
+ // Return whether this is an Output_section of the specified type.
+ bool
+ is_section_type(elfcpp::Elf_Word stt) const
+ { return this->do_is_section_type(stt); }
+
+ // Return whether this is an Output_section with the specified flag
+ // set.
+ bool
+ is_section_flag_set(elfcpp::Elf_Xword shf) const
+ { return this->do_is_section_flag_set(shf); }
+
+ // Return the output section that this goes in, if there is one.
+ Output_section*
+ output_section()
+ { return this->do_output_section(); }
+
+ const Output_section*
+ output_section() const
+ { return this->do_output_section(); }
+
+ // Return the output section index, if there is an output section.
+ unsigned int
+ out_shndx() const
+ { return this->do_out_shndx(); }
+
+ // Set the output section index, if this is an output section.
+ void
+ set_out_shndx(unsigned int shndx)
+ { this->do_set_out_shndx(shndx); }
+
+ // Set the address and file offset of this data, and finalize the
+ // size of the data. This is called during Layout::finalize for
+ // allocated sections.
+ void
+ set_address_and_file_offset(uint64_t addr, off_t off)
+ {
+ this->set_address(addr);
+ this->set_file_offset(off);
+ this->finalize_data_size();
+ }
+
+ // Set the address.
+ void
+ set_address(uint64_t addr)
+ {
+ gold_assert(!this->is_address_valid_);
+ this->address_ = addr;
+ this->is_address_valid_ = true;
+ }
+
+ // Set the file offset.
+ void
+ set_file_offset(off_t off)
+ {
+ gold_assert(!this->is_offset_valid_);
+ this->offset_ = off;
+ this->is_offset_valid_ = true;
+ }
+
+ // Update the data size without finalizing it.
+ void
+ pre_finalize_data_size()
+ {
+ if (!this->is_data_size_valid_)
+ {
+ // Tell the child class to update the data size.
+ this->update_data_size();
+ }
+ }
+
+ // Finalize the data size.
+ void
+ finalize_data_size()
+ {
+ if (!this->is_data_size_valid_)
+ {
+ // Tell the child class to set the data size.
+ this->set_final_data_size();
+ gold_assert(this->is_data_size_valid_);
+ }
+ }
+
+ // Set the TLS offset. Called only for SHT_TLS sections.
+ void
+ set_tls_offset(uint64_t tls_base)
+ { this->do_set_tls_offset(tls_base); }
+
+ // Return the TLS offset, relative to the base of the TLS segment.
+ // Valid only for SHT_TLS sections.
+ uint64_t
+ tls_offset() const
+ { return this->do_tls_offset(); }
+
+ // Write the data to the output file. This is called after
+ // Layout::finalize is complete.
+ void
+ write(Output_file* file)
+ { this->do_write(file); }
+
+ // This is called by Layout::finalize to note that the sizes of
+ // allocated sections must now be fixed.
+ static void
+ layout_complete()
+ { Output_data::allocated_sizes_are_fixed = true; }
+
+ // Used to check that layout has been done.
+ static bool
+ is_layout_complete()
+ { return Output_data::allocated_sizes_are_fixed; }
+
+ // Note that a dynamic reloc has been applied to this data.
+ void
+ add_dynamic_reloc()
+ { this->has_dynamic_reloc_ = true; }
+
+ // Return whether a dynamic reloc has been applied.
+ bool
+ has_dynamic_reloc() const
+ { return this->has_dynamic_reloc_; }
+
+ // Whether the address is valid.
+ bool
+ is_address_valid() const
+ { return this->is_address_valid_; }
+
+ // Whether the file offset is valid.
+ bool
+ is_offset_valid() const
+ { return this->is_offset_valid_; }
+
+ // Whether the data size is valid.
+ bool
+ is_data_size_valid() const
+ { return this->is_data_size_valid_; }
+
+ // Print information to the map file.
+ void
+ print_to_mapfile(Mapfile* mapfile) const
+ { return this->do_print_to_mapfile(mapfile); }
+
+ protected:
+ // Functions that child classes may or in some cases must implement.
+
+ // Write the data to the output file.
+ virtual void
+ do_write(Output_file*) = 0;
+
+ // Return the required alignment.
+ virtual uint64_t
+ do_addralign() const = 0;
+
+ // Return whether this has a load address.
+ virtual bool
+ do_has_load_address() const
+ { return false; }
+
+ // Return the load address.
+ virtual uint64_t
+ do_load_address() const
+ { gold_unreachable(); }
+
+ // Return whether this is an Output_section.
+ virtual bool
+ do_is_section() const
+ { return false; }
+
+ // Return whether this is an Output_section of the specified type.
+ // This only needs to be implement by Output_section.
+ virtual bool
+ do_is_section_type(elfcpp::Elf_Word) const
+ { return false; }
+
+ // Return whether this is an Output_section with the specific flag
+ // set. This only needs to be implemented by Output_section.
+ virtual bool
+ do_is_section_flag_set(elfcpp::Elf_Xword) const
+ { return false; }
+
+ // Return the output section, if there is one.
+ virtual Output_section*
+ do_output_section()
+ { return NULL; }
+
+ virtual const Output_section*
+ do_output_section() const
+ { return NULL; }
+
+ // Return the output section index, if there is an output section.
+ virtual unsigned int
+ do_out_shndx() const
+ { gold_unreachable(); }
+
+ // Set the output section index, if this is an output section.
+ virtual void
+ do_set_out_shndx(unsigned int)
+ { gold_unreachable(); }
+
+ // This is a hook for derived classes to set the preliminary data size.
+ // This is called by pre_finalize_data_size, normally called during
+ // Layout::finalize, before the section address is set, and is used
+ // during an incremental update, when we need to know the size of a
+ // section before allocating space in the output file. For classes
+ // where the current data size is up to date, this default version of
+ // the method can be inherited.
+ virtual void
+ update_data_size()
+ { }
+
+ // This is a hook for derived classes to set the data size. This is
+ // called by finalize_data_size, normally called during
+ // Layout::finalize, when the section address is set.
+ virtual void
+ set_final_data_size()
+ { gold_unreachable(); }
+
+ // A hook for resetting the address and file offset.
+ virtual void
+ do_reset_address_and_file_offset()
+ { }
+
+ // Return true if address and file offset already have reset values. In
+ // other words, calling reset_address_and_file_offset will not change them.
+ // A child class overriding do_reset_address_and_file_offset may need to
+ // also override this.
+ virtual bool
+ do_address_and_file_offset_have_reset_values() const
+ { return !this->is_address_valid_ && !this->is_offset_valid_; }
+
+ // Set the TLS offset. Called only for SHT_TLS sections.
+ virtual void
+ do_set_tls_offset(uint64_t)
+ { gold_unreachable(); }
+
+ // Return the TLS offset, relative to the base of the TLS segment.
+ // Valid only for SHT_TLS sections.
+ virtual uint64_t
+ do_tls_offset() const
+ { gold_unreachable(); }
+
+ // Print to the map file. This only needs to be implemented by
+ // classes which may appear in a PT_LOAD segment.
+ virtual void
+ do_print_to_mapfile(Mapfile*) const
+ { gold_unreachable(); }
+
+ // Functions that child classes may call.
+
+ // Reset the address. The Output_section class needs this when an
+ // SHF_ALLOC input section is added to an output section which was
+ // formerly not SHF_ALLOC.
+ void
+ mark_address_invalid()
+ { this->is_address_valid_ = false; }
+
+ // Set the size of the data.
+ void
+ set_data_size(off_t data_size)
+ {
+ gold_assert(!this->is_data_size_valid_
+ && !this->is_data_size_fixed_);
+ this->data_size_ = data_size;
+ this->is_data_size_valid_ = true;
+ }
+
+ // Fix the data size. Once it is fixed, it cannot be changed
+ // and the data size remains always valid.
+ void
+ fix_data_size()
+ {
+ gold_assert(this->is_data_size_valid_);
+ this->is_data_size_fixed_ = true;
+ }
+
+ // Get the current data size--this is for the convenience of
+ // sections which build up their size over time.
+ off_t
+ current_data_size_for_child() const
+ { return this->data_size_; }
+
+ // Set the current data size--this is for the convenience of
+ // sections which build up their size over time.
+ void
+ set_current_data_size_for_child(off_t data_size)
+ {
+ gold_assert(!this->is_data_size_valid_);
+ this->data_size_ = data_size;
+ }
+
+ // Return default alignment for the target size.
+ static uint64_t
+ default_alignment();
+
+ // Return default alignment for a specified size--32 or 64.
+ static uint64_t
+ default_alignment_for_size(int size);
+
+ private:
+ Output_data(const Output_data&);
+ Output_data& operator=(const Output_data&);
+
+ // This is used for verification, to make sure that we don't try to
+ // change any sizes of allocated sections after we set the section
+ // addresses.
+ static bool allocated_sizes_are_fixed;
+
+ // Memory address in output file.
+ uint64_t address_;
+ // Size of data in output file.
+ off_t data_size_;
+ // File offset of contents in output file.
+ off_t offset_;
+ // Whether address_ is valid.
+ bool is_address_valid_ : 1;
+ // Whether data_size_ is valid.
+ bool is_data_size_valid_ : 1;
+ // Whether offset_ is valid.
+ bool is_offset_valid_ : 1;
+ // Whether data size is fixed.
+ bool is_data_size_fixed_ : 1;
+ // Whether any dynamic relocs have been applied to this section.
+ bool has_dynamic_reloc_ : 1;
+};
+
+// Output the section headers.
+
+class Output_section_headers : public Output_data
+{
+ public:
+ Output_section_headers(const Layout*,
+ const Layout::Segment_list*,
+ const Layout::Section_list*,
+ const Layout::Section_list*,
+ const Stringpool*,
+ const Output_section*);
+
+ protected:
+ // Write the data to the file.
+ void
+ do_write(Output_file*);
+
+ // Return the required alignment.
+ uint64_t
+ do_addralign() const
+ { return Output_data::default_alignment(); }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** section headers")); }
+
+ // Update the data size.
+ void
+ update_data_size()
+ { this->set_data_size(this->do_size()); }
+
+ // Set final data size.
+ void
+ set_final_data_size()
+ { this->set_data_size(this->do_size()); }
+
+ private:
+ // Write the data to the file with the right size and endianness.
+ template<int size, bool big_endian>
+ void
+ do_sized_write(Output_file*);
+
+ // Compute data size.
+ off_t
+ do_size() const;
+
+ const Layout* layout_;
+ const Layout::Segment_list* segment_list_;
+ const Layout::Section_list* section_list_;
+ const Layout::Section_list* unattached_section_list_;
+ const Stringpool* secnamepool_;
+ const Output_section* shstrtab_section_;
+};
+
+// Output the segment headers.
+
+class Output_segment_headers : public Output_data
+{
+ public:
+ Output_segment_headers(const Layout::Segment_list& segment_list);
+
+ protected:
+ // Write the data to the file.
+ void
+ do_write(Output_file*);
+
+ // Return the required alignment.
+ uint64_t
+ do_addralign() const
+ { return Output_data::default_alignment(); }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** segment headers")); }
+
+ // Set final data size.
+ void
+ set_final_data_size()
+ { this->set_data_size(this->do_size()); }
+
+ private:
+ // Write the data to the file with the right size and endianness.
+ template<int size, bool big_endian>
+ void
+ do_sized_write(Output_file*);
+
+ // Compute the current size.
+ off_t
+ do_size() const;
+
+ const Layout::Segment_list& segment_list_;
+};
+
+// Output the ELF file header.
+
+class Output_file_header : public Output_data
+{
+ public:
+ Output_file_header(Target*,
+ const Symbol_table*,
+ const Output_segment_headers*);
+
+ // Add information about the section headers. We lay out the ELF
+ // file header before we create the section headers.
+ void set_section_info(const Output_section_headers*,
+ const Output_section* shstrtab);
+
+ protected:
+ // Write the data to the file.
+ void
+ do_write(Output_file*);
+
+ // Return the required alignment.
+ uint64_t
+ do_addralign() const
+ { return Output_data::default_alignment(); }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** file header")); }
+
+ // Set final data size.
+ void
+ set_final_data_size(void)
+ { this->set_data_size(this->do_size()); }
+
+ private:
+ // Write the data to the file with the right size and endianness.
+ template<int size, bool big_endian>
+ void
+ do_sized_write(Output_file*);
+
+ // Return the value to use for the entry address.
+ template<int size>
+ typename elfcpp::Elf_types<size>::Elf_Addr
+ entry();
+
+ // Compute the current data size.
+ off_t
+ do_size() const;
+
+ Target* target_;
+ const Symbol_table* symtab_;
+ const Output_segment_headers* segment_header_;
+ const Output_section_headers* section_header_;
+ const Output_section* shstrtab_;
+};
+
+// Output sections are mainly comprised of input sections. However,
+// there are cases where we have data to write out which is not in an
+// input section. Output_section_data is used in such cases. This is
+// an abstract base class.
+
+class Output_section_data : public Output_data
+{
+ public:
+ Output_section_data(off_t data_size, uint64_t addralign,
+ bool is_data_size_fixed)
+ : Output_data(), output_section_(NULL), addralign_(addralign)
+ {
+ this->set_data_size(data_size);
+ if (is_data_size_fixed)
+ this->fix_data_size();
+ }
+
+ Output_section_data(uint64_t addralign)
+ : Output_data(), output_section_(NULL), addralign_(addralign)
+ { }
+
+ // Return the output section.
+ Output_section*
+ output_section()
+ { return this->output_section_; }
+
+ const Output_section*
+ output_section() const
+ { return this->output_section_; }
+
+ // Record the output section.
+ void
+ set_output_section(Output_section* os);
+
+ // Add an input section, for SHF_MERGE sections. This returns true
+ // if the section was handled.
+ bool
+ add_input_section(Relobj* object, unsigned int shndx)
+ { return this->do_add_input_section(object, shndx); }
+
+ // 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
+ output_offset(const Relobj* object, unsigned int shndx,
+ section_offset_type offset,
+ section_offset_type* poutput) const
+ { return this->do_output_offset(object, shndx, offset, poutput); }
+
+ // Return whether this is the merge section for the input section
+ // SHNDX in OBJECT. This should return true when output_offset
+ // would return true for some values of OFFSET.
+ bool
+ is_merge_section_for(const Relobj* object, unsigned int shndx) const
+ { return this->do_is_merge_section_for(object, shndx); }
+
+ // Write the contents to a buffer. This is used for sections which
+ // require postprocessing, such as compression.
+ void
+ write_to_buffer(unsigned char* buffer)
+ { this->do_write_to_buffer(buffer); }
+
+ // Print merge stats to stderr. This should only be called for
+ // SHF_MERGE sections.
+ void
+ print_merge_stats(const char* section_name)
+ { this->do_print_merge_stats(section_name); }
+
+ protected:
+ // The child class must implement do_write.
+
+ // The child class may implement specific adjustments to the output
+ // section.
+ virtual void
+ do_adjust_output_section(Output_section*)
+ { }
+
+ // May be implemented by child class. Return true if the section
+ // was handled.
+ virtual bool
+ do_add_input_section(Relobj*, unsigned int)
+ { gold_unreachable(); }
+
+ // The child class may implement output_offset.
+ virtual bool
+ do_output_offset(const Relobj*, unsigned int, section_offset_type,
+ section_offset_type*) const
+ { return false; }
+
+ // The child class may implement is_merge_section_for.
+ virtual bool
+ do_is_merge_section_for(const Relobj*, unsigned int) const
+ { return false; }
+
+ // The child class may implement write_to_buffer. Most child
+ // classes can not appear in a compressed section, and they do not
+ // implement this.
+ virtual void
+ do_write_to_buffer(unsigned char*)
+ { gold_unreachable(); }
+
+ // Print merge statistics.
+ virtual void
+ do_print_merge_stats(const char*)
+ { gold_unreachable(); }
+
+ // Return the required alignment.
+ uint64_t
+ do_addralign() const
+ { return this->addralign_; }
+
+ // Return the output section.
+ Output_section*
+ do_output_section()
+ { return this->output_section_; }
+
+ const Output_section*
+ do_output_section() const
+ { return this->output_section_; }
+
+ // Return the section index of the output section.
+ unsigned int
+ do_out_shndx() const;
+
+ // Set the alignment.
+ void
+ set_addralign(uint64_t addralign);
+
+ private:
+ // The output section for this section.
+ Output_section* output_section_;
+ // The required alignment.
+ uint64_t addralign_;
+};
+
+// Some Output_section_data classes build up their data step by step,
+// rather than all at once. This class provides an interface for
+// them.
+
+class Output_section_data_build : public Output_section_data
+{
+ public:
+ Output_section_data_build(uint64_t addralign)
+ : Output_section_data(addralign)
+ { }
+
+ Output_section_data_build(off_t data_size, uint64_t addralign)
+ : Output_section_data(data_size, addralign, false)
+ { }
+
+ // Set the current data size.
+ void
+ set_current_data_size(off_t data_size)
+ { this->set_current_data_size_for_child(data_size); }
+
+ protected:
+ // Set the final data size.
+ virtual void
+ set_final_data_size()
+ { this->set_data_size(this->current_data_size_for_child()); }
+};
+
+// A simple case of Output_data in which we have constant data to
+// output.
+
+class Output_data_const : public Output_section_data
+{
+ public:
+ Output_data_const(const std::string& data, uint64_t addralign)
+ : Output_section_data(data.size(), addralign, true), data_(data)
+ { }
+
+ Output_data_const(const char* p, off_t len, uint64_t addralign)
+ : Output_section_data(len, addralign, true), data_(p, len)
+ { }
+
+ Output_data_const(const unsigned char* p, off_t len, uint64_t addralign)
+ : Output_section_data(len, addralign, true),
+ data_(reinterpret_cast<const char*>(p), len)
+ { }
+
+ protected:
+ // Write the data to the output file.
+ void
+ do_write(Output_file*);
+
+ // Write the data to a buffer.
+ void
+ do_write_to_buffer(unsigned char* buffer)
+ { memcpy(buffer, this->data_.data(), this->data_.size()); }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** fill")); }
+
+ private:
+ std::string data_;
+};
+
+// Another version of Output_data with constant data, in which the
+// buffer is allocated by the caller.
+
+class Output_data_const_buffer : public Output_section_data
+{
+ public:
+ Output_data_const_buffer(const unsigned char* p, off_t len,
+ uint64_t addralign, const char* map_name)
+ : Output_section_data(len, addralign, true),
+ p_(p), map_name_(map_name)
+ { }
+
+ protected:
+ // Write the data the output file.
+ void
+ do_write(Output_file*);
+
+ // Write the data to a buffer.
+ void
+ do_write_to_buffer(unsigned char* buffer)
+ { memcpy(buffer, this->p_, this->data_size()); }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _(this->map_name_)); }
+
+ private:
+ // The data to output.
+ const unsigned char* p_;
+ // Name to use in a map file. Maps are a rarely used feature, but
+ // the space usage is minor as aren't very many of these objects.
+ const char* map_name_;
+};
+
+// A place holder for a fixed amount of data written out via some
+// other mechanism.
+
+class Output_data_fixed_space : public Output_section_data
+{
+ public:
+ Output_data_fixed_space(off_t data_size, uint64_t addralign,
+ const char* map_name)
+ : Output_section_data(data_size, addralign, true),
+ map_name_(map_name)
+ { }
+
+ protected:
+ // Write out the data--the actual data must be written out
+ // elsewhere.
+ void
+ do_write(Output_file*)
+ { }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _(this->map_name_)); }
+
+ private:
+ // Name to use in a map file. Maps are a rarely used feature, but
+ // the space usage is minor as aren't very many of these objects.
+ const char* map_name_;
+};
+
+// A place holder for variable sized data written out via some other
+// mechanism.
+
+class Output_data_space : public Output_section_data_build
+{
+ public:
+ explicit Output_data_space(uint64_t addralign, const char* map_name)
+ : Output_section_data_build(addralign),
+ map_name_(map_name)
+ { }
+
+ explicit Output_data_space(off_t data_size, uint64_t addralign,
+ const char* map_name)
+ : Output_section_data_build(data_size, addralign),
+ map_name_(map_name)
+ { }
+
+ // Set the alignment.
+ void
+ set_space_alignment(uint64_t align)
+ { this->set_addralign(align); }
+
+ protected:
+ // Write out the data--the actual data must be written out
+ // elsewhere.
+ void
+ do_write(Output_file*)
+ { }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _(this->map_name_)); }
+
+ private:
+ // Name to use in a map file. Maps are a rarely used feature, but
+ // the space usage is minor as aren't very many of these objects.
+ const char* map_name_;
+};
+
+// Fill fixed space with zeroes. This is just like
+// Output_data_fixed_space, except that the map name is known.
+
+class Output_data_zero_fill : public Output_section_data
+{
+ public:
+ Output_data_zero_fill(off_t data_size, uint64_t addralign)
+ : Output_section_data(data_size, addralign, true)
+ { }
+
+ protected:
+ // There is no data to write out.
+ void
+ do_write(Output_file*)
+ { }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, "** zero fill"); }
+};
+
+// A string table which goes into an output section.
+
+class Output_data_strtab : public Output_section_data
+{
+ public:
+ Output_data_strtab(Stringpool* strtab)
+ : Output_section_data(1), strtab_(strtab)
+ { }
+
+ 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(); }
+
+ // This is called to set the address and file offset. Here we make
+ // sure that the Stringpool is finalized.
+ void
+ set_final_data_size();
+
+ // Write out the data.
+ void
+ do_write(Output_file*);
+
+ // Write the data to a buffer.
+ void
+ do_write_to_buffer(unsigned char* buffer)
+ { this->strtab_->write_to_buffer(buffer, this->data_size()); }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** string table")); }
+
+ private:
+ Stringpool* strtab_;
+};
+
+// This POD class is used to represent a single reloc in the output
+// file. This could be a private class within Output_data_reloc, but
+// the templatization is complex enough that I broke it out into a
+// separate class. The class is templatized on either elfcpp::SHT_REL
+// or elfcpp::SHT_RELA, and also on whether this is a dynamic
+// relocation or an ordinary relocation.
+
+// A relocation can be against a global symbol, a local symbol, a
+// local section symbol, an output section, or the undefined symbol at
+// index 0. We represent the latter by using a NULL global symbol.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Output_reloc;
+
+template<bool dynamic, int size, bool big_endian>
+class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Addend;
+
+ static const Address invalid_address = static_cast<Address>(0) - 1;
+
+ // An uninitialized entry. We need this because we want to put
+ // instances of this class into an STL container.
+ Output_reloc()
+ : local_sym_index_(INVALID_CODE)
+ { }
+
+ // We have a bunch of different constructors. They come in pairs
+ // depending on how the address of the relocation is specified. It
+ // can either be an offset in an Output_data or an offset in an
+ // input section.
+
+ // A reloc against a global symbol.
+
+ Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
+ Address address, bool is_relative, bool is_symbolless,
+ bool use_plt_offset);
+
+ Output_reloc(Symbol* gsym, unsigned int type,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, bool is_relative,
+ bool is_symbolless, bool use_plt_offset);
+
+ // A reloc against a local symbol or local section symbol.
+
+ Output_reloc(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address, bool is_relative,
+ bool is_symbolless, bool is_section_symbol,
+ bool use_plt_offset);
+
+ Output_reloc(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ unsigned int shndx, Address address, bool is_relative,
+ bool is_symbolless, bool is_section_symbol,
+ bool use_plt_offset);
+
+ // A reloc against the STT_SECTION symbol of an output section.
+
+ Output_reloc(Output_section* os, unsigned int type, Output_data* od,
+ Address address, bool is_relative);
+
+ Output_reloc(Output_section* os, unsigned int type,
+ Sized_relobj<size, big_endian>* relobj, unsigned int shndx,
+ Address address, bool is_relative);
+
+ // An absolute or relative relocation with no symbol.
+
+ Output_reloc(unsigned int type, Output_data* od, Address address,
+ bool is_relative);
+
+ Output_reloc(unsigned int type, Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, bool is_relative);
+
+ // A target specific relocation. The target will be called to get
+ // the symbol index, passing ARG. The type and offset will be set
+ // as for other relocation types.
+
+ Output_reloc(unsigned int type, void* arg, Output_data* od,
+ Address address);
+
+ Output_reloc(unsigned int type, void* arg,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address);
+
+ // Return the reloc type.
+ unsigned int
+ type() const
+ { return this->type_; }
+
+ // Return whether this is a RELATIVE relocation.
+ bool
+ is_relative() const
+ { return this->is_relative_; }
+
+ // Return whether this is a relocation which should not use
+ // a symbol, but which obtains its addend from a symbol.
+ bool
+ is_symbolless() const
+ { return this->is_symbolless_; }
+
+ // Return whether this is against a local section symbol.
+ bool
+ is_local_section_symbol() const
+ {
+ return (this->local_sym_index_ != GSYM_CODE
+ && this->local_sym_index_ != SECTION_CODE
+ && this->local_sym_index_ != INVALID_CODE
+ && this->local_sym_index_ != TARGET_CODE
+ && this->is_section_symbol_);
+ }
+
+ // Return whether this is a target specific relocation.
+ bool
+ is_target_specific() const
+ { return this->local_sym_index_ == TARGET_CODE; }
+
+ // Return the argument to pass to the target for a target specific
+ // relocation.
+ void*
+ target_arg() const
+ {
+ gold_assert(this->local_sym_index_ == TARGET_CODE);
+ return this->u1_.arg;
+ }
+
+ // For a local section symbol, return the offset of the input
+ // section within the output section. ADDEND is the addend being
+ // applied to the input section.
+ Address
+ local_section_offset(Addend addend) const;
+
+ // Get the value of the symbol referred to by a Rel relocation when
+ // we are adding the given ADDEND.
+ Address
+ symbol_value(Addend addend) const;
+
+ // If this relocation is against an input section, return the
+ // relocatable object containing the input section.
+ Sized_relobj<size, big_endian>*
+ get_relobj() const
+ {
+ if (this->shndx_ == INVALID_CODE)
+ return NULL;
+ return this->u2_.relobj;
+ }
+
+ // Write the reloc entry to an output view.
+ void
+ write(unsigned char* pov) const;
+
+ // Write the offset and info fields to Write_rel.
+ template<typename Write_rel>
+ void write_rel(Write_rel*) const;
+
+ // This is used when sorting dynamic relocs. Return -1 to sort this
+ // reloc before R2, 0 to sort the same as R2, 1 to sort after R2.
+ int
+ compare(const Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>& r2)
+ const;
+
+ // Return whether this reloc should be sorted before the argument
+ // when sorting dynamic relocs.
+ bool
+ sort_before(const Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>&
+ r2) const
+ { return this->compare(r2) < 0; }
+
+ private:
+ // Record that we need a dynamic symbol index.
+ void
+ set_needs_dynsym_index();
+
+ // Return the symbol index.
+ unsigned int
+ get_symbol_index() const;
+
+ // Return the output address.
+ Address
+ get_address() const;
+
+ // Codes for local_sym_index_.
+ enum
+ {
+ // Global symbol.
+ GSYM_CODE = -1U,
+ // Output section.
+ SECTION_CODE = -2U,
+ // Target specific.
+ TARGET_CODE = -3U,
+ // Invalid uninitialized entry.
+ INVALID_CODE = -4U
+ };
+
+ union
+ {
+ // For a local symbol or local section symbol
+ // (this->local_sym_index_ >= 0), the object. We will never
+ // generate a relocation against a local symbol in a dynamic
+ // object; that doesn't make sense. And our callers will always
+ // be templatized, so we use Sized_relobj here.
+ Sized_relobj<size, big_endian>* relobj;
+ // For a global symbol (this->local_sym_index_ == GSYM_CODE, the
+ // symbol. If this is NULL, it indicates a relocation against the
+ // undefined 0 symbol.
+ Symbol* gsym;
+ // For a relocation against an output section
+ // (this->local_sym_index_ == SECTION_CODE), the output section.
+ Output_section* os;
+ // For a target specific relocation, an argument to pass to the
+ // target.
+ void* arg;
+ } u1_;
+ union
+ {
+ // If this->shndx_ is not INVALID CODE, the object which holds the
+ // input section being used to specify the reloc address.
+ Sized_relobj<size, big_endian>* relobj;
+ // If this->shndx_ is INVALID_CODE, the output data being used to
+ // specify the reloc address. This may be NULL if the reloc
+ // address is absolute.
+ Output_data* od;
+ } u2_;
+ // The address offset within the input section or the Output_data.
+ Address address_;
+ // This is GSYM_CODE for a global symbol, or SECTION_CODE for a
+ // relocation against an output section, or TARGET_CODE for a target
+ // specific relocation, or INVALID_CODE for an uninitialized value.
+ // Otherwise, for a local symbol (this->is_section_symbol_ is
+ // false), the local symbol index. For a local section symbol
+ // (this->is_section_symbol_ is true), the section index in the
+ // input file.
+ unsigned int local_sym_index_;
+ // The reloc type--a processor specific code.
+ unsigned int type_ : 28;
+ // True if the relocation is a RELATIVE relocation.
+ bool is_relative_ : 1;
+ // True if the relocation is one which should not use
+ // a symbol, but which obtains its addend from a symbol.
+ bool is_symbolless_ : 1;
+ // True if the relocation is against a section symbol.
+ bool is_section_symbol_ : 1;
+ // True if the addend should be the PLT offset.
+ // (Used only for RELA, but stored here for space.)
+ bool use_plt_offset_ : 1;
+ // If the reloc address is an input section in an object, the
+ // section index. This is INVALID_CODE if the reloc address is
+ // specified in some other way.
+ unsigned int shndx_;
+};
+
+// The SHT_RELA version of Output_reloc<>. This is just derived from
+// the SHT_REL version of Output_reloc, but it adds an addend.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Addend;
+
+ // An uninitialized entry.
+ Output_reloc()
+ : rel_()
+ { }
+
+ // A reloc against a global symbol.
+
+ Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
+ Address address, Addend addend, bool is_relative,
+ bool is_symbolless, bool use_plt_offset)
+ : rel_(gsym, type, od, address, is_relative, is_symbolless,
+ use_plt_offset),
+ addend_(addend)
+ { }
+
+ Output_reloc(Symbol* gsym, unsigned int type,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend,
+ bool is_relative, bool is_symbolless, bool use_plt_offset)
+ : rel_(gsym, type, relobj, shndx, address, is_relative,
+ is_symbolless, use_plt_offset), addend_(addend)
+ { }
+
+ // A reloc against a local symbol.
+
+ Output_reloc(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address,
+ Addend addend, bool is_relative,
+ bool is_symbolless, bool is_section_symbol,
+ bool use_plt_offset)
+ : rel_(relobj, local_sym_index, type, od, address, is_relative,
+ is_symbolless, is_section_symbol, use_plt_offset),
+ addend_(addend)
+ { }
+
+ Output_reloc(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ unsigned int shndx, Address address,
+ Addend addend, bool is_relative,
+ bool is_symbolless, bool is_section_symbol,
+ bool use_plt_offset)
+ : rel_(relobj, local_sym_index, type, shndx, address, is_relative,
+ is_symbolless, is_section_symbol, use_plt_offset),
+ addend_(addend)
+ { }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+
+ Output_reloc(Output_section* os, unsigned int type, Output_data* od,
+ Address address, Addend addend, bool is_relative)
+ : rel_(os, type, od, address, is_relative), addend_(addend)
+ { }
+
+ Output_reloc(Output_section* os, unsigned int type,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend,
+ bool is_relative)
+ : rel_(os, type, relobj, shndx, address, is_relative), addend_(addend)
+ { }
+
+ // An absolute or relative relocation with no symbol.
+
+ Output_reloc(unsigned int type, Output_data* od, Address address,
+ Addend addend, bool is_relative)
+ : rel_(type, od, address, is_relative), addend_(addend)
+ { }
+
+ Output_reloc(unsigned int type, Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend,
+ bool is_relative)
+ : rel_(type, relobj, shndx, address, is_relative), addend_(addend)
+ { }
+
+ // A target specific relocation. The target will be called to get
+ // the symbol index and the addend, passing ARG. The type and
+ // offset will be set as for other relocation types.
+
+ Output_reloc(unsigned int type, void* arg, Output_data* od,
+ Address address, Addend addend)
+ : rel_(type, arg, od, address), addend_(addend)
+ { }
+
+ Output_reloc(unsigned int type, void* arg,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ : rel_(type, arg, relobj, shndx, address), addend_(addend)
+ { }
+
+ // Return whether this is a RELATIVE relocation.
+ bool
+ is_relative() const
+ { return this->rel_.is_relative(); }
+
+ // Return whether this is a relocation which should not use
+ // a symbol, but which obtains its addend from a symbol.
+ bool
+ is_symbolless() const
+ { return this->rel_.is_symbolless(); }
+
+ // If this relocation is against an input section, return the
+ // relocatable object containing the input section.
+ Sized_relobj<size, big_endian>*
+ get_relobj() const
+ { return this->rel_.get_relobj(); }
+
+ // Write the reloc entry to an output view.
+ void
+ write(unsigned char* pov) const;
+
+ // Return whether this reloc should be sorted before the argument
+ // when sorting dynamic relocs.
+ bool
+ sort_before(const Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>&
+ r2) const
+ {
+ int i = this->rel_.compare(r2.rel_);
+ if (i < 0)
+ return true;
+ else if (i > 0)
+ return false;
+ else
+ return this->addend_ < r2.addend_;
+ }
+
+ private:
+ // The basic reloc.
+ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian> rel_;
+ // The addend.
+ Addend addend_;
+};
+
+// Output_data_reloc_generic is a non-template base class for
+// Output_data_reloc_base. This gives the generic code a way to hold
+// a pointer to a reloc section.
+
+class Output_data_reloc_generic : public Output_section_data_build
+{
+ public:
+ Output_data_reloc_generic(int size, bool sort_relocs)
+ : Output_section_data_build(Output_data::default_alignment_for_size(size)),
+ relative_reloc_count_(0), sort_relocs_(sort_relocs)
+ { }
+
+ // Return the number of relative relocs in this section.
+ size_t
+ relative_reloc_count() const
+ { return this->relative_reloc_count_; }
+
+ // Whether we should sort the relocs.
+ bool
+ sort_relocs() const
+ { return this->sort_relocs_; }
+
+ // Add a reloc of type TYPE against the global symbol GSYM. The
+ // relocation applies to the data at offset ADDRESS within OD.
+ virtual void
+ add_global_generic(Symbol* gsym, unsigned int type, Output_data* od,
+ uint64_t address, uint64_t addend) = 0;
+
+ // Add a reloc of type TYPE against the global symbol GSYM. The
+ // relocation applies to data at offset ADDRESS within section SHNDX
+ // of object file RELOBJ. OD is the associated output section.
+ virtual void
+ add_global_generic(Symbol* gsym, unsigned int type, Output_data* od,
+ Relobj* relobj, unsigned int shndx, uint64_t address,
+ uint64_t addend) = 0;
+
+ // Add a reloc of type TYPE against the local symbol LOCAL_SYM_INDEX
+ // in RELOBJ. The relocation applies to the data at offset ADDRESS
+ // within OD.
+ virtual void
+ add_local_generic(Relobj* relobj, unsigned int local_sym_index,
+ unsigned int type, Output_data* od, uint64_t address,
+ uint64_t addend) = 0;
+
+ // Add a reloc of type TYPE against the local symbol LOCAL_SYM_INDEX
+ // in RELOBJ. The relocation applies to the data at offset ADDRESS
+ // within section SHNDX of RELOBJ. OD is the associated output
+ // section.
+ virtual void
+ add_local_generic(Relobj* relobj, unsigned int local_sym_index,
+ unsigned int type, Output_data* od, unsigned int shndx,
+ uint64_t address, uint64_t addend) = 0;
+
+ // Add a reloc of type TYPE against the STT_SECTION symbol of the
+ // output section OS. The relocation applies to the data at offset
+ // ADDRESS within OD.
+ virtual void
+ add_output_section_generic(Output_section *os, unsigned int type,
+ Output_data* od, uint64_t address,
+ uint64_t addend) = 0;
+
+ // Add a reloc of type TYPE against the STT_SECTION symbol of the
+ // output section OS. The relocation applies to the data at offset
+ // ADDRESS within section SHNDX of RELOBJ. OD is the associated
+ // output section.
+ virtual void
+ add_output_section_generic(Output_section* os, unsigned int type,
+ Output_data* od, Relobj* relobj,
+ unsigned int shndx, uint64_t address,
+ uint64_t addend) = 0;
+
+ protected:
+ // Note that we've added another relative reloc.
+ void
+ bump_relative_reloc_count()
+ { ++this->relative_reloc_count_; }
+
+ private:
+ // The number of relative relocs added to this section. This is to
+ // support DT_RELCOUNT.
+ size_t relative_reloc_count_;
+ // Whether to sort the relocations when writing them out, to make
+ // the dynamic linker more efficient.
+ bool sort_relocs_;
+};
+
+// Output_data_reloc is used to manage a section containing relocs.
+// SH_TYPE is either elfcpp::SHT_REL or elfcpp::SHT_RELA. DYNAMIC
+// indicates whether this is a dynamic relocation or a normal
+// relocation. Output_data_reloc_base is a base class.
+// Output_data_reloc is the real class, which we specialize based on
+// the reloc type.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Output_data_reloc_base : public Output_data_reloc_generic
+{
+ public:
+ typedef Output_reloc<sh_type, dynamic, size, big_endian> Output_reloc_type;
+ typedef typename Output_reloc_type::Address Address;
+ static const int reloc_size =
+ Reloc_types<sh_type, size, big_endian>::reloc_size;
+
+ // Construct the section.
+ Output_data_reloc_base(bool sort_relocs)
+ : Output_data_reloc_generic(size, sort_relocs)
+ { }
+
+ protected:
+ // Write out the data.
+ void
+ do_write(Output_file*);
+
+ // Set the entry size and the link.
+ 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,
+ (dynamic
+ ? _("** dynamic relocs")
+ : _("** relocs")));
+ }
+
+ // Add a relocation entry.
+ void
+ add(Output_data* od, const Output_reloc_type& reloc)
+ {
+ this->relocs_.push_back(reloc);
+ this->set_current_data_size(this->relocs_.size() * reloc_size);
+ if (dynamic)
+ od->add_dynamic_reloc();
+ if (reloc.is_relative())
+ this->bump_relative_reloc_count();
+ Sized_relobj<size, big_endian>* relobj = reloc.get_relobj();
+ if (relobj != NULL)
+ relobj->add_dyn_reloc(this->relocs_.size() - 1);
+ }
+
+ private:
+ typedef std::vector<Output_reloc_type> Relocs;
+
+ // The class used to sort the relocations.
+ struct Sort_relocs_comparison
+ {
+ bool
+ operator()(const Output_reloc_type& r1, const Output_reloc_type& r2) const
+ { return r1.sort_before(r2); }
+ };
+
+ // The relocations in this section.
+ Relocs relocs_;
+};
+
+// The class which callers actually create.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Output_data_reloc;
+
+// The SHT_REL version of Output_data_reloc.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
+ : public Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>
+{
+ private:
+ typedef Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size,
+ big_endian> Base;
+
+ public:
+ typedef typename Base::Output_reloc_type Output_reloc_type;
+ typedef typename Output_reloc_type::Address Address;
+
+ Output_data_reloc(bool sr)
+ : Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>(sr)
+ { }
+
+ // Add a reloc against a global symbol.
+
+ void
+ add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address)
+ {
+ this->add(od, Output_reloc_type(gsym, type, od, address,
+ false, false, false));
+ }
+
+ void
+ add_global(Symbol* gsym, unsigned int type, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ {
+ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ false, false, false));
+ }
+
+ void
+ add_global_generic(Symbol* gsym, unsigned int type, Output_data* od,
+ uint64_t address, uint64_t addend)
+ {
+ gold_assert(addend == 0);
+ this->add(od, Output_reloc_type(gsym, type, od,
+ convert_types<Address, uint64_t>(address),
+ false, false, false));
+ }
+
+ void
+ add_global_generic(Symbol* gsym, unsigned int type, Output_data* od,
+ Relobj* relobj, unsigned int shndx, uint64_t address,
+ uint64_t addend)
+ {
+ gold_assert(addend == 0);
+ Sized_relobj<size, big_endian>* sized_relobj =
+ static_cast<Sized_relobj<size, big_endian>*>(relobj);
+ this->add(od, Output_reloc_type(gsym, type, sized_relobj, shndx,
+ convert_types<Address, uint64_t>(address),
+ false, false, false));
+ }
+
+ // Add a RELATIVE reloc against a global symbol. The final relocation
+ // will not reference the symbol.
+
+ void
+ add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
+ Address address)
+ {
+ this->add(od, Output_reloc_type(gsym, type, od, address, true, true,
+ false));
+ }
+
+ void
+ add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ {
+ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ true, true, false));
+ }
+
+ // Add a global relocation which does not use a symbol for the relocation,
+ // but which gets its addend from a symbol.
+
+ void
+ add_symbolless_global_addend(Symbol* gsym, unsigned int type,
+ Output_data* od, Address address)
+ {
+ this->add(od, Output_reloc_type(gsym, type, od, address, false, true,
+ false));
+ }
+
+ void
+ add_symbolless_global_addend(Symbol* gsym, unsigned int type,
+ Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ {
+ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ false, true, false));
+ }
+
+ // Add a reloc against a local symbol.
+
+ void
+ add_local(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
+ address, false, false, false, false));
+ }
+
+ void
+ add_local(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, unsigned int shndx, Address address)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+ address, false, false, false, false));
+ }
+
+ void
+ add_local_generic(Relobj* relobj, unsigned int local_sym_index,
+ unsigned int type, Output_data* od, uint64_t address,
+ uint64_t addend)
+ {
+ gold_assert(addend == 0);
+ Sized_relobj<size, big_endian>* sized_relobj =
+ static_cast<Sized_relobj<size, big_endian> *>(relobj);
+ this->add(od, Output_reloc_type(sized_relobj, local_sym_index, type, od,
+ convert_types<Address, uint64_t>(address),
+ false, false, false, false));
+ }
+
+ void
+ add_local_generic(Relobj* relobj, unsigned int local_sym_index,
+ unsigned int type, Output_data* od, unsigned int shndx,
+ uint64_t address, uint64_t addend)
+ {
+ gold_assert(addend == 0);
+ Sized_relobj<size, big_endian>* sized_relobj =
+ static_cast<Sized_relobj<size, big_endian>*>(relobj);
+ this->add(od, Output_reloc_type(sized_relobj, local_sym_index, type, shndx,
+ convert_types<Address, uint64_t>(address),
+ false, false, false, false));
+ }
+
+ // Add a RELATIVE reloc against a local symbol.
+
+ void
+ add_local_relative(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
+ address, true, true, false, false));
+ }
+
+ void
+ add_local_relative(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, unsigned int shndx, Address address)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+ address, true, true, false, false));
+ }
+
+ // Add a local relocation which does not use a symbol for the relocation,
+ // but which gets its addend from a symbol.
+
+ void
+ add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
+ address, false, true, false, false));
+ }
+
+ void
+ add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, unsigned int shndx,
+ Address address)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+ address, false, true, false, false));
+ }
+
+ // Add a reloc against a local section symbol. This will be
+ // converted into a reloc against the STT_SECTION symbol of the
+ // output section.
+
+ void
+ add_local_section(Sized_relobj<size, big_endian>* relobj,
+ unsigned int input_shndx, unsigned int type,
+ Output_data* od, Address address)
+ {
+ this->add(od, Output_reloc_type(relobj, input_shndx, type, od,
+ address, false, false, true, false));
+ }
+
+ void
+ add_local_section(Sized_relobj<size, big_endian>* relobj,
+ unsigned int input_shndx, unsigned int type,
+ Output_data* od, unsigned int shndx, Address address)
+ {
+ this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
+ address, false, false, true, false));
+ }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+ // OS is the Output_section that the relocation refers to; OD is
+ // the Output_data object being relocated.
+
+ void
+ add_output_section(Output_section* os, unsigned int type,
+ Output_data* od, Address address)
+ { this->add(od, Output_reloc_type(os, type, od, address, false)); }
+
+ void
+ add_output_section(Output_section* os, unsigned int type, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ { this->add(od, Output_reloc_type(os, type, relobj, shndx, address, false)); }
+
+ void
+ add_output_section_generic(Output_section* os, unsigned int type,
+ Output_data* od, uint64_t address,
+ uint64_t addend)
+ {
+ gold_assert(addend == 0);
+ this->add(od, Output_reloc_type(os, type, od,
+ convert_types<Address, uint64_t>(address),
+ false));
+ }
+
+ void
+ add_output_section_generic(Output_section* os, unsigned int type,
+ Output_data* od, Relobj* relobj,
+ unsigned int shndx, uint64_t address,
+ uint64_t addend)
+ {
+ gold_assert(addend == 0);
+ Sized_relobj<size, big_endian>* sized_relobj =
+ static_cast<Sized_relobj<size, big_endian>*>(relobj);
+ this->add(od, Output_reloc_type(os, type, sized_relobj, shndx,
+ convert_types<Address, uint64_t>(address),
+ false));
+ }
+
+ // As above, but the reloc TYPE is relative
+
+ void
+ add_output_section_relative(Output_section* os, unsigned int type,
+ Output_data* od, Address address)
+ { this->add(od, Output_reloc_type(os, type, od, address, true)); }
+
+ void
+ add_output_section_relative(Output_section* os, unsigned int type,
+ Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ { this->add(od, Output_reloc_type(os, type, relobj, shndx, address, true)); }
+
+ // Add an absolute relocation.
+
+ void
+ add_absolute(unsigned int type, Output_data* od, Address address)
+ { this->add(od, Output_reloc_type(type, od, address, false)); }
+
+ void
+ add_absolute(unsigned int type, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ { this->add(od, Output_reloc_type(type, relobj, shndx, address, false)); }
+
+ // Add a relative relocation
+
+ void
+ add_relative(unsigned int type, Output_data* od, Address address)
+ { this->add(od, Output_reloc_type(type, od, address, true)); }
+
+ void
+ add_relative(unsigned int type, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ { this->add(od, Output_reloc_type(type, relobj, shndx, address, true)); }
+
+ // Add a target specific relocation. A target which calls this must
+ // define the reloc_symbol_index and reloc_addend virtual functions.
+
+ void
+ add_target_specific(unsigned int type, void* arg, Output_data* od,
+ Address address)
+ { this->add(od, Output_reloc_type(type, arg, od, address)); }
+
+ void
+ add_target_specific(unsigned int type, void* arg, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ { this->add(od, Output_reloc_type(type, arg, relobj, shndx, address)); }
+};
+
+// The SHT_RELA version of Output_data_reloc.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
+ : public Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>
+{
+ private:
+ typedef Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size,
+ big_endian> Base;
+
+ public:
+ typedef typename Base::Output_reloc_type Output_reloc_type;
+ typedef typename Output_reloc_type::Address Address;
+ typedef typename Output_reloc_type::Addend Addend;
+
+ Output_data_reloc(bool sr)
+ : Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>(sr)
+ { }
+
+ // Add a reloc against a global symbol.
+
+ void
+ add_global(Symbol* gsym, unsigned int type, Output_data* od,
+ Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(gsym, type, od, address, addend,
+ false, false, false));
+ }
+
+ void
+ add_global(Symbol* gsym, unsigned int type, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address,
+ Addend addend)
+ {
+ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ addend, false, false, false));
+ }
+
+ void
+ add_global_generic(Symbol* gsym, unsigned int type, Output_data* od,
+ uint64_t address, uint64_t addend)
+ {
+ this->add(od, Output_reloc_type(gsym, type, od,
+ convert_types<Address, uint64_t>(address),
+ convert_types<Addend, uint64_t>(addend),
+ false, false, false));
+ }
+
+ void
+ add_global_generic(Symbol* gsym, unsigned int type, Output_data* od,
+ Relobj* relobj, unsigned int shndx, uint64_t address,
+ uint64_t addend)
+ {
+ Sized_relobj<size, big_endian>* sized_relobj =
+ static_cast<Sized_relobj<size, big_endian>*>(relobj);
+ this->add(od, Output_reloc_type(gsym, type, sized_relobj, shndx,
+ convert_types<Address, uint64_t>(address),
+ convert_types<Addend, uint64_t>(addend),
+ false, false, false));
+ }
+
+ // Add a RELATIVE reloc against a global symbol. The final output
+ // relocation will not reference the symbol, but we must keep the symbol
+ // information long enough to set the addend of the relocation correctly
+ // when it is written.
+
+ void
+ add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
+ Address address, Addend addend, bool use_plt_offset)
+ {
+ this->add(od, Output_reloc_type(gsym, type, od, address, addend, true,
+ true, use_plt_offset));
+ }
+
+ void
+ add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend,
+ bool use_plt_offset)
+ {
+ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ addend, true, true, use_plt_offset));
+ }
+
+ // Add a global relocation which does not use a symbol for the relocation,
+ // but which gets its addend from a symbol.
+
+ void
+ add_symbolless_global_addend(Symbol* gsym, unsigned int type, Output_data* od,
+ Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(gsym, type, od, address, addend,
+ false, true, false));
+ }
+
+ void
+ add_symbolless_global_addend(Symbol* gsym, unsigned int type,
+ Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address,
+ Addend addend)
+ {
+ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ addend, false, true, false));
+ }
+
+ // Add a reloc against a local symbol.
+
+ void
+ add_local(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
+ addend, false, false, false, false));
+ }
+
+ void
+ add_local(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, unsigned int shndx, Address address,
+ Addend addend)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+ address, addend, false, false, false,
+ false));
+ }
+
+ void
+ add_local_generic(Relobj* relobj, unsigned int local_sym_index,
+ unsigned int type, Output_data* od, uint64_t address,
+ uint64_t addend)
+ {
+ Sized_relobj<size, big_endian>* sized_relobj =
+ static_cast<Sized_relobj<size, big_endian> *>(relobj);
+ this->add(od, Output_reloc_type(sized_relobj, local_sym_index, type, od,
+ convert_types<Address, uint64_t>(address),
+ convert_types<Addend, uint64_t>(addend),
+ false, false, false, false));
+ }
+
+ void
+ add_local_generic(Relobj* relobj, unsigned int local_sym_index,
+ unsigned int type, Output_data* od, unsigned int shndx,
+ uint64_t address, uint64_t addend)
+ {
+ Sized_relobj<size, big_endian>* sized_relobj =
+ static_cast<Sized_relobj<size, big_endian>*>(relobj);
+ this->add(od, Output_reloc_type(sized_relobj, local_sym_index, type, shndx,
+ convert_types<Address, uint64_t>(address),
+ convert_types<Addend, uint64_t>(addend),
+ false, false, false, false));
+ }
+
+ // Add a RELATIVE reloc against a local symbol.
+
+ void
+ add_local_relative(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address, Addend addend,
+ bool use_plt_offset)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
+ addend, true, true, false,
+ use_plt_offset));
+ }
+
+ void
+ add_local_relative(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, unsigned int shndx, Address address,
+ Addend addend, bool use_plt_offset)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+ address, addend, true, true, false,
+ use_plt_offset));
+ }
+
+ // Add a local relocation which does not use a symbol for the relocation,
+ // but which gets it's addend from a symbol.
+
+ void
+ add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
+ addend, false, true, false, false));
+ }
+
+ void
+ add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, unsigned int shndx,
+ Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+ address, addend, false, true, false,
+ false));
+ }
+
+ // Add a reloc against a local section symbol. This will be
+ // converted into a reloc against the STT_SECTION symbol of the
+ // output section.
+
+ void
+ add_local_section(Sized_relobj<size, big_endian>* relobj,
+ unsigned int input_shndx, unsigned int type,
+ Output_data* od, Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(relobj, input_shndx, type, od, address,
+ addend, false, false, true, false));
+ }
+
+ void
+ add_local_section(Sized_relobj<size, big_endian>* relobj,
+ unsigned int input_shndx, unsigned int type,
+ Output_data* od, unsigned int shndx, Address address,
+ Addend addend)
+ {
+ this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
+ address, addend, false, false, true,
+ false));
+ }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+
+ void
+ add_output_section(Output_section* os, unsigned int type, Output_data* od,
+ Address address, Addend addend)
+ { this->add(od, Output_reloc_type(os, type, od, address, addend, false)); }
+
+ void
+ add_output_section(Output_section* os, unsigned int type, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(os, type, relobj, shndx, address,
+ addend, false));
+ }
+
+ void
+ add_output_section_generic(Output_section* os, unsigned int type,
+ Output_data* od, uint64_t address,
+ uint64_t addend)
+ {
+ this->add(od, Output_reloc_type(os, type, od,
+ convert_types<Address, uint64_t>(address),
+ convert_types<Addend, uint64_t>(addend),
+ false));
+ }
+
+ void
+ add_output_section_generic(Output_section* os, unsigned int type,
+ Output_data* od, Relobj* relobj,
+ unsigned int shndx, uint64_t address,
+ uint64_t addend)
+ {
+ Sized_relobj<size, big_endian>* sized_relobj =
+ static_cast<Sized_relobj<size, big_endian>*>(relobj);
+ this->add(od, Output_reloc_type(os, type, sized_relobj, shndx,
+ convert_types<Address, uint64_t>(address),
+ convert_types<Addend, uint64_t>(addend),
+ false));
+ }
+
+ // As above, but the reloc TYPE is relative
+
+ void
+ add_output_section_relative(Output_section* os, unsigned int type,
+ Output_data* od, Address address, Addend addend)
+ { this->add(od, Output_reloc_type(os, type, od, address, addend, true)); }
+
+ void
+ add_output_section_relative(Output_section* os, unsigned int type,
+ Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address,
+ Addend addend)
+ {
+ this->add(od, Output_reloc_type(os, type, relobj, shndx,
+ address, addend, true));
+ }
+
+ // Add an absolute relocation.
+
+ void
+ add_absolute(unsigned int type, Output_data* od, Address address,
+ Addend addend)
+ { this->add(od, Output_reloc_type(type, od, address, addend, false)); }
+
+ void
+ add_absolute(unsigned int type, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(type, relobj, shndx, address, addend,
+ false));
+ }
+
+ // Add a relative relocation
+
+ void
+ add_relative(unsigned int type, Output_data* od, Address address,
+ Addend addend)
+ { this->add(od, Output_reloc_type(type, od, address, addend, true)); }
+
+ void
+ add_relative(unsigned int type, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(type, relobj, shndx, address, addend,
+ true));
+ }
+
+ // Add a target specific relocation. A target which calls this must
+ // define the reloc_symbol_index and reloc_addend virtual functions.
+
+ void
+ add_target_specific(unsigned int type, void* arg, Output_data* od,
+ Address address, Addend addend)
+ { this->add(od, Output_reloc_type(type, arg, od, address, addend)); }
+
+ void
+ add_target_specific(unsigned int type, void* arg, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(type, arg, relobj, shndx, address,
+ addend));
+ }
+};
+
+// Output_relocatable_relocs represents a relocation section in a
+// relocatable link. The actual data is written out in the target
+// hook relocate_relocs. This just saves space for it.
+
+template<int sh_type, int size, bool big_endian>
+class Output_relocatable_relocs : public Output_section_data
+{
+ public:
+ Output_relocatable_relocs(Relocatable_relocs* rr)
+ : Output_section_data(Output_data::default_alignment_for_size(size)),
+ rr_(rr)
+ { }
+
+ void
+ set_final_data_size();
+
+ // Write out the data. There is nothing to do here.
+ void
+ do_write(Output_file*)
+ { }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** relocs")); }
+
+ private:
+ // The relocs associated with this input section.
+ Relocatable_relocs* rr_;
+};
+
+// Handle a GROUP section.
+
+template<int size, bool big_endian>
+class Output_data_group : public Output_section_data
+{
+ public:
+ // The constructor clears *INPUT_SHNDXES.
+ Output_data_group(Sized_relobj_file<size, big_endian>* relobj,
+ section_size_type entry_count,
+ elfcpp::Elf_Word flags,
+ std::vector<unsigned int>* input_shndxes);
+
+ void
+ do_write(Output_file*);
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** group")); }
+
+ // Set final data size.
+ void
+ set_final_data_size()
+ { this->set_data_size((this->input_shndxes_.size() + 1) * 4); }
+
+ private:
+ // The input object.
+ Sized_relobj_file<size, big_endian>* relobj_;
+ // The group flag word.
+ elfcpp::Elf_Word flags_;
+ // The section indexes of the input sections in this group.
+ std::vector<unsigned int> input_shndxes_;
+};
+
+// Output_data_got is used to manage a GOT. Each entry in the GOT is
+// for one symbol--either a global symbol or a local symbol in an
+// object. The target specific code adds entries to the GOT as
+// needed. The GOT_SIZE template parameter is the size in bits of a
+// GOT entry, typically 32 or 64.
+
+class Output_data_got_base : public Output_section_data_build
+{
+ public:
+ Output_data_got_base(uint64_t align)
+ : Output_section_data_build(align)
+ { }
+
+ Output_data_got_base(off_t data_size, uint64_t align)
+ : Output_section_data_build(data_size, align)
+ { }
+
+ // Reserve the slot at index I in the GOT.
+ void
+ reserve_slot(unsigned int i)
+ { this->do_reserve_slot(i); }
+
+ protected:
+ // Reserve the slot at index I in the GOT.
+ virtual void
+ do_reserve_slot(unsigned int i) = 0;
+};
+
+template<int got_size, bool big_endian>
+class Output_data_got : public Output_data_got_base
+{
+ public:
+ typedef typename elfcpp::Elf_types<got_size>::Elf_Addr Valtype;
+
+ Output_data_got()
+ : Output_data_got_base(Output_data::default_alignment_for_size(got_size)),
+ entries_(), free_list_()
+ { }
+
+ Output_data_got(off_t data_size)
+ : Output_data_got_base(data_size,
+ Output_data::default_alignment_for_size(got_size)),
+ entries_(), free_list_()
+ {
+ // For an incremental update, we have an existing GOT section.
+ // Initialize the list of entries and the free list.
+ this->entries_.resize(data_size / (got_size / 8));
+ this->free_list_.init(data_size, false);
+ }
+
+ // Add an entry for a global symbol to the GOT. Return true if this
+ // is a new GOT entry, false if the symbol was already in the GOT.
+ bool
+ add_global(Symbol* gsym, unsigned int got_type);
+
+ // Like add_global, but use the PLT offset of the global symbol if
+ // it has one.
+ bool
+ add_global_plt(Symbol* gsym, unsigned int got_type);
+
+ // Like add_global, but for a TLS symbol where the value will be
+ // offset using Target::tls_offset_for_global.
+ bool
+ add_global_tls(Symbol* gsym, unsigned int got_type)
+ { return add_global_plt(gsym, got_type); }
+
+ // Add an entry for a global symbol to the GOT, and add a dynamic
+ // relocation of type R_TYPE for the GOT entry.
+ void
+ add_global_with_rel(Symbol* gsym, unsigned int got_type,
+ Output_data_reloc_generic* rel_dyn, unsigned int r_type);
+
+ // Add a pair of entries for a global symbol to the GOT, and add
+ // dynamic relocations of type R_TYPE_1 and R_TYPE_2, respectively.
+ void
+ add_global_pair_with_rel(Symbol* gsym, unsigned int got_type,
+ Output_data_reloc_generic* rel_dyn,
+ unsigned int r_type_1, unsigned int r_type_2);
+
+ // Add an entry for a local symbol to the GOT. This returns true if
+ // this is a new GOT entry, false if the symbol already has a GOT
+ // entry.
+ bool
+ add_local(Relobj* object, unsigned int sym_index, unsigned int got_type);
+
+ // Like add_local, but use the PLT offset of the local symbol if it
+ // has one.
+ bool
+ add_local_plt(Relobj* object, unsigned int sym_index, unsigned int got_type);
+
+ // Like add_local, but for a TLS symbol where the value will be
+ // offset using Target::tls_offset_for_local.
+ bool
+ add_local_tls(Relobj* object, unsigned int sym_index, unsigned int got_type)
+ { return add_local_plt(object, sym_index, got_type); }
+
+ // Add an entry for a local symbol to the GOT, and add a dynamic
+ // relocation of type R_TYPE for the GOT entry.
+ void
+ add_local_with_rel(Relobj* object, unsigned int sym_index,
+ unsigned int got_type, Output_data_reloc_generic* rel_dyn,
+ unsigned int r_type);
+
+ // Add a pair of entries for a local symbol to the GOT, and add
+ // a dynamic relocation of type R_TYPE using the section symbol of
+ // the output section to which input section SHNDX maps, on the first.
+ // The first got entry will have a value of zero, the second the
+ // value of the local symbol.
+ void
+ add_local_pair_with_rel(Relobj* object, unsigned int sym_index,
+ unsigned int shndx, unsigned int got_type,
+ Output_data_reloc_generic* rel_dyn,
+ unsigned int r_type);
+
+ // Add a pair of entries for a local symbol to the GOT, and add
+ // a dynamic relocation of type R_TYPE using STN_UNDEF on the first.
+ // The first got entry will have a value of zero, the second the
+ // value of the local symbol offset by Target::tls_offset_for_local.
+ void
+ add_local_tls_pair(Relobj* object, unsigned int sym_index,
+ unsigned int got_type,
+ Output_data_reloc_generic* rel_dyn,
+ unsigned int r_type);
+
+ // Add a constant to the GOT. This returns the offset of the new
+ // entry from the start of the GOT.
+ unsigned int
+ add_constant(Valtype constant)
+ { return this->add_got_entry(Got_entry(constant)); }
+
+ // Add a pair of constants to the GOT. This returns the offset of
+ // the new entry from the start of the GOT.
+ unsigned int
+ add_constant_pair(Valtype c1, Valtype c2)
+ { return this->add_got_entry_pair(Got_entry(c1), Got_entry(c2)); }
+
+ // Replace GOT entry I with a new constant.
+ void
+ replace_constant(unsigned int i, Valtype constant)
+ {
+ this->replace_got_entry(i, Got_entry(constant));
+ }
+
+ // Reserve a slot in the GOT for a local symbol.
+ void
+ reserve_local(unsigned int i, Relobj* object, unsigned int sym_index,
+ unsigned int got_type);
+
+ // Reserve a slot in the GOT for a global symbol.
+ void
+ reserve_global(unsigned int i, Symbol* gsym, unsigned int got_type);
+
+ protected:
+ // Write out the GOT table.
+ void
+ do_write(Output_file*);
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** GOT")); }
+
+ // Reserve the slot at index I in the GOT.
+ virtual void
+ do_reserve_slot(unsigned int i)
+ { this->free_list_.remove(i * got_size / 8, (i + 1) * got_size / 8); }
+
+ // Return the number of words in the GOT.
+ unsigned int
+ num_entries () const
+ { return this->entries_.size(); }
+
+ // Return the offset into the GOT of GOT entry I.
+ unsigned int
+ got_offset(unsigned int i) const
+ { return i * (got_size / 8); }
+
+ private:
+ // This POD class holds a single GOT entry.
+ class Got_entry
+ {
+ public:
+ // Create a zero entry.
+ Got_entry()
+ : local_sym_index_(RESERVED_CODE), use_plt_or_tls_offset_(false)
+ { this->u_.constant = 0; }
+
+ // Create a global symbol entry.
+ Got_entry(Symbol* gsym, bool use_plt_or_tls_offset)
+ : local_sym_index_(GSYM_CODE),
+ use_plt_or_tls_offset_(use_plt_or_tls_offset)
+ { this->u_.gsym = gsym; }
+
+ // Create a local symbol entry.
+ Got_entry(Relobj* object, unsigned int local_sym_index,
+ bool use_plt_or_tls_offset)
+ : local_sym_index_(local_sym_index),
+ use_plt_or_tls_offset_(use_plt_or_tls_offset)
+ {
+ gold_assert(local_sym_index != GSYM_CODE
+ && local_sym_index != CONSTANT_CODE
+ && local_sym_index != RESERVED_CODE
+ && local_sym_index == this->local_sym_index_);
+ this->u_.object = object;
+ }
+
+ // Create a constant entry. The constant is a host value--it will
+ // be swapped, if necessary, when it is written out.
+ explicit Got_entry(Valtype constant)
+ : local_sym_index_(CONSTANT_CODE), use_plt_or_tls_offset_(false)
+ { this->u_.constant = constant; }
+
+ // Write the GOT entry to an output view.
+ void
+ write(unsigned int got_indx, unsigned char* pov) const;
+
+ private:
+ enum
+ {
+ GSYM_CODE = 0x7fffffff,
+ CONSTANT_CODE = 0x7ffffffe,
+ RESERVED_CODE = 0x7ffffffd
+ };
+
+ union
+ {
+ // For a local symbol, the object.
+ Relobj* object;
+ // For a global symbol, the symbol.
+ Symbol* gsym;
+ // For a constant, the constant.
+ Valtype constant;
+ } u_;
+ // For a local symbol, the local symbol index. This is GSYM_CODE
+ // for a global symbol, or CONSTANT_CODE for a constant.
+ unsigned int local_sym_index_ : 31;
+ // Whether to use the PLT offset of the symbol if it has one.
+ // For TLS symbols, whether to offset the symbol value.
+ bool use_plt_or_tls_offset_ : 1;
+ };
+
+ typedef std::vector<Got_entry> Got_entries;
+
+ // Create a new GOT entry and return its offset.
+ unsigned int
+ add_got_entry(Got_entry got_entry);
+
+ // Create a pair of new GOT entries and return the offset of the first.
+ unsigned int
+ add_got_entry_pair(Got_entry got_entry_1, Got_entry got_entry_2);
+
+ // Replace GOT entry I with a new value.
+ void
+ replace_got_entry(unsigned int i, Got_entry got_entry);
+
+ // Return the offset into the GOT of the last entry added.
+ unsigned int
+ last_got_offset() const
+ { return this->got_offset(this->num_entries() - 1); }
+
+ // Set the size of the section.
+ void
+ set_got_size()
+ { this->set_current_data_size(this->got_offset(this->num_entries())); }
+
+ // The list of GOT entries.
+ Got_entries entries_;
+
+ // List of available regions within the section, for incremental
+ // update links.
+ Free_list free_list_;
+};
+
+// Output_data_dynamic is used to hold the data in SHT_DYNAMIC
+// section.
+
+class Output_data_dynamic : public Output_section_data
+{
+ public:
+ Output_data_dynamic(Stringpool* pool)
+ : Output_section_data(Output_data::default_alignment()),
+ entries_(), pool_(pool)
+ { }
+
+ // Add a new dynamic entry with a fixed numeric value.
+ void
+ add_constant(elfcpp::DT tag, unsigned int val)
+ { this->add_entry(Dynamic_entry(tag, val)); }
+
+ // Add a new dynamic entry with the address of output data.
+ void
+ add_section_address(elfcpp::DT tag, const Output_data* od)
+ { this->add_entry(Dynamic_entry(tag, od, false)); }
+
+ // Add a new dynamic entry with the address of output data
+ // plus a constant offset.
+ void
+ add_section_plus_offset(elfcpp::DT tag, const Output_data* od,
+ unsigned int offset)
+ { this->add_entry(Dynamic_entry(tag, od, offset)); }
+
+ // Add a new dynamic entry with the size of output data.
+ void
+ add_section_size(elfcpp::DT tag, const Output_data* od)
+ { this->add_entry(Dynamic_entry(tag, od, true)); }
+
+ // Add a new dynamic entry with the total size of two output datas.
+ void
+ add_section_size(elfcpp::DT tag, const Output_data* od,
+ const Output_data* od2)
+ { this->add_entry(Dynamic_entry(tag, od, od2)); }
+
+ // Add a new dynamic entry with the address of a symbol.
+ void
+ add_symbol(elfcpp::DT tag, const Symbol* sym)
+ { this->add_entry(Dynamic_entry(tag, sym)); }
+
+ // Add a new dynamic entry with a string.
+ void
+ add_string(elfcpp::DT tag, const char* str)
+ { this->add_entry(Dynamic_entry(tag, this->pool_->add(str, true, NULL))); }
+
+ void
+ add_string(elfcpp::DT tag, const std::string& str)
+ { this->add_string(tag, str.c_str()); }
+
+ protected:
+ // Adjust the output section to set the entry size.
+ void
+ do_adjust_output_section(Output_section*);
+
+ // Set the final data size.
+ void
+ set_final_data_size();
+
+ // Write out the dynamic entries.
+ void
+ do_write(Output_file*);
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** dynamic")); }
+
+ private:
+ // This POD class holds a single dynamic entry.
+ class Dynamic_entry
+ {
+ public:
+ // Create an entry with a fixed numeric value.
+ Dynamic_entry(elfcpp::DT tag, unsigned int val)
+ : tag_(tag), offset_(DYNAMIC_NUMBER)
+ { this->u_.val = val; }
+
+ // Create an entry with the size or address of a section.
+ Dynamic_entry(elfcpp::DT tag, const Output_data* od, bool section_size)
+ : tag_(tag),
+ offset_(section_size
+ ? DYNAMIC_SECTION_SIZE
+ : DYNAMIC_SECTION_ADDRESS)
+ {
+ this->u_.od = od;
+ this->od2 = NULL;
+ }
+
+ // Create an entry with the size of two sections.
+ Dynamic_entry(elfcpp::DT tag, const Output_data* od, const Output_data* od2)
+ : tag_(tag),
+ offset_(DYNAMIC_SECTION_SIZE)
+ {
+ this->u_.od = od;
+ this->od2 = od2;
+ }
+
+ // Create an entry with the address of a section plus a constant offset.
+ Dynamic_entry(elfcpp::DT tag, const Output_data* od, unsigned int offset)
+ : tag_(tag),
+ offset_(offset)
+ { this->u_.od = od; }
+
+ // Create an entry with the address of a symbol.
+ Dynamic_entry(elfcpp::DT tag, const Symbol* sym)
+ : tag_(tag), offset_(DYNAMIC_SYMBOL)
+ { this->u_.sym = sym; }
+
+ // Create an entry with a string.
+ Dynamic_entry(elfcpp::DT tag, const char* str)
+ : tag_(tag), offset_(DYNAMIC_STRING)
+ { this->u_.str = str; }
+
+ // Return the tag of this entry.
+ elfcpp::DT
+ tag() const
+ { return this->tag_; }
+
+ // Write the dynamic entry to an output view.
+ template<int size, bool big_endian>
+ void
+ write(unsigned char* pov, const Stringpool*) const;
+
+ private:
+ // Classification is encoded in the OFFSET field.
+ enum Classification
+ {
+ // Section address.
+ DYNAMIC_SECTION_ADDRESS = 0,
+ // Number.
+ DYNAMIC_NUMBER = -1U,
+ // Section size.
+ DYNAMIC_SECTION_SIZE = -2U,
+ // Symbol adress.
+ DYNAMIC_SYMBOL = -3U,
+ // String.
+ DYNAMIC_STRING = -4U
+ // Any other value indicates a section address plus OFFSET.
+ };
+
+ union
+ {
+ // For DYNAMIC_NUMBER.
+ unsigned int val;
+ // For DYNAMIC_SECTION_SIZE and section address plus OFFSET.
+ const Output_data* od;
+ // For DYNAMIC_SYMBOL.
+ const Symbol* sym;
+ // For DYNAMIC_STRING.
+ const char* str;
+ } u_;
+ // For DYNAMIC_SYMBOL with two sections.
+ const Output_data* od2;
+ // The dynamic tag.
+ elfcpp::DT tag_;
+ // The type of entry (Classification) or offset within a section.
+ unsigned int offset_;
+ };
+
+ // Add an entry to the list.
+ void
+ add_entry(const Dynamic_entry& entry)
+ { this->entries_.push_back(entry); }
+
+ // Sized version of write function.
+ template<int size, bool big_endian>
+ void
+ sized_write(Output_file* of);
+
+ // The type of the list of entries.
+ typedef std::vector<Dynamic_entry> Dynamic_entries;
+
+ // The entries.
+ Dynamic_entries entries_;
+ // The pool used for strings.
+ Stringpool* pool_;
+};
+
+// Output_symtab_xindex is used to handle SHT_SYMTAB_SHNDX sections,
+// which may be required if the object file has more than
+// SHN_LORESERVE sections.
+
+class Output_symtab_xindex : public Output_section_data
+{
+ public:
+ Output_symtab_xindex(size_t symcount)
+ : Output_section_data(symcount * 4, 4, true),
+ entries_()
+ { }
+
+ // Add an entry: symbol number SYMNDX has section SHNDX.
+ void
+ add(unsigned int symndx, unsigned int shndx)
+ { this->entries_.push_back(std::make_pair(symndx, shndx)); }
+
+ protected:
+ void
+ do_write(Output_file*);
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** symtab xindex")); }
+
+ private:
+ template<bool big_endian>
+ void
+ endian_do_write(unsigned char*);
+
+ // It is likely that most symbols will not require entries. Rather
+ // than keep a vector for all symbols, we keep pairs of symbol index
+ // and section index.
+ typedef std::vector<std::pair<unsigned int, unsigned int> > Xindex_entries;
+
+ // The entries we need.
+ Xindex_entries entries_;
+};
+
+// A relaxed input section.
+class Output_relaxed_input_section : public Output_section_data_build
+{
+ public:
+ // We would like to call relobj->section_addralign(shndx) to get the
+ // alignment but we do not want the constructor to fail. So callers
+ // are repsonsible for ensuring that.
+ Output_relaxed_input_section(Relobj* relobj, unsigned int shndx,
+ uint64_t addralign)
+ : Output_section_data_build(addralign), relobj_(relobj), shndx_(shndx)
+ { }
+
+ // Return the Relobj of this relaxed input section.
+ Relobj*
+ relobj() const
+ { return this->relobj_; }
+
+ // Return the section index of this relaxed input section.
+ unsigned int
+ shndx() const
+ { return this->shndx_; }
+
+ protected:
+ void
+ set_relobj(Relobj* relobj)
+ { this->relobj_ = relobj; }
+
+ void
+ set_shndx(unsigned int shndx)
+ { this->shndx_ = shndx; }
+
+ private:
+ Relobj* relobj_;
+ unsigned int shndx_;
+};
+
+// This class describes properties of merge data sections. It is used
+// as a key type for maps.
+class Merge_section_properties
+{
+ public:
+ Merge_section_properties(bool is_string, uint64_t entsize,
+ uint64_t addralign)
+ : is_string_(is_string), entsize_(entsize), addralign_(addralign)
+ { }
+
+ // Whether this equals to another Merge_section_properties MSP.
+ bool
+ eq(const Merge_section_properties& msp) const
+ {
+ return ((this->is_string_ == msp.is_string_)
+ && (this->entsize_ == msp.entsize_)
+ && (this->addralign_ == msp.addralign_));
+ }
+
+ // Compute a hash value for this using 64-bit FNV-1a hash.
+ size_t
+ hash_value() const
+ {
+ uint64_t h = 14695981039346656037ULL; // FNV offset basis.
+ uint64_t prime = 1099511628211ULL;
+ h = (h ^ static_cast<uint64_t>(this->is_string_)) * prime;
+ h = (h ^ static_cast<uint64_t>(this->entsize_)) * prime;
+ h = (h ^ static_cast<uint64_t>(this->addralign_)) * prime;
+ return h;
+ }
+
+ // Functors for associative containers.
+ struct equal_to
+ {
+ bool
+ operator()(const Merge_section_properties& msp1,
+ const Merge_section_properties& msp2) const
+ { return msp1.eq(msp2); }
+ };
+
+ struct hash
+ {
+ size_t
+ operator()(const Merge_section_properties& msp) const
+ { return msp.hash_value(); }
+ };
+
+ private:
+ // Whether this merge data section is for strings.
+ bool is_string_;
+ // Entsize of this merge data section.
+ uint64_t entsize_;
+ // Address alignment.
+ uint64_t addralign_;
+};
+
+// This class is used to speed up look up of special input sections in an
+// Output_section.
+
+class Output_section_lookup_maps
+{
+ public:
+ Output_section_lookup_maps()
+ : is_valid_(true), merge_sections_by_properties_(),
+ merge_sections_by_id_(), relaxed_input_sections_by_id_()
+ { }
+
+ // Whether the maps are valid.
+ bool
+ is_valid() const
+ { return this->is_valid_; }
+
+ // Invalidate the maps.
+ void
+ invalidate()
+ { this->is_valid_ = false; }
+
+ // Clear the maps.
+ void
+ clear()
+ {
+ this->merge_sections_by_properties_.clear();
+ this->merge_sections_by_id_.clear();
+ this->relaxed_input_sections_by_id_.clear();
+ // A cleared map is valid.
+ this->is_valid_ = true;
+ }
+
+ // Find a merge section by merge section properties. Return NULL if none
+ // is found.
+ Output_merge_base*
+ find_merge_section(const Merge_section_properties& msp) const
+ {
+ gold_assert(this->is_valid_);
+ Merge_sections_by_properties::const_iterator p =
+ this->merge_sections_by_properties_.find(msp);
+ return p != this->merge_sections_by_properties_.end() ? p->second : NULL;
+ }
+
+ // Find a merge section by section ID of a merge input section. Return NULL
+ // if none is found.
+ Output_merge_base*
+ find_merge_section(const Object* object, unsigned int shndx) const
+ {
+ gold_assert(this->is_valid_);
+ Merge_sections_by_id::const_iterator p =
+ this->merge_sections_by_id_.find(Const_section_id(object, shndx));
+ return p != this->merge_sections_by_id_.end() ? p->second : NULL;
+ }
+
+ // Add a merge section pointed by POMB with properties MSP.
+ void
+ add_merge_section(const Merge_section_properties& msp,
+ Output_merge_base* pomb)
+ {
+ std::pair<Merge_section_properties, Output_merge_base*> value(msp, pomb);
+ std::pair<Merge_sections_by_properties::iterator, bool> result =
+ this->merge_sections_by_properties_.insert(value);
+ gold_assert(result.second);
+ }
+
+ // Add a mapping from a merged input section in OBJECT with index SHNDX
+ // to a merge output section pointed by POMB.
+ void
+ add_merge_input_section(const Object* object, unsigned int shndx,
+ Output_merge_base* pomb)
+ {
+ Const_section_id csid(object, shndx);
+ std::pair<Const_section_id, Output_merge_base*> value(csid, pomb);
+ std::pair<Merge_sections_by_id::iterator, bool> result =
+ this->merge_sections_by_id_.insert(value);
+ gold_assert(result.second);
+ }
+
+ // Find a relaxed input section of OBJECT with index SHNDX.
+ Output_relaxed_input_section*
+ find_relaxed_input_section(const Object* object, unsigned int shndx) const
+ {
+ gold_assert(this->is_valid_);
+ Relaxed_input_sections_by_id::const_iterator p =
+ this->relaxed_input_sections_by_id_.find(Const_section_id(object, shndx));
+ return p != this->relaxed_input_sections_by_id_.end() ? p->second : NULL;
+ }
+
+ // Add a relaxed input section pointed by POMB and whose original input
+ // section is in OBJECT with index SHNDX.
+ void
+ add_relaxed_input_section(const Relobj* relobj, unsigned int shndx,
+ Output_relaxed_input_section* poris)
+ {
+ Const_section_id csid(relobj, shndx);
+ std::pair<Const_section_id, Output_relaxed_input_section*>
+ value(csid, poris);
+ std::pair<Relaxed_input_sections_by_id::iterator, bool> result =
+ this->relaxed_input_sections_by_id_.insert(value);
+ gold_assert(result.second);
+ }
+
+ private:
+ typedef Unordered_map<Const_section_id, Output_merge_base*,
+ Const_section_id_hash>
+ Merge_sections_by_id;
+
+ typedef Unordered_map<Merge_section_properties, Output_merge_base*,
+ Merge_section_properties::hash,
+ Merge_section_properties::equal_to>
+ Merge_sections_by_properties;
+
+ typedef Unordered_map<Const_section_id, Output_relaxed_input_section*,
+ Const_section_id_hash>
+ Relaxed_input_sections_by_id;
+
+ // Whether this is valid
+ bool is_valid_;
+ // Merge sections by merge section properties.
+ Merge_sections_by_properties merge_sections_by_properties_;
+ // Merge sections by section IDs.
+ Merge_sections_by_id merge_sections_by_id_;
+ // Relaxed sections by section IDs.
+ Relaxed_input_sections_by_id relaxed_input_sections_by_id_;
+};
+
+// This abstract base class defines the interface for the
+// types of methods used to fill free space left in an output
+// section during an incremental link. These methods are used
+// to insert dummy compilation units into debug info so that
+// debug info consumers can scan the debug info serially.
+
+class Output_fill
+{
+ public:
+ Output_fill()
+ : is_big_endian_(parameters->target().is_big_endian())
+ { }
+
+ virtual
+ ~Output_fill()
+ { }
+
+ // Return the smallest size chunk of free space that can be
+ // filled with a dummy compilation unit.
+ size_t
+ minimum_hole_size() const
+ { return this->do_minimum_hole_size(); }
+
+ // Write a fill pattern of length LEN at offset OFF in the file.
+ void
+ write(Output_file* of, off_t off, size_t len) const
+ { this->do_write(of, off, len); }
+
+ protected:
+ virtual size_t
+ do_minimum_hole_size() const = 0;
+
+ virtual void
+ do_write(Output_file* of, off_t off, size_t len) const = 0;
+
+ bool
+ is_big_endian() const
+ { return this->is_big_endian_; }
+
+ private:
+ bool is_big_endian_;
+};
+
+// Fill method that introduces a dummy compilation unit in
+// a .debug_info or .debug_types section.
+
+class Output_fill_debug_info : public Output_fill
+{
+ public:
+ Output_fill_debug_info(bool is_debug_types)
+ : is_debug_types_(is_debug_types)
+ { }
+
+ protected:
+ virtual size_t
+ do_minimum_hole_size() const;
+
+ virtual void
+ do_write(Output_file* of, off_t off, size_t len) const;
+
+ private:
+ // Version of the header.
+ static const int version = 4;
+ // True if this is a .debug_types section.
+ bool is_debug_types_;
+};
+
+// Fill method that introduces a dummy compilation unit in
+// a .debug_line section.
+
+class Output_fill_debug_line : public Output_fill
+{
+ public:
+ Output_fill_debug_line()
+ { }
+
+ protected:
+ virtual size_t
+ do_minimum_hole_size() const;
+
+ virtual void
+ do_write(Output_file* of, off_t off, size_t len) const;
+
+ private:
+ // Version of the header. We write a DWARF-3 header because it's smaller
+ // and many tools have not yet been updated to understand the DWARF-4 header.
+ static const int version = 3;
+ // Length of the portion of the header that follows the header_length
+ // field. This includes the following fields:
+ // minimum_instruction_length, default_is_stmt, line_base, line_range,
+ // opcode_base, standard_opcode_lengths[], include_directories, filenames.
+ // The standard_opcode_lengths array is 12 bytes long, and the
+ // include_directories and filenames fields each contain only a single
+ // null byte.
+ static const size_t header_length = 19;
+};
+
+// An output section. We don't expect to have too many output
+// sections, so we don't bother to do a template on the size.
+
+class Output_section : public Output_data
+{
+ public:
+ // Create an output section, giving the name, type, and flags.
+ Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword);
+ virtual ~Output_section();
+
+ // Add a new input section SHNDX, named NAME, with header SHDR, from
+ // object OBJECT. RELOC_SHNDX is the index of a relocation section
+ // which applies to this section, or 0 if none, or -1 if more than
+ // one. HAVE_SECTIONS_SCRIPT is true if we have a SECTIONS clause
+ // in a linker script; in that case we need to keep track of input
+ // sections associated with an output section. Return the offset
+ // within the output section.
+ template<int size, bool big_endian>
+ off_t
+ add_input_section(Layout* layout, Sized_relobj_file<size, big_endian>* object,
+ unsigned int shndx, const char* name,
+ const elfcpp::Shdr<size, big_endian>& shdr,
+ unsigned int reloc_shndx, bool have_sections_script);
+
+ // Add generated data POSD to this output section.
+ void
+ add_output_section_data(Output_section_data* posd);
+
+ // Add a relaxed input section PORIS called NAME to this output section
+ // with LAYOUT.
+ void
+ add_relaxed_input_section(Layout* layout,
+ Output_relaxed_input_section* poris,
+ const std::string& name);
+
+ // Return the section name.
+ const char*
+ name() const
+ { return this->name_; }
+
+ // Return the section type.
+ elfcpp::Elf_Word
+ type() const
+ { return this->type_; }
+
+ // Return the section flags.
+ elfcpp::Elf_Xword
+ flags() const
+ { return this->flags_; }
+
+ typedef std::map<Section_id, unsigned int> Section_layout_order;
+
+ void
+ update_section_layout(const Section_layout_order* order_map);
+
+ // Update the output section flags based on input section flags.
+ void
+ update_flags_for_input_section(elfcpp::Elf_Xword flags);
+
+ // Return the entsize field.
+ uint64_t
+ entsize() const
+ { return this->entsize_; }
+
+ // Set the entsize field.
+ void
+ set_entsize(uint64_t v);
+
+ // Set the load address.
+ void
+ set_load_address(uint64_t load_address)
+ {
+ this->load_address_ = load_address;
+ this->has_load_address_ = true;
+ }
+
+ // Set the link field to the output section index of a section.
+ void
+ set_link_section(const Output_data* od)
+ {
+ gold_assert(this->link_ == 0
+ && !this->should_link_to_symtab_
+ && !this->should_link_to_dynsym_);
+ this->link_section_ = od;
+ }
+
+ // Set the link field to a constant.
+ void
+ set_link(unsigned int v)
+ {
+ gold_assert(this->link_section_ == NULL
+ && !this->should_link_to_symtab_
+ && !this->should_link_to_dynsym_);
+ this->link_ = v;
+ }
+
+ // Record that this section should link to the normal symbol table.
+ void
+ set_should_link_to_symtab()
+ {
+ gold_assert(this->link_section_ == NULL
+ && this->link_ == 0
+ && !this->should_link_to_dynsym_);
+ this->should_link_to_symtab_ = true;
+ }
+
+ // Record that this section should link to the dynamic symbol table.
+ void
+ set_should_link_to_dynsym()
+ {
+ gold_assert(this->link_section_ == NULL
+ && this->link_ == 0
+ && !this->should_link_to_symtab_);
+ this->should_link_to_dynsym_ = true;
+ }
+
+ // Return the info field.
+ unsigned int
+ info() const
+ {
+ gold_assert(this->info_section_ == NULL
+ && this->info_symndx_ == NULL);
+ return this->info_;
+ }
+
+ // Set the info field to the output section index of a section.
+ void
+ set_info_section(const Output_section* os)
+ {
+ gold_assert((this->info_section_ == NULL
+ || (this->info_section_ == os
+ && this->info_uses_section_index_))
+ && this->info_symndx_ == NULL
+ && this->info_ == 0);
+ this->info_section_ = os;
+ this->info_uses_section_index_= true;
+ }
+
+ // Set the info field to the symbol table index of a symbol.
+ void
+ set_info_symndx(const Symbol* sym)
+ {
+ gold_assert(this->info_section_ == NULL
+ && (this->info_symndx_ == NULL
+ || this->info_symndx_ == sym)
+ && this->info_ == 0);
+ this->info_symndx_ = sym;
+ }
+
+ // Set the info field to the symbol table index of a section symbol.
+ void
+ set_info_section_symndx(const Output_section* os)
+ {
+ gold_assert((this->info_section_ == NULL
+ || (this->info_section_ == os
+ && !this->info_uses_section_index_))
+ && this->info_symndx_ == NULL
+ && this->info_ == 0);
+ this->info_section_ = os;
+ this->info_uses_section_index_ = false;
+ }
+
+ // Set the info field to a constant.
+ void
+ set_info(unsigned int v)
+ {
+ gold_assert(this->info_section_ == NULL
+ && this->info_symndx_ == NULL
+ && (this->info_ == 0
+ || this->info_ == v));
+ this->info_ = v;
+ }
+
+ // Set the addralign field.
+ void
+ set_addralign(uint64_t v)
+ { this->addralign_ = v; }
+
+ void
+ checkpoint_set_addralign(uint64_t val)
+ {
+ if (this->checkpoint_ != NULL)
+ this->checkpoint_->set_addralign(val);
+ }
+
+ // Whether the output section index has been set.
+ bool
+ has_out_shndx() const
+ { return this->out_shndx_ != -1U; }
+
+ // Indicate that we need a symtab index.
+ void
+ set_needs_symtab_index()
+ { this->needs_symtab_index_ = true; }
+
+ // Return whether we need a symtab index.
+ bool
+ needs_symtab_index() const
+ { return this->needs_symtab_index_; }
+
+ // Get the symtab index.
+ unsigned int
+ symtab_index() const
+ {
+ gold_assert(this->symtab_index_ != 0);
+ return this->symtab_index_;
+ }
+
+ // Set the symtab index.
+ void
+ set_symtab_index(unsigned int index)
+ {
+ gold_assert(index != 0);
+ this->symtab_index_ = index;
+ }
+
+ // Indicate that we need a dynsym index.
+ void
+ set_needs_dynsym_index()
+ { this->needs_dynsym_index_ = true; }
+
+ // Return whether we need a dynsym index.
+ bool
+ needs_dynsym_index() const
+ { return this->needs_dynsym_index_; }
+
+ // Get the dynsym index.
+ unsigned int
+ dynsym_index() const
+ {
+ gold_assert(this->dynsym_index_ != 0);
+ return this->dynsym_index_;
+ }
+
+ // Set the dynsym index.
+ void
+ set_dynsym_index(unsigned int index)
+ {
+ gold_assert(index != 0);
+ this->dynsym_index_ = index;
+ }
+
+ // Sort the attached input sections.
+ void
+ sort_attached_input_sections();
+
+ // Return whether the input sections sections attachd to this output
+ // section may require sorting. This is used to handle constructor
+ // priorities compatibly with GNU ld.
+ bool
+ may_sort_attached_input_sections() const
+ { return this->may_sort_attached_input_sections_; }
+
+ // Record that the input sections attached to this output section
+ // may require sorting.
+ void
+ set_may_sort_attached_input_sections()
+ { this->may_sort_attached_input_sections_ = true; }
+
+ // Returns true if input sections must be sorted according to the
+ // order in which their name appear in the --section-ordering-file.
+ bool
+ input_section_order_specified()
+ { return this->input_section_order_specified_; }
+
+ // Record that input sections must be sorted as some of their names
+ // match the patterns specified through --section-ordering-file.
+ void
+ set_input_section_order_specified()
+ { this->input_section_order_specified_ = true; }
+
+ // Return whether the input sections attached to this output section
+ // require sorting. This is used to handle constructor priorities
+ // compatibly with GNU ld.
+ bool
+ must_sort_attached_input_sections() const
+ { return this->must_sort_attached_input_sections_; }
+
+ // Record that the input sections attached to this output section
+ // require sorting.
+ void
+ set_must_sort_attached_input_sections()
+ { this->must_sort_attached_input_sections_ = true; }
+
+ // Get the order in which this section appears in the PT_LOAD output
+ // segment.
+ Output_section_order
+ order() const
+ { return this->order_; }
+
+ // Set the order for this section.
+ void
+ set_order(Output_section_order order)
+ { this->order_ = order; }
+
+ // Return whether this section holds relro data--data which has
+ // dynamic relocations but which may be marked read-only after the
+ // dynamic relocations have been completed.
+ bool
+ is_relro() const
+ { return this->is_relro_; }
+
+ // Record that this section holds relro data.
+ void
+ set_is_relro()
+ { this->is_relro_ = true; }
+
+ // Record that this section does not hold relro data.
+ void
+ clear_is_relro()
+ { this->is_relro_ = false; }
+
+ // True if this is a small section: a section which holds small
+ // variables.
+ bool
+ is_small_section() const
+ { return this->is_small_section_; }
+
+ // Record that this is a small section.
+ void
+ set_is_small_section()
+ { this->is_small_section_ = true; }
+
+ // True if this is a large section: a section which holds large
+ // variables.
+ bool
+ is_large_section() const
+ { return this->is_large_section_; }
+
+ // Record that this is a large section.
+ void
+ set_is_large_section()
+ { this->is_large_section_ = true; }
+
+ // True if this is a large data (not BSS) section.
+ bool
+ is_large_data_section()
+ { return this->is_large_section_ && this->type_ != elfcpp::SHT_NOBITS; }
+
+ // Return whether this section should be written after all the input
+ // sections are complete.
+ bool
+ after_input_sections() const
+ { return this->after_input_sections_; }
+
+ // Record that this section should be written after all the input
+ // sections are complete.
+ void
+ set_after_input_sections()
+ { this->after_input_sections_ = true; }
+
+ // Return whether this section requires postprocessing after all
+ // relocations have been applied.
+ bool
+ requires_postprocessing() const
+ { return this->requires_postprocessing_; }
+
+ bool
+ is_unique_segment() const
+ { return this->is_unique_segment_; }
+
+ void
+ set_is_unique_segment()
+ { this->is_unique_segment_ = true; }
+
+ uint64_t extra_segment_flags() const
+ { return this->extra_segment_flags_; }
+
+ void
+ set_extra_segment_flags(uint64_t flags)
+ { this->extra_segment_flags_ = flags; }
+
+ uint64_t segment_alignment() const
+ { return this->segment_alignment_; }
+
+ void
+ set_segment_alignment(uint64_t align)
+ { this->segment_alignment_ = align; }
+
+ // If a section requires postprocessing, return the buffer to use.
+ unsigned char*
+ postprocessing_buffer() const
+ {
+ gold_assert(this->postprocessing_buffer_ != NULL);
+ return this->postprocessing_buffer_;
+ }
+
+ // If a section requires postprocessing, create the buffer to use.
+ void
+ create_postprocessing_buffer();
+
+ // If a section requires postprocessing, this is the size of the
+ // buffer to which relocations should be applied.
+ off_t
+ postprocessing_buffer_size() const
+ { return this->current_data_size_for_child(); }
+
+ // Modify the section name. This is only permitted for an
+ // unallocated section, and only before the size has been finalized.
+ // Otherwise the name will not get into Layout::namepool_.
+ void
+ set_name(const char* newname)
+ {
+ gold_assert((this->flags_ & elfcpp::SHF_ALLOC) == 0);
+ gold_assert(!this->is_data_size_valid());
+ this->name_ = newname;
+ }
+
+ // Return whether the offset OFFSET in the input section SHNDX in
+ // object OBJECT is being included in the link.
+ bool
+ is_input_address_mapped(const Relobj* object, unsigned int shndx,
+ off_t offset) const;
+
+ // Return the offset within the output section of OFFSET relative to
+ // the start of input section SHNDX in object OBJECT.
+ section_offset_type
+ output_offset(const Relobj* object, unsigned int shndx,
+ section_offset_type offset) const;
+
+ // Return the output virtual address of OFFSET relative to the start
+ // of input section SHNDX in object OBJECT.
+ uint64_t
+ output_address(const Relobj* object, unsigned int shndx,
+ off_t offset) const;
+
+ // Look for the merged section for input section SHNDX in object
+ // OBJECT. If found, return true, and set *ADDR to the address of
+ // the start of the merged section. This is not necessary the
+ // output offset corresponding to input offset 0 in the section,
+ // since the section may be mapped arbitrarily.
+ bool
+ find_starting_output_address(const Relobj* object, unsigned int shndx,
+ uint64_t* addr) const;
+
+ // Record that this output section was found in the SECTIONS clause
+ // of a linker script.
+ void
+ set_found_in_sections_clause()
+ { this->found_in_sections_clause_ = true; }
+
+ // Return whether this output section was found in the SECTIONS
+ // clause of a linker script.
+ bool
+ found_in_sections_clause() const
+ { return this->found_in_sections_clause_; }
+
+ // Write the section header into *OPHDR.
+ template<int size, bool big_endian>
+ void
+ write_header(const Layout*, const Stringpool*,
+ elfcpp::Shdr_write<size, big_endian>*) const;
+
+ // The next few calls are for linker script support.
+
+ // In some cases we need to keep a list of the input sections
+ // associated with this output section. We only need the list if we
+ // might have to change the offsets of the input section within the
+ // output section after we add the input section. The ordinary
+ // input sections will be written out when we process the object
+ // file, and as such we don't need to track them here. We do need
+ // to track Output_section_data objects here. We store instances of
+ // this structure in a std::vector, so it must be a POD. There can
+ // be many instances of this structure, so we use a union to save
+ // some space.
+ class Input_section
+ {
+ public:
+ Input_section()
+ : shndx_(0), p2align_(0)
+ {
+ this->u1_.data_size = 0;
+ this->u2_.object = NULL;
+ }
+
+ // For an ordinary input section.
+ Input_section(Relobj* object, unsigned int shndx, off_t data_size,
+ uint64_t addralign)
+ : shndx_(shndx),
+ p2align_(ffsll(static_cast<long long>(addralign))),
+ section_order_index_(0)
+ {
+ gold_assert(shndx != OUTPUT_SECTION_CODE
+ && shndx != MERGE_DATA_SECTION_CODE
+ && shndx != MERGE_STRING_SECTION_CODE
+ && shndx != RELAXED_INPUT_SECTION_CODE);
+ this->u1_.data_size = data_size;
+ this->u2_.object = object;
+ }
+
+ // For a non-merge output section.
+ Input_section(Output_section_data* posd)
+ : shndx_(OUTPUT_SECTION_CODE), p2align_(0),
+ section_order_index_(0)
+ {
+ this->u1_.data_size = 0;
+ this->u2_.posd = posd;
+ }
+
+ // For a merge section.
+ Input_section(Output_section_data* posd, bool is_string, uint64_t entsize)
+ : shndx_(is_string
+ ? MERGE_STRING_SECTION_CODE
+ : MERGE_DATA_SECTION_CODE),
+ p2align_(0),
+ section_order_index_(0)
+ {
+ this->u1_.entsize = entsize;
+ this->u2_.posd = posd;
+ }
+
+ // For a relaxed input section.
+ Input_section(Output_relaxed_input_section* psection)
+ : shndx_(RELAXED_INPUT_SECTION_CODE), p2align_(0),
+ section_order_index_(0)
+ {
+ this->u1_.data_size = 0;
+ this->u2_.poris = psection;
+ }
+
+ unsigned int
+ section_order_index() const
+ {
+ return this->section_order_index_;
+ }
+
+ void
+ set_section_order_index(unsigned int number)
+ {
+ this->section_order_index_ = number;
+ }
+
+ // The required alignment.
+ uint64_t
+ addralign() const
+ {
+ if (this->p2align_ != 0)
+ return static_cast<uint64_t>(1) << (this->p2align_ - 1);
+ else if (!this->is_input_section())
+ return this->u2_.posd->addralign();
+ else
+ return 0;
+ }
+
+ // Set the required alignment, which must be either 0 or a power of 2.
+ // For input sections that are sub-classes of Output_section_data, a
+ // alignment of zero means asking the underlying object for alignment.
+ void
+ set_addralign(uint64_t addralign)
+ {
+ if (addralign == 0)
+ this->p2align_ = 0;
+ else
+ {
+ gold_assert((addralign & (addralign - 1)) == 0);
+ this->p2align_ = ffsll(static_cast<long long>(addralign));
+ }
+ }
+
+ // Return the current required size, without finalization.
+ off_t
+ current_data_size() const;
+
+ // Return the required size.
+ off_t
+ data_size() const;
+
+ // Whether this is an input section.
+ bool
+ is_input_section() const
+ {
+ return (this->shndx_ != OUTPUT_SECTION_CODE
+ && this->shndx_ != MERGE_DATA_SECTION_CODE
+ && this->shndx_ != MERGE_STRING_SECTION_CODE
+ && this->shndx_ != RELAXED_INPUT_SECTION_CODE);
+ }
+
+ // Return whether this is a merge section which matches the
+ // parameters.
+ bool
+ is_merge_section(bool is_string, uint64_t entsize,
+ uint64_t addralign) const
+ {
+ return (this->shndx_ == (is_string
+ ? MERGE_STRING_SECTION_CODE
+ : MERGE_DATA_SECTION_CODE)
+ && this->u1_.entsize == entsize
+ && this->addralign() == addralign);
+ }
+
+ // Return whether this is a merge section for some input section.
+ bool
+ is_merge_section() const
+ {
+ return (this->shndx_ == MERGE_DATA_SECTION_CODE
+ || this->shndx_ == MERGE_STRING_SECTION_CODE);
+ }
+
+ // Return whether this is a relaxed input section.
+ bool
+ is_relaxed_input_section() const
+ { return this->shndx_ == RELAXED_INPUT_SECTION_CODE; }
+
+ // Return whether this is a generic Output_section_data.
+ bool
+ is_output_section_data() const
+ {
+ return this->shndx_ == OUTPUT_SECTION_CODE;
+ }
+
+ // Return the object for an input section.
+ Relobj*
+ relobj() const;
+
+ // Return the input section index for an input section.
+ unsigned int
+ shndx() const;
+
+ // For non-input-sections, return the associated Output_section_data
+ // object.
+ Output_section_data*
+ output_section_data() const
+ {
+ gold_assert(!this->is_input_section());
+ return this->u2_.posd;
+ }
+
+ // For a merge section, return the Output_merge_base pointer.
+ Output_merge_base*
+ output_merge_base() const
+ {
+ gold_assert(this->is_merge_section());
+ return this->u2_.pomb;
+ }
+
+ // Return the Output_relaxed_input_section object.
+ Output_relaxed_input_section*
+ relaxed_input_section() const
+ {
+ gold_assert(this->is_relaxed_input_section());
+ return this->u2_.poris;
+ }
+
+ // Set the output section.
+ void
+ set_output_section(Output_section* os)
+ {
+ gold_assert(!this->is_input_section());
+ Output_section_data* posd =
+ this->is_relaxed_input_section() ? this->u2_.poris : this->u2_.posd;
+ posd->set_output_section(os);
+ }
+
+ // Set the address and file offset. This is called during
+ // Layout::finalize. SECTION_FILE_OFFSET is the file offset of
+ // the enclosing section.
+ void
+ set_address_and_file_offset(uint64_t address, off_t file_offset,
+ off_t section_file_offset);
+
+ // Reset the address and file offset.
+ void
+ reset_address_and_file_offset();
+
+ // Finalize the data size.
+ void
+ finalize_data_size();
+
+ // Add an input section, for SHF_MERGE sections.
+ bool
+ add_input_section(Relobj* object, unsigned int shndx)
+ {
+ gold_assert(this->shndx_ == MERGE_DATA_SECTION_CODE
+ || this->shndx_ == MERGE_STRING_SECTION_CODE);
+ return this->u2_.posd->add_input_section(object, shndx);
+ }
+
+ // 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 output offset is known. If
+ // this function returns true, it sets *POUTPUT to the offset in
+ // the output section, relative to the start of the input section
+ // in the output section. *POUTPUT may be different from OFFSET
+ // for a merged section.
+ bool
+ 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 the input section
+ // SHNDX in OBJECT.
+ bool
+ is_merge_section_for(const Relobj* object, unsigned int shndx) const;
+
+ // Write out the data. This does nothing for an input section.
+ void
+ write(Output_file*);
+
+ // Write the data to a buffer. This does nothing for an input
+ // section.
+ void
+ write_to_buffer(unsigned char*);
+
+ // Print to a map file.
+ void
+ print_to_mapfile(Mapfile*) const;
+
+ // Print statistics about merge sections to stderr.
+ void
+ print_merge_stats(const char* section_name)
+ {
+ if (this->shndx_ == MERGE_DATA_SECTION_CODE
+ || this->shndx_ == MERGE_STRING_SECTION_CODE)
+ this->u2_.posd->print_merge_stats(section_name);
+ }
+
+ private:
+ // Code values which appear in shndx_. If the value is not one of
+ // these codes, it is the input section index in the object file.
+ enum
+ {
+ // An Output_section_data.
+ OUTPUT_SECTION_CODE = -1U,
+ // An Output_section_data for an SHF_MERGE section with
+ // SHF_STRINGS not set.
+ MERGE_DATA_SECTION_CODE = -2U,
+ // An Output_section_data for an SHF_MERGE section with
+ // SHF_STRINGS set.
+ MERGE_STRING_SECTION_CODE = -3U,
+ // An Output_section_data for a relaxed input section.
+ RELAXED_INPUT_SECTION_CODE = -4U
+ };
+
+ // For an ordinary input section, this is the section index in the
+ // input file. For an Output_section_data, this is
+ // OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
+ // MERGE_STRING_SECTION_CODE.
+ unsigned int shndx_;
+ // The required alignment, stored as a power of 2.
+ unsigned int p2align_;
+ union
+ {
+ // For an ordinary input section, the section size.
+ off_t data_size;
+ // For OUTPUT_SECTION_CODE or RELAXED_INPUT_SECTION_CODE, this is not
+ // used. For MERGE_DATA_SECTION_CODE or MERGE_STRING_SECTION_CODE, the
+ // entity size.
+ uint64_t entsize;
+ } u1_;
+ union
+ {
+ // For an ordinary input section, the object which holds the
+ // input section.
+ Relobj* object;
+ // For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
+ // MERGE_STRING_SECTION_CODE, the data.
+ Output_section_data* posd;
+ Output_merge_base* pomb;
+ // For RELAXED_INPUT_SECTION_CODE, the data.
+ Output_relaxed_input_section* poris;
+ } u2_;
+ // The line number of the pattern it matches in the --section-ordering-file
+ // file. It is 0 if does not match any pattern.
+ unsigned int section_order_index_;
+ };
+
+ // Store the list of input sections for this Output_section into the
+ // list passed in. This removes the input sections, leaving only
+ // any Output_section_data elements. This returns the size of those
+ // Output_section_data elements. ADDRESS is the address of this
+ // output section. FILL is the fill value to use, in case there are
+ // any spaces between the remaining Output_section_data elements.
+ uint64_t
+ get_input_sections(uint64_t address, const std::string& fill,
+ std::list<Input_section>*);
+
+ // Add a script input section. A script input section can either be
+ // a plain input section or a sub-class of Output_section_data.
+ void
+ add_script_input_section(const Input_section& input_section);
+
+ // Set the current size of the output section.
+ void
+ set_current_data_size(off_t size)
+ { this->set_current_data_size_for_child(size); }
+
+ // End of linker script support.
+
+ // Save states before doing section layout.
+ // This is used for relaxation.
+ void
+ save_states();
+
+ // Restore states prior to section layout.
+ void
+ restore_states();
+
+ // Discard states.
+ void
+ discard_states();
+
+ // Convert existing input sections to relaxed input sections.
+ void
+ convert_input_sections_to_relaxed_sections(
+ const std::vector<Output_relaxed_input_section*>& sections);
+
+ // Find a relaxed input section to an input section in OBJECT
+ // with index SHNDX. Return NULL if none is found.
+ const Output_relaxed_input_section*
+ find_relaxed_input_section(const Relobj* object, unsigned int shndx) const;
+
+ // Whether section offsets need adjustment due to relaxation.
+ bool
+ section_offsets_need_adjustment() const
+ { return this->section_offsets_need_adjustment_; }
+
+ // Set section_offsets_need_adjustment to be true.
+ void
+ set_section_offsets_need_adjustment()
+ { this->section_offsets_need_adjustment_ = true; }
+
+ // Set section_offsets_need_adjustment to be false.
+ void
+ clear_section_offsets_need_adjustment()
+ { this->section_offsets_need_adjustment_ = false; }
+
+ // Adjust section offsets of input sections in this. This is
+ // requires if relaxation caused some input sections to change sizes.
+ void
+ adjust_section_offsets();
+
+ // Whether this is a NOLOAD section.
+ bool
+ is_noload() const
+ { return this->is_noload_; }
+
+ // Set NOLOAD flag.
+ void
+ set_is_noload()
+ { this->is_noload_ = true; }
+
+ // Print merge statistics to stderr.
+ void
+ print_merge_stats();
+
+ // Set a fixed layout for the section. Used for incremental update links.
+ void
+ set_fixed_layout(uint64_t sh_addr, off_t sh_offset, off_t sh_size,
+ uint64_t sh_addralign);
+
+ // Return TRUE if the section has a fixed layout.
+ bool
+ has_fixed_layout() const
+ { return this->has_fixed_layout_; }
+
+ // Set flag to allow patch space for this section. Used for full
+ // incremental links.
+ void
+ set_is_patch_space_allowed()
+ { this->is_patch_space_allowed_ = true; }
+
+ // Set a fill method to use for free space left in the output section
+ // during incremental links.
+ void
+ set_free_space_fill(Output_fill* free_space_fill)
+ {
+ this->free_space_fill_ = free_space_fill;
+ this->free_list_.set_min_hole_size(free_space_fill->minimum_hole_size());
+ }
+
+ // Reserve space within the fixed layout for the section. Used for
+ // incremental update links.
+ void
+ reserve(uint64_t sh_offset, uint64_t sh_size);
+
+ // Allocate space from the free list for the section. Used for
+ // incremental update links.
+ off_t
+ allocate(off_t len, uint64_t addralign);
+
+ typedef std::vector<Input_section> Input_section_list;
+
+ // Allow access to the input sections.
+ const Input_section_list&
+ input_sections() const
+ { return this->input_sections_; }
+
+ Input_section_list&
+ input_sections()
+ { return this->input_sections_; }
+
+ protected:
+ // Return the output section--i.e., the object itself.
+ Output_section*
+ do_output_section()
+ { return this; }
+
+ const Output_section*
+ do_output_section() const
+ { return this; }
+
+ // Return the section index in the output file.
+ unsigned int
+ do_out_shndx() const
+ {
+ gold_assert(this->out_shndx_ != -1U);
+ return this->out_shndx_;
+ }
+
+ // Set the output section index.
+ void
+ do_set_out_shndx(unsigned int shndx)
+ {
+ gold_assert(this->out_shndx_ == -1U || this->out_shndx_ == shndx);
+ this->out_shndx_ = shndx;
+ }
+
+ // Update the data size of the Output_section. For a typical
+ // Output_section, there is nothing to do, but if there are any
+ // Output_section_data objects we need to do a trial layout
+ // here.
+ virtual void
+ update_data_size();
+
+ // Set the final data size of the Output_section. For a typical
+ // Output_section, there is nothing to do, but if there are any
+ // Output_section_data objects we need to set their final addresses
+ // here.
+ virtual void
+ set_final_data_size();
+
+ // Reset the address and file offset.
+ void
+ do_reset_address_and_file_offset();
+
+ // Return true if address and file offset already have reset values. In
+ // other words, calling reset_address_and_file_offset will not change them.
+ bool
+ do_address_and_file_offset_have_reset_values() const;
+
+ // Write the data to the file. For a typical Output_section, this
+ // does nothing: the data is written out by calling Object::Relocate
+ // on each input object. But if there are any Output_section_data
+ // objects we do need to write them out here.
+ virtual void
+ do_write(Output_file*);
+
+ // Return the address alignment--function required by parent class.
+ uint64_t
+ do_addralign() const
+ { return this->addralign_; }
+
+ // Return whether there is a load address.
+ bool
+ do_has_load_address() const
+ { return this->has_load_address_; }
+
+ // Return the load address.
+ uint64_t
+ do_load_address() const
+ {
+ gold_assert(this->has_load_address_);
+ return this->load_address_;
+ }
+
+ // Return whether this is an Output_section.
+ bool
+ do_is_section() const
+ { return true; }
+
+ // Return whether this is a section of the specified type.
+ bool
+ do_is_section_type(elfcpp::Elf_Word type) const
+ { return this->type_ == type; }
+
+ // Return whether the specified section flag is set.
+ bool
+ do_is_section_flag_set(elfcpp::Elf_Xword flag) const
+ { return (this->flags_ & flag) != 0; }
+
+ // Set the TLS offset. Called only for SHT_TLS sections.
+ void
+ do_set_tls_offset(uint64_t tls_base);
+
+ // Return the TLS offset, relative to the base of the TLS segment.
+ // Valid only for SHT_TLS sections.
+ uint64_t
+ do_tls_offset() const
+ { return this->tls_offset_; }
+
+ // This may be implemented by a child class.
+ virtual void
+ do_finalize_name(Layout*)
+ { }
+
+ // Print to the map file.
+ virtual void
+ do_print_to_mapfile(Mapfile*) const;
+
+ // Record that this section requires postprocessing after all
+ // relocations have been applied. This is called by a child class.
+ void
+ set_requires_postprocessing()
+ {
+ this->requires_postprocessing_ = true;
+ this->after_input_sections_ = true;
+ }
+
+ // Write all the data of an Output_section into the postprocessing
+ // buffer.
+ void
+ write_to_postprocessing_buffer();
+
+ // Whether this always keeps an input section list
+ bool
+ always_keeps_input_sections() const
+ { return this->always_keeps_input_sections_; }
+
+ // Always keep an input section list.
+ void
+ set_always_keeps_input_sections()
+ {
+ gold_assert(this->current_data_size_for_child() == 0);
+ this->always_keeps_input_sections_ = true;
+ }
+
+ private:
+ // We only save enough information to undo the effects of section layout.
+ class Checkpoint_output_section
+ {
+ public:
+ Checkpoint_output_section(uint64_t addralign, elfcpp::Elf_Xword flags,
+ const Input_section_list& input_sections,
+ off_t first_input_offset,
+ bool attached_input_sections_are_sorted)
+ : addralign_(addralign), flags_(flags),
+ input_sections_(input_sections),
+ input_sections_size_(input_sections_.size()),
+ input_sections_copy_(), first_input_offset_(first_input_offset),
+ attached_input_sections_are_sorted_(attached_input_sections_are_sorted)
+ { }
+
+ virtual
+ ~Checkpoint_output_section()
+ { }
+
+ // Return the address alignment.
+ uint64_t
+ addralign() const
+ { return this->addralign_; }
+
+ void
+ set_addralign(uint64_t val)
+ { this->addralign_ = val; }
+
+ // Return the section flags.
+ elfcpp::Elf_Xword
+ flags() const
+ { return this->flags_; }
+
+ // Return a reference to the input section list copy.
+ Input_section_list*
+ input_sections()
+ { return &this->input_sections_copy_; }
+
+ // Return the size of input_sections at the time when checkpoint is
+ // taken.
+ size_t
+ input_sections_size() const
+ { return this->input_sections_size_; }
+
+ // Whether input sections are copied.
+ bool
+ input_sections_saved() const
+ { return this->input_sections_copy_.size() == this->input_sections_size_; }
+
+ off_t
+ first_input_offset() const
+ { return this->first_input_offset_; }
+
+ bool
+ attached_input_sections_are_sorted() const
+ { return this->attached_input_sections_are_sorted_; }
+
+ // Save input sections.
+ void
+ save_input_sections()
+ {
+ this->input_sections_copy_.reserve(this->input_sections_size_);
+ this->input_sections_copy_.clear();
+ Input_section_list::const_iterator p = this->input_sections_.begin();
+ gold_assert(this->input_sections_size_ >= this->input_sections_.size());
+ for(size_t i = 0; i < this->input_sections_size_ ; i++, ++p)
+ this->input_sections_copy_.push_back(*p);
+ }
+
+ private:
+ // The section alignment.
+ uint64_t addralign_;
+ // The section flags.
+ elfcpp::Elf_Xword flags_;
+ // Reference to the input sections to be checkpointed.
+ const Input_section_list& input_sections_;
+ // Size of the checkpointed portion of input_sections_;
+ size_t input_sections_size_;
+ // Copy of input sections.
+ Input_section_list input_sections_copy_;
+ // The offset of the first entry in input_sections_.
+ off_t first_input_offset_;
+ // True if the input sections attached to this output section have
+ // already been sorted.
+ bool attached_input_sections_are_sorted_;
+ };
+
+ // This class is used to sort the input sections.
+ class Input_section_sort_entry;
+
+ // This is the sort comparison function for ctors and dtors.
+ struct Input_section_sort_compare
+ {
+ bool
+ operator()(const Input_section_sort_entry&,
+ const Input_section_sort_entry&) const;
+ };
+
+ // This is the sort comparison function for .init_array and .fini_array.
+ struct Input_section_sort_init_fini_compare
+ {
+ bool
+ operator()(const Input_section_sort_entry&,
+ const Input_section_sort_entry&) const;
+ };
+
+ // This is the sort comparison function when a section order is specified
+ // from an input file.
+ struct Input_section_sort_section_order_index_compare
+ {
+ bool
+ operator()(const Input_section_sort_entry&,
+ const Input_section_sort_entry&) const;
+ };
+
+ // This is the sort comparison function for .text to sort sections with
+ // prefixes .text.{unlikely,exit,startup,hot} before other sections.
+ struct Input_section_sort_section_prefix_special_ordering_compare
+ {
+ bool
+ operator()(const Input_section_sort_entry&,
+ const Input_section_sort_entry&) const;
+ };
+
+ // This is the sort comparison function for sorting sections by name.
+ struct Input_section_sort_section_name_compare
+ {
+ bool
+ operator()(const Input_section_sort_entry&,
+ const Input_section_sort_entry&) const;
+ };
+
+ // Fill data. This is used to fill in data between input sections.
+ // It is also used for data statements (BYTE, WORD, etc.) in linker
+ // scripts. When we have to keep track of the input sections, we
+ // can use an Output_data_const, but we don't want to have to keep
+ // track of input sections just to implement fills.
+ class Fill
+ {
+ public:
+ Fill(off_t section_offset, off_t length)
+ : section_offset_(section_offset),
+ length_(convert_to_section_size_type(length))
+ { }
+
+ // Return section offset.
+ off_t
+ section_offset() const
+ { return this->section_offset_; }
+
+ // Return fill length.
+ section_size_type
+ length() const
+ { return this->length_; }
+
+ private:
+ // The offset within the output section.
+ off_t section_offset_;
+ // The length of the space to fill.
+ section_size_type length_;
+ };
+
+ typedef std::vector<Fill> Fill_list;
+
+ // Map used during relaxation of existing sections. This map
+ // a section id an input section list index. We assume that
+ // Input_section_list is a vector.
+ typedef Unordered_map<Section_id, size_t, Section_id_hash> Relaxation_map;
+
+ // Add a new output section by Input_section.
+ void
+ add_output_section_data(Input_section*);
+
+ // Add an SHF_MERGE input section. Returns true if the section was
+ // handled. If KEEPS_INPUT_SECTIONS is true, the output merge section
+ // stores information about the merged input sections.
+ bool
+ add_merge_input_section(Relobj* object, unsigned int shndx, uint64_t flags,
+ uint64_t entsize, uint64_t addralign,
+ bool keeps_input_sections);
+
+ // Add an output SHF_MERGE section POSD to this output section.
+ // IS_STRING indicates whether it is a SHF_STRINGS section, and
+ // ENTSIZE is the entity size. This returns the entry added to
+ // input_sections_.
+ void
+ add_output_merge_section(Output_section_data* posd, bool is_string,
+ uint64_t entsize);
+
+ // Find the merge section into which an input section with index SHNDX in
+ // OBJECT has been added. Return NULL if none found.
+ Output_section_data*
+ find_merge_section(const Relobj* object, unsigned int shndx) const;
+
+ // Build a relaxation map.
+ void
+ build_relaxation_map(
+ const Input_section_list& input_sections,
+ size_t limit,
+ Relaxation_map* map) const;
+
+ // Convert input sections in an input section list into relaxed sections.
+ void
+ convert_input_sections_in_list_to_relaxed_sections(
+ const std::vector<Output_relaxed_input_section*>& relaxed_sections,
+ const Relaxation_map& map,
+ Input_section_list* input_sections);
+
+ // Build the lookup maps for merge and relaxed input sections.
+ void
+ build_lookup_maps() const;
+
+ // Most of these fields are only valid after layout.
+
+ // The name of the section. This will point into a Stringpool.
+ const char* name_;
+ // The section address is in the parent class.
+ // The section alignment.
+ uint64_t addralign_;
+ // The section entry size.
+ uint64_t entsize_;
+ // The load address. This is only used when using a linker script
+ // with a SECTIONS clause. The has_load_address_ field indicates
+ // whether this field is valid.
+ uint64_t load_address_;
+ // The file offset is in the parent class.
+ // Set the section link field to the index of this section.
+ const Output_data* link_section_;
+ // If link_section_ is NULL, this is the link field.
+ unsigned int link_;
+ // Set the section info field to the index of this section.
+ const Output_section* info_section_;
+ // If info_section_ is NULL, set the info field to the symbol table
+ // index of this symbol.
+ const Symbol* info_symndx_;
+ // If info_section_ and info_symndx_ are NULL, this is the section
+ // info field.
+ unsigned int info_;
+ // The section type.
+ const elfcpp::Elf_Word type_;
+ // The section flags.
+ elfcpp::Elf_Xword flags_;
+ // The order of this section in the output segment.
+ Output_section_order order_;
+ // The section index.
+ unsigned int out_shndx_;
+ // If there is a STT_SECTION for this output section in the normal
+ // symbol table, this is the symbol index. This starts out as zero.
+ // It is initialized in Layout::finalize() to be the index, or -1U
+ // if there isn't one.
+ unsigned int symtab_index_;
+ // If there is a STT_SECTION for this output section in the dynamic
+ // symbol table, this is the symbol index. This starts out as zero.
+ // It is initialized in Layout::finalize() to be the index, or -1U
+ // if there isn't one.
+ unsigned int dynsym_index_;
+ // The input sections. This will be empty in cases where we don't
+ // need to keep track of them.
+ Input_section_list input_sections_;
+ // The offset of the first entry in input_sections_.
+ off_t first_input_offset_;
+ // The fill data. This is separate from input_sections_ because we
+ // often will need fill sections without needing to keep track of
+ // input sections.
+ Fill_list fills_;
+ // If the section requires postprocessing, this buffer holds the
+ // section contents during relocation.
+ unsigned char* postprocessing_buffer_;
+ // Whether this output section needs a STT_SECTION symbol in the
+ // normal symbol table. This will be true if there is a relocation
+ // which needs it.
+ bool needs_symtab_index_ : 1;
+ // Whether this output section needs a STT_SECTION symbol in the
+ // dynamic symbol table. This will be true if there is a dynamic
+ // relocation which needs it.
+ bool needs_dynsym_index_ : 1;
+ // Whether the link field of this output section should point to the
+ // normal symbol table.
+ bool should_link_to_symtab_ : 1;
+ // Whether the link field of this output section should point to the
+ // dynamic symbol table.
+ bool should_link_to_dynsym_ : 1;
+ // Whether this section should be written after all the input
+ // sections are complete.
+ bool after_input_sections_ : 1;
+ // Whether this section requires post processing after all
+ // relocations have been applied.
+ bool requires_postprocessing_ : 1;
+ // Whether an input section was mapped to this output section
+ // because of a SECTIONS clause in a linker script.
+ bool found_in_sections_clause_ : 1;
+ // Whether this section has an explicitly specified load address.
+ bool has_load_address_ : 1;
+ // True if the info_section_ field means the section index of the
+ // section, false if it means the symbol index of the corresponding
+ // section symbol.
+ bool info_uses_section_index_ : 1;
+ // True if input sections attached to this output section have to be
+ // sorted according to a specified order.
+ bool input_section_order_specified_ : 1;
+ // True if the input sections attached to this output section may
+ // need sorting.
+ bool may_sort_attached_input_sections_ : 1;
+ // True if the input sections attached to this output section must
+ // be sorted.
+ bool must_sort_attached_input_sections_ : 1;
+ // True if the input sections attached to this output section have
+ // already been sorted.
+ bool attached_input_sections_are_sorted_ : 1;
+ // True if this section holds relro data.
+ bool is_relro_ : 1;
+ // True if this is a small section.
+ bool is_small_section_ : 1;
+ // True if this is a large section.
+ bool is_large_section_ : 1;
+ // Whether code-fills are generated at write.
+ bool generate_code_fills_at_write_ : 1;
+ // Whether the entry size field should be zero.
+ bool is_entsize_zero_ : 1;
+ // Whether section offsets need adjustment due to relaxation.
+ bool section_offsets_need_adjustment_ : 1;
+ // Whether this is a NOLOAD section.
+ bool is_noload_ : 1;
+ // Whether this always keeps input section.
+ bool always_keeps_input_sections_ : 1;
+ // Whether this section has a fixed layout, for incremental update links.
+ bool has_fixed_layout_ : 1;
+ // True if we can add patch space to this section.
+ bool is_patch_space_allowed_ : 1;
+ // True if this output section goes into a unique segment.
+ bool is_unique_segment_ : 1;
+ // For SHT_TLS sections, the offset of this section relative to the base
+ // of the TLS segment.
+ uint64_t tls_offset_;
+ // Additional segment flags, specified via linker plugin, when mapping some
+ // input sections to unique segments.
+ uint64_t extra_segment_flags_;
+ // Segment alignment specified via linker plugin, when mapping some
+ // input sections to unique segments.
+ uint64_t segment_alignment_;
+ // Saved checkpoint.
+ Checkpoint_output_section* checkpoint_;
+ // Fast lookup maps for merged and relaxed input sections.
+ Output_section_lookup_maps* lookup_maps_;
+ // List of available regions within the section, for incremental
+ // update links.
+ Free_list free_list_;
+ // Method for filling chunks of free space.
+ Output_fill* free_space_fill_;
+ // Amount added as patch space for incremental linking.
+ off_t patch_space_;
+};
+
+// An output segment. PT_LOAD segments are built from collections of
+// output sections. Other segments typically point within PT_LOAD
+// segments, and are built directly as needed.
+//
+// NOTE: We want to use the copy constructor for this class. During
+// relaxation, we may try built the segments multiple times. We do
+// that by copying the original segment list before lay-out, doing
+// a trial lay-out and roll-back to the saved copied if we need to
+// to the lay-out again.
+
+class Output_segment
+{
+ public:
+ // Create an output segment, specifying the type and flags.
+ Output_segment(elfcpp::Elf_Word, elfcpp::Elf_Word);
+
+ // Return the virtual address.
+ uint64_t
+ vaddr() const
+ { return this->vaddr_; }
+
+ // Return the physical address.
+ uint64_t
+ paddr() const
+ { return this->paddr_; }
+
+ // Return the segment type.
+ elfcpp::Elf_Word
+ type() const
+ { return this->type_; }
+
+ // Return the segment flags.
+ elfcpp::Elf_Word
+ flags() const
+ { return this->flags_; }
+
+ // Return the memory size.
+ uint64_t
+ memsz() const
+ { return this->memsz_; }
+
+ // Return the file size.
+ off_t
+ filesz() const
+ { return this->filesz_; }
+
+ // Return the file offset.
+ off_t
+ offset() const
+ { return this->offset_; }
+
+ // Whether this is a segment created to hold large data sections.
+ bool
+ is_large_data_segment() const
+ { return this->is_large_data_segment_; }
+
+ // Record that this is a segment created to hold large data
+ // sections.
+ void
+ set_is_large_data_segment()
+ { this->is_large_data_segment_ = true; }
+
+ bool
+ is_unique_segment() const
+ { return this->is_unique_segment_; }
+
+ // Mark segment as unique, happens when linker plugins request that
+ // certain input sections be mapped to unique segments.
+ void
+ set_is_unique_segment()
+ { this->is_unique_segment_ = true; }
+
+ // Return the maximum alignment of the Output_data.
+ uint64_t
+ maximum_alignment();
+
+ // Add the Output_section OS to this PT_LOAD segment. SEG_FLAGS is
+ // the segment flags to use.
+ void
+ add_output_section_to_load(Layout* layout, Output_section* os,
+ elfcpp::Elf_Word seg_flags);
+
+ // Add the Output_section OS to this non-PT_LOAD segment. SEG_FLAGS
+ // is the segment flags to use.
+ void
+ add_output_section_to_nonload(Output_section* os,
+ elfcpp::Elf_Word seg_flags);
+
+ // Remove an Output_section from this segment. It is an error if it
+ // is not present.
+ void
+ remove_output_section(Output_section* os);
+
+ // Add an Output_data (which need not be an Output_section) to the
+ // start of this segment.
+ void
+ add_initial_output_data(Output_data*);
+
+ // Return true if this segment has any sections which hold actual
+ // data, rather than being a BSS section.
+ bool
+ has_any_data_sections() const;
+
+ // Whether this segment has a dynamic relocs.
+ bool
+ has_dynamic_reloc() const;
+
+ // Return the first section.
+ Output_section*
+ first_section() const;
+
+ // Return the address of the first section.
+ uint64_t
+ first_section_load_address() const
+ {
+ const Output_section* os = this->first_section();
+ return os->has_load_address() ? os->load_address() : os->address();
+ }
+
+ // Return whether the addresses have been set already.
+ bool
+ are_addresses_set() const
+ { return this->are_addresses_set_; }
+
+ // Set the addresses.
+ void
+ set_addresses(uint64_t vaddr, uint64_t paddr)
+ {
+ this->vaddr_ = vaddr;
+ this->paddr_ = paddr;
+ this->are_addresses_set_ = true;
+ }
+
+ // Update the flags for the flags of an output section added to this
+ // segment.
+ void
+ update_flags_for_output_section(elfcpp::Elf_Xword flags)
+ {
+ // The ELF ABI specifies that a PT_TLS segment should always have
+ // PF_R as the flags.
+ if (this->type() != elfcpp::PT_TLS)
+ this->flags_ |= flags;
+ }
+
+ // Set the segment flags. This is only used if we have a PHDRS
+ // clause which explicitly specifies the flags.
+ void
+ set_flags(elfcpp::Elf_Word flags)
+ { this->flags_ = flags; }
+
+ // Set the address of the segment to ADDR and the offset to *POFF
+ // and set the addresses and offsets of all contained output
+ // sections accordingly. Set the section indexes of all contained
+ // output sections starting with *PSHNDX. If RESET is true, first
+ // reset the addresses of the contained sections. Return the
+ // address of the immediately following segment. Update *POFF and
+ // *PSHNDX. This should only be called for a PT_LOAD segment.
+ uint64_t
+ set_section_addresses(const Target*, Layout*, bool reset, uint64_t addr,
+ unsigned int* increase_relro, bool* has_relro,
+ off_t* poff, unsigned int* pshndx);
+
+ // Set the minimum alignment of this segment. This may be adjusted
+ // upward based on the section alignments.
+ void
+ set_minimum_p_align(uint64_t align)
+ {
+ if (align > this->min_p_align_)
+ this->min_p_align_ = align;
+ }
+
+ // Set the offset of this segment based on the section. This should
+ // only be called for a non-PT_LOAD segment.
+ void
+ set_offset(unsigned int increase);
+
+ // Set the TLS offsets of the sections contained in the PT_TLS segment.
+ void
+ set_tls_offsets();
+
+ // Return the number of output sections.
+ unsigned int
+ output_section_count() const;
+
+ // Return the section attached to the list segment with the lowest
+ // load address. This is used when handling a PHDRS clause in a
+ // linker script.
+ Output_section*
+ section_with_lowest_load_address() const;
+
+ // Write the segment header into *OPHDR.
+ template<int size, bool big_endian>
+ void
+ write_header(elfcpp::Phdr_write<size, big_endian>*);
+
+ // Write the section headers of associated sections into V.
+ template<int size, bool big_endian>
+ unsigned char*
+ write_section_headers(const Layout*, const Stringpool*, unsigned char* v,
+ unsigned int* pshndx) const;
+
+ // Print the output sections in the map file.
+ void
+ print_sections_to_mapfile(Mapfile*) const;
+
+ private:
+ typedef std::vector<Output_data*> Output_data_list;
+
+ // Find the maximum alignment in an Output_data_list.
+ static uint64_t
+ maximum_alignment_list(const Output_data_list*);
+
+ // Return whether the first data section is a relro section.
+ bool
+ is_first_section_relro() const;
+
+ // Set the section addresses in an Output_data_list.
+ uint64_t
+ set_section_list_addresses(Layout*, bool reset, Output_data_list*,
+ uint64_t addr, off_t* poff, unsigned int* pshndx,
+ bool* in_tls);
+
+ // Return the number of Output_sections in an Output_data_list.
+ unsigned int
+ output_section_count_list(const Output_data_list*) const;
+
+ // Return whether an Output_data_list has a dynamic reloc.
+ bool
+ has_dynamic_reloc_list(const Output_data_list*) const;
+
+ // Find the section with the lowest load address in an
+ // Output_data_list.
+ void
+ lowest_load_address_in_list(const Output_data_list* pdl,
+ Output_section** found,
+ uint64_t* found_lma) const;
+
+ // Find the first and last entries by address.
+ void
+ find_first_and_last_list(const Output_data_list* pdl,
+ const Output_data** pfirst,
+ const Output_data** plast) const;
+
+ // Write the section headers in the list into V.
+ template<int size, bool big_endian>
+ unsigned char*
+ write_section_headers_list(const Layout*, const Stringpool*,
+ const Output_data_list*, unsigned char* v,
+ unsigned int* pshdx) const;
+
+ // Print a section list to the mapfile.
+ void
+ print_section_list_to_mapfile(Mapfile*, const Output_data_list*) const;
+
+ // NOTE: We want to use the copy constructor. Currently, shallow copy
+ // works for us so we do not need to write our own copy constructor.
+
+ // The list of output data attached to this segment.
+ Output_data_list output_lists_[ORDER_MAX];
+ // The segment virtual address.
+ uint64_t vaddr_;
+ // The segment physical address.
+ uint64_t paddr_;
+ // The size of the segment in memory.
+ uint64_t memsz_;
+ // The maximum section alignment. The is_max_align_known_ field
+ // indicates whether this has been finalized.
+ uint64_t max_align_;
+ // The required minimum value for the p_align field. This is used
+ // for PT_LOAD segments. Note that this does not mean that
+ // addresses should be aligned to this value; it means the p_paddr
+ // and p_vaddr fields must be congruent modulo this value. For
+ // non-PT_LOAD segments, the dynamic linker works more efficiently
+ // if the p_align field has the more conventional value, although it
+ // can align as needed.
+ uint64_t min_p_align_;
+ // The offset of the segment data within the file.
+ off_t offset_;
+ // The size of the segment data in the file.
+ off_t filesz_;
+ // The segment type;
+ elfcpp::Elf_Word type_;
+ // The segment flags.
+ elfcpp::Elf_Word flags_;
+ // Whether we have finalized max_align_.
+ bool is_max_align_known_ : 1;
+ // Whether vaddr and paddr were set by a linker script.
+ bool are_addresses_set_ : 1;
+ // Whether this segment holds large data sections.
+ bool is_large_data_segment_ : 1;
+ // Whether this was marked as a unique segment via a linker plugin.
+ bool is_unique_segment_ : 1;
+};
+
+// This class represents the output file.
+
+class Output_file
+{
+ public:
+ Output_file(const char* name);
+
+ // Indicate that this is a temporary file which should not be
+ // output.
+ void
+ set_is_temporary()
+ { this->is_temporary_ = true; }
+
+ // Try to open an existing file. Returns false if the file doesn't
+ // exist, has a size of 0 or can't be mmaped. This method is
+ // thread-unsafe. If BASE_NAME is not NULL, use the contents of
+ // that file as the base for incremental linking.
+ bool
+ open_base_file(const char* base_name, bool writable);
+
+ // Open the output file. FILE_SIZE is the final size of the file.
+ // If the file already exists, it is deleted/truncated. This method
+ // is thread-unsafe.
+ void
+ open(off_t file_size);
+
+ // Resize the output file. This method is thread-unsafe.
+ void
+ resize(off_t file_size);
+
+ // Close the output file (flushing all buffered data) and make sure
+ // there are no errors. This method is thread-unsafe.
+ void
+ close();
+
+ // Return the size of this file.
+ off_t
+ filesize()
+ { return this->file_size_; }
+
+ // Return the name of this file.
+ const char*
+ filename()
+ { return this->name_; }
+
+ // We currently always use mmap which makes the view handling quite
+ // simple. In the future we may support other approaches.
+
+ // Write data to the output file.
+ void
+ write(off_t offset, const void* data, size_t len)
+ { memcpy(this->base_ + offset, data, len); }
+
+ // Get a buffer to use to write to the file, given the offset into
+ // the file and the size.
+ unsigned char*
+ get_output_view(off_t start, size_t size)
+ {
+ gold_assert(start >= 0
+ && start + static_cast<off_t>(size) <= this->file_size_);
+ return this->base_ + start;
+ }
+
+ // VIEW must have been returned by get_output_view. Write the
+ // buffer to the file, passing in the offset and the size.
+ void
+ write_output_view(off_t, size_t, unsigned char*)
+ { }
+
+ // Get a read/write buffer. This is used when we want to write part
+ // of the file, read it in, and write it again.
+ unsigned char*
+ get_input_output_view(off_t start, size_t size)
+ { return this->get_output_view(start, size); }
+
+ // Write a read/write buffer back to the file.
+ void
+ write_input_output_view(off_t, size_t, unsigned char*)
+ { }
+
+ // Get a read buffer. This is used when we just want to read part
+ // of the file back it in.
+ const unsigned char*
+ get_input_view(off_t start, size_t size)
+ { return this->get_output_view(start, size); }
+
+ // Release a read bfufer.
+ void
+ free_input_view(off_t, size_t, const unsigned char*)
+ { }
+
+ private:
+ // Map the file into memory or, if that fails, allocate anonymous
+ // memory.
+ void
+ map();
+
+ // Allocate anonymous memory for the file.
+ bool
+ map_anonymous();
+
+ // Map the file into memory.
+ bool
+ map_no_anonymous(bool);
+
+ // Unmap the file from memory (and flush to disk buffers).
+ void
+ unmap();
+
+ // File name.
+ const char* name_;
+ // File descriptor.
+ int o_;
+ // File size.
+ off_t file_size_;
+ // Base of file mapped into memory.
+ unsigned char* base_;
+ // True iff base_ points to a memory buffer rather than an output file.
+ bool map_is_anonymous_;
+ // True if base_ was allocated using new rather than mmap.
+ bool map_is_allocated_;
+ // True if this is a temporary file which should not be output.
+ bool is_temporary_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_OUTPUT_H)
diff --git a/binutils-2.25/gold/parameters.cc b/binutils-2.25/gold/parameters.cc
new file mode 100644
index 00000000..7410e7f8
--- /dev/null
+++ b/binutils-2.25/gold/parameters.cc
@@ -0,0 +1,389 @@
+// parameters.cc -- general parameters for a link using gold
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
+// Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 "debug.h"
+#include "options.h"
+#include "target.h"
+#include "target-select.h"
+
+namespace gold
+{
+
+// Our local version of the variable, which is not const.
+
+static Parameters static_parameters;
+
+// The global variable.
+
+const Parameters* parameters = &static_parameters;
+
+// A helper class to set the target once.
+
+class Set_parameters_target_once : public Once
+{
+ public:
+ Set_parameters_target_once(Parameters* parameters)
+ : parameters_(parameters)
+ { }
+
+ protected:
+ void
+ do_run_once(void* arg)
+ { this->parameters_->set_target_once(static_cast<Target*>(arg)); }
+
+ private:
+ Parameters* parameters_;
+};
+
+// We only need one Set_parameters_target_once.
+
+static
+Set_parameters_target_once set_parameters_target_once(&static_parameters);
+
+// Class Parameters.
+
+Parameters::Parameters()
+ : errors_(NULL), timer_(NULL), options_(NULL), target_(NULL),
+ doing_static_link_valid_(false), doing_static_link_(false),
+ debug_(0), incremental_mode_(General_options::INCREMENTAL_OFF),
+ set_parameters_target_once_(&set_parameters_target_once)
+ {
+ }
+
+void
+Parameters::set_errors(Errors* errors)
+{
+ gold_assert(this->errors_ == NULL);
+ this->errors_ = errors;
+}
+
+void
+Parameters::set_timer(Timer* timer)
+{
+ gold_assert(this->timer_ == NULL);
+ this->timer_ = timer;
+}
+
+void
+Parameters::set_options(const General_options* options)
+{
+ gold_assert(!this->options_valid());
+ this->options_ = options;
+ // For speed, we convert the options() debug var from a string to an
+ // enum (from debug.h).
+ this->debug_ = debug_string_to_enum(this->options().debug());
+ // Set incremental_mode_ based on the value of the --incremental option.
+ // We copy the mode into parameters because it can change based on inputs.
+ this->incremental_mode_ = this->options().incremental_mode();
+ // If --verbose is set, it acts as "--debug=files".
+ if (options->verbose())
+ this->debug_ |= DEBUG_FILES;
+ if (this->target_valid())
+ this->check_target_endianness();
+}
+
+void
+Parameters::set_doing_static_link(bool doing_static_link)
+{
+ gold_assert(!this->doing_static_link_valid_);
+ this->doing_static_link_ = doing_static_link;
+ this->doing_static_link_valid_ = true;
+}
+
+void
+Parameters::set_target(Target* target)
+{
+ this->set_parameters_target_once_->run_once(static_cast<void*>(target));
+ gold_assert(target == this->target_);
+}
+
+// This is called at most once.
+
+void
+Parameters::set_target_once(Target* target)
+{
+ gold_assert(this->target_ == NULL);
+ this->target_ = target;
+ if (this->options_valid())
+ {
+ this->check_target_endianness();
+ this->check_rodata_segment();
+ }
+}
+
+// Clear the target, for testing.
+
+void
+Parameters::clear_target()
+{
+ this->target_ = NULL;
+ // We need a new Set_parameters_target_once so that we can set the
+ // target again.
+ this->set_parameters_target_once_ = new Set_parameters_target_once(this);
+}
+
+// Return whether TARGET is compatible with the target we are using.
+
+bool
+Parameters::is_compatible_target(const Target* target) const
+{
+ if (this->target_ == NULL)
+ return true;
+ return target == this->target_;
+}
+
+Parameters::Target_size_endianness
+Parameters::size_and_endianness() const
+{
+ if (this->target().get_size() == 32)
+ {
+ if (!this->target().is_big_endian())
+ {
+#ifdef HAVE_TARGET_32_LITTLE
+ return TARGET_32_LITTLE;
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ {
+#ifdef HAVE_TARGET_32_BIG
+ return TARGET_32_BIG;
+#else
+ gold_unreachable();
+#endif
+ }
+ }
+ else if (parameters->target().get_size() == 64)
+ {
+ if (!parameters->target().is_big_endian())
+ {
+#ifdef HAVE_TARGET_64_LITTLE
+ return TARGET_64_LITTLE;
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ {
+#ifdef HAVE_TARGET_64_BIG
+ return TARGET_64_BIG;
+#else
+ gold_unreachable();
+#endif
+ }
+ }
+ else
+ gold_unreachable();
+}
+
+// If output endianness is specified in command line, check that it does
+// not conflict with the target.
+
+void
+Parameters::check_target_endianness()
+{
+ General_options::Endianness endianness = this->options().endianness();
+ if (endianness != General_options::ENDIANNESS_NOT_SET)
+ {
+ bool big_endian;
+ if (endianness == General_options::ENDIANNESS_BIG)
+ big_endian = true;
+ else
+ {
+ gold_assert(endianness == General_options::ENDIANNESS_LITTLE);
+ big_endian = false;;
+ }
+
+ if (this->target().is_big_endian() != big_endian)
+ gold_error(_("input file does not match -EB/EL option"));
+ }
+}
+
+void
+Parameters::check_rodata_segment()
+{
+ if (this->options().user_set_Trodata_segment()
+ && !this->options().rosegment()
+ && !this->target().isolate_execinstr())
+ gold_error(_("-Trodata-segment is meaningless without --rosegment"));
+}
+
+// Return the name of the entry symbol.
+
+const char*
+Parameters::entry() const
+{
+ const char* ret = this->options().entry();
+ if (ret == NULL)
+ ret = parameters->target().entry_symbol_name();
+ return ret;
+}
+
+// Set the incremental linking mode to INCREMENTAL_FULL. Used when
+// the linker determines that an incremental update is not possible.
+// Returns false if the incremental mode was INCREMENTAL_UPDATE,
+// indicating that the linker should exit if an update is not possible.
+
+bool
+Parameters::set_incremental_full()
+{
+ gold_assert(this->incremental_mode_ != General_options::INCREMENTAL_OFF);
+ if (this->incremental_mode_ == General_options::INCREMENTAL_UPDATE)
+ return false;
+ this->incremental_mode_ = General_options::INCREMENTAL_FULL;
+ return true;
+}
+
+// Return true if we need to prepare incremental linking information.
+
+bool
+Parameters::incremental() const
+{
+ return this->incremental_mode_ != General_options::INCREMENTAL_OFF;
+}
+
+// Return true if we are doing a full incremental link.
+
+bool
+Parameters::incremental_full() const
+{
+ return this->incremental_mode_ == General_options::INCREMENTAL_FULL;
+}
+
+// Return true if we are doing an incremental update.
+
+bool
+Parameters::incremental_update() const
+{
+ return (this->incremental_mode_ == General_options::INCREMENTAL_UPDATE
+ || this->incremental_mode_ == General_options::INCREMENTAL_AUTO);
+}
+
+void
+set_parameters_errors(Errors* errors)
+{ static_parameters.set_errors(errors); }
+
+void
+set_parameters_timer(Timer* timer)
+{ static_parameters.set_timer(timer); }
+
+void
+set_parameters_options(const General_options* options)
+{ static_parameters.set_options(options); }
+
+void
+set_parameters_target(Target* target)
+{
+ static_parameters.set_target(target);
+ target->select_as_default_target();
+}
+
+void
+set_parameters_doing_static_link(bool doing_static_link)
+{ static_parameters.set_doing_static_link(doing_static_link); }
+
+// Set the incremental linking mode to INCREMENTAL_FULL. Used when
+// the linker determines that an incremental update is not possible.
+// Returns false if the incremental mode was INCREMENTAL_UPDATE,
+// indicating that the linker should exit if an update is not possible.
+bool
+set_parameters_incremental_full()
+{ return static_parameters.set_incremental_full(); }
+
+// Force the target to be valid by using the default. Use the
+// --oformat option is set; this supports the x86_64 kernel build,
+// which converts a binary file to an object file using -r --format
+// binary --oformat elf32-i386 foo.o. Otherwise use the configured
+// default.
+
+void
+parameters_force_valid_target()
+{
+ if (parameters->target_valid())
+ return;
+
+ gold_assert(parameters->options_valid());
+ if (parameters->options().user_set_oformat())
+ {
+ const char* bfd_name = parameters->options().oformat();
+ Target* target = select_target_by_bfd_name(bfd_name);
+ if (target != NULL)
+ {
+ set_parameters_target(target);
+ return;
+ }
+
+ gold_error(_("unrecognized output format %s"), bfd_name);
+ }
+
+ if (parameters->options().user_set_m())
+ {
+ const char* emulation = parameters->options().m();
+ Target* target = select_target_by_emulation(emulation);
+ if (target != NULL)
+ {
+ set_parameters_target(target);
+ return;
+ }
+
+ gold_error(_("unrecognized emulation %s"), emulation);
+ }
+
+ // The GOLD_DEFAULT_xx macros are defined by the configure script.
+ bool is_big_endian;
+ General_options::Endianness endianness = parameters->options().endianness();
+ if (endianness == General_options::ENDIANNESS_BIG)
+ is_big_endian = true;
+ else if (endianness == General_options::ENDIANNESS_LITTLE)
+ is_big_endian = false;
+ else
+ is_big_endian = GOLD_DEFAULT_BIG_ENDIAN;
+
+ Target* target = select_target(NULL, 0,
+ elfcpp::GOLD_DEFAULT_MACHINE,
+ GOLD_DEFAULT_SIZE,
+ is_big_endian,
+ elfcpp::GOLD_DEFAULT_OSABI,
+ 0);
+
+ if (target == NULL)
+ {
+ gold_assert(is_big_endian != GOLD_DEFAULT_BIG_ENDIAN);
+ gold_fatal(_("no supported target for -EB/-EL option"));
+ }
+
+ set_parameters_target(target);
+}
+
+// Clear the current target, for testing.
+
+void
+parameters_clear_target()
+{
+ static_parameters.clear_target();
+}
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/parameters.h b/binutils-2.25/gold/parameters.h
new file mode 100644
index 00000000..8d1ec2e1
--- /dev/null
+++ b/binutils-2.25/gold/parameters.h
@@ -0,0 +1,246 @@
+// parameters.h -- general parameters for a link using gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2013 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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_PARAMETERS_H
+#define GOLD_PARAMETERS_H
+
+namespace gold
+{
+
+class General_options;
+class Errors;
+class Timer;
+class Target;
+template<int size, bool big_endian>
+class Sized_target;
+class Set_parameters_target_once;
+
+// Here we define the Parameters class which simply holds simple
+// general parameters which apply to the entire link. We use a global
+// variable for this. The parameters class holds three types of data:
+// 1) An Errors struct. Any part of the code that wants to log an
+// error can use parameters->errors().
+// 2) A const General_options. These are the options as read on
+// the commandline.
+// 3) Target information, such as size and endian-ness. This is
+// available as soon as we've decided on the Target (after
+// parsing the first .o file).
+// 4) Whether we're doing a static link or not. This is set
+// after all inputs have been read and we know if any is a
+// dynamic library.
+
+class Parameters
+{
+ public:
+ Parameters();
+
+ // These should be called as soon as they are known.
+ void
+ set_errors(Errors* errors);
+
+ void
+ set_timer(Timer* timer);
+
+ void
+ set_options(const General_options* options);
+
+ void
+ set_target(Target* target);
+
+ void
+ set_doing_static_link(bool doing_static_link);
+
+ // Return the error object.
+ Errors*
+ errors() const
+ { return this->errors_; }
+
+ // Return the timer object.
+ Timer*
+ timer() const
+ { return this->timer_; }
+
+ // Whether the options are valid. This should not normally be
+ // called, but it is needed by gold_exit.
+ bool
+ options_valid() const
+ { return this->options_ != NULL; }
+
+ // Return the options object.
+ const General_options&
+ options() const
+ {
+ gold_assert(this->options_valid());
+ return *this->options_;
+ }
+
+ // Return whether the target field has been set.
+ bool
+ target_valid() const
+ { return this->target_ != NULL; }
+
+ // The target of the output file we are generating.
+ const Target&
+ target() const
+ {
+ gold_assert(this->target_valid());
+ return *this->target_;
+ }
+
+ // The Sized_target of the output file. The caller must request the
+ // right size and endianness.
+ template<int size, bool big_endian>
+ Sized_target<size, big_endian>*
+ sized_target() const
+ {
+ gold_assert(this->target_valid());
+ return static_cast<Sized_target<size, big_endian>*>(this->target_);
+ }
+
+ // Clear the target, for testing.
+ void
+ clear_target();
+
+ // Return true if TARGET is compatible with the current target.
+ bool
+ is_compatible_target(const Target*) const;
+
+ bool
+ doing_static_link() const
+ {
+ gold_assert(this->doing_static_link_valid_);
+ return this->doing_static_link_;
+ }
+
+ // This is just a copy of options().debug(). We make a copy so we
+ // don't have to #include options.h in order to inline
+ // is_debugging_enabled, below.
+ int
+ debug() const
+ {
+ // This can be called before the options are set up.
+ if (!this->options_valid())
+ return 0;
+ return debug_;
+ }
+
+ // Return the name of the entry symbol.
+ const char*
+ entry() const;
+
+ // A convenience routine for combining size and endianness. It also
+ // checks the HAVE_TARGET_FOO configure options and dies if the
+ // current target's size/endianness is not supported according to
+ // HAVE_TARGET_FOO. Otherwise it returns this enum
+ enum Target_size_endianness
+ { TARGET_32_LITTLE, TARGET_32_BIG, TARGET_64_LITTLE, TARGET_64_BIG };
+
+ Target_size_endianness
+ size_and_endianness() const;
+
+ // Set the incremental linking mode to INCREMENTAL_FULL. Used when
+ // the linker determines that an incremental update is not possible.
+ // Returns false if the incremental mode was INCREMENTAL_UPDATE,
+ // indicating that the linker should exit if an update is not possible.
+ bool
+ set_incremental_full();
+
+ // Return true if we need to prepare incremental linking information.
+ bool
+ incremental() const;
+
+ // Return true if we are doing a full incremental link.
+ bool
+ incremental_full() const;
+
+ // Return true if we are doing an incremental update.
+ bool
+ incremental_update() const;
+
+ private:
+ void
+ set_target_once(Target*);
+
+ void
+ check_target_endianness();
+
+ void
+ check_rodata_segment();
+
+ friend class Set_parameters_target_once;
+
+ Errors* errors_;
+ Timer* timer_;
+ const General_options* options_;
+ Target* target_;
+ bool doing_static_link_valid_;
+ bool doing_static_link_;
+ int debug_;
+ int incremental_mode_;
+ Set_parameters_target_once* set_parameters_target_once_;
+};
+
+// This is a global variable.
+extern const Parameters* parameters;
+
+// We use free functions for these since they affect a global variable
+// that is internal to parameters.cc.
+
+extern void
+set_parameters_errors(Errors* errors);
+
+extern void
+set_parameters_timer(Timer* timer);
+
+extern void
+set_parameters_options(const General_options* options);
+
+extern void
+set_parameters_target(Target* target);
+
+extern void
+set_parameters_doing_static_link(bool doing_static_link);
+
+extern bool
+set_parameters_incremental_full();
+
+// Ensure that the target to be valid by using the default target if
+// necessary.
+
+extern void
+parameters_force_valid_target();
+
+// Clear the current target, for testing.
+
+extern void
+parameters_clear_target();
+
+// Return whether we are doing a particular debugging type. The
+// argument is one of the flags from debug.h.
+
+inline bool
+is_debugging_enabled(unsigned int type)
+{ return (parameters->debug() & type) != 0; }
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_PARAMETERS_H)
diff --git a/binutils-2.25/gold/plugin.cc b/binutils-2.25/gold/plugin.cc
new file mode 100644
index 00000000..e932c1c9
--- /dev/null
+++ b/binutils-2.25/gold/plugin.cc
@@ -0,0 +1,1862 @@
+// plugin.cc -- plugin manager for gold -*- C++ -*-
+
+// Copyright 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include "gold.h"
+
+#include <cstdio>
+#include <cstdarg>
+#include <cstring>
+#include <string>
+#include <vector>
+
+#ifdef ENABLE_PLUGINS
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#elif defined (HAVE_WINDOWS_H)
+#include <windows.h>
+#else
+#error Unknown how to handle dynamic-load-libraries.
+#endif
+
+#if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)
+
+#define RTLD_NOW 0 /* Dummy value. */
+static void *
+dlopen(const char *file, int mode ATTRIBUTE_UNUSED)
+{
+ return LoadLibrary(file);
+}
+
+static void *
+dlsym(void *handle, const char *name)
+{
+ return reinterpret_cast<void *>(
+ GetProcAddress(static_cast<HMODULE>(handle),name));
+}
+
+static const char *
+dlerror(void)
+{
+ return "unable to load dll";
+}
+
+#endif /* !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) */
+#endif /* ENABLE_PLUGINS */
+
+#include "parameters.h"
+#include "errors.h"
+#include "fileread.h"
+#include "layout.h"
+#include "options.h"
+#include "plugin.h"
+#include "target.h"
+#include "readsyms.h"
+#include "symtab.h"
+#include "descriptors.h"
+#include "elfcpp.h"
+
+namespace gold
+{
+
+#ifdef ENABLE_PLUGINS
+
+// The linker's exported interfaces.
+
+extern "C"
+{
+
+static enum ld_plugin_status
+register_claim_file(ld_plugin_claim_file_handler handler);
+
+static enum ld_plugin_status
+register_all_symbols_read(ld_plugin_all_symbols_read_handler handler);
+
+static enum ld_plugin_status
+register_cleanup(ld_plugin_cleanup_handler handler);
+
+static enum ld_plugin_status
+add_symbols(void *handle, int nsyms, const struct ld_plugin_symbol *syms);
+
+static enum ld_plugin_status
+get_input_file(const void *handle, struct ld_plugin_input_file *file);
+
+static enum ld_plugin_status
+get_view(const void *handle, const void **viewp);
+
+static enum ld_plugin_status
+release_input_file(const void *handle);
+
+static enum ld_plugin_status
+get_symbols(const void *handle, int nsyms, struct ld_plugin_symbol *syms);
+
+static enum ld_plugin_status
+get_symbols_v2(const void *handle, int nsyms, struct ld_plugin_symbol *syms);
+
+static enum ld_plugin_status
+add_input_file(const char *pathname);
+
+static enum ld_plugin_status
+add_input_library(const char *pathname);
+
+static enum ld_plugin_status
+set_extra_library_path(const char *path);
+
+static enum ld_plugin_status
+message(int level, const char *format, ...);
+
+static enum ld_plugin_status
+get_input_section_count(const void* handle, unsigned int* count);
+
+static enum ld_plugin_status
+get_input_section_type(const struct ld_plugin_section section,
+ unsigned int* type);
+
+static enum ld_plugin_status
+get_input_section_name(const struct ld_plugin_section section,
+ char** section_name_ptr);
+
+static enum ld_plugin_status
+get_input_section_contents(const struct ld_plugin_section section,
+ const unsigned char** section_contents,
+ size_t* len);
+
+static enum ld_plugin_status
+update_section_order(const struct ld_plugin_section *section_list,
+ unsigned int num_sections);
+
+static enum ld_plugin_status
+allow_section_ordering();
+
+static enum ld_plugin_status
+allow_unique_segment_for_sections();
+
+static enum ld_plugin_status
+unique_segment_for_sections(const char* segment_name,
+ uint64_t flags,
+ uint64_t align,
+ const struct ld_plugin_section *section_list,
+ unsigned int num_sections);
+};
+
+#endif // ENABLE_PLUGINS
+
+static Pluginobj* make_sized_plugin_object(Input_file* input_file,
+ off_t offset, off_t filesize);
+
+// Plugin methods.
+
+// Load one plugin library.
+
+void
+Plugin::load()
+{
+#ifdef ENABLE_PLUGINS
+ // Load the plugin library.
+ // FIXME: Look for the library in standard locations.
+ this->handle_ = dlopen(this->filename_.c_str(), RTLD_NOW);
+ if (this->handle_ == NULL)
+ {
+ gold_error(_("%s: could not load plugin library: %s"),
+ this->filename_.c_str(), dlerror());
+ return;
+ }
+
+ // Find the plugin's onload entry point.
+ void* ptr = dlsym(this->handle_, "onload");
+ if (ptr == NULL)
+ {
+ gold_error(_("%s: could not find onload entry point"),
+ this->filename_.c_str());
+ return;
+ }
+ ld_plugin_onload onload;
+ gold_assert(sizeof(onload) == sizeof(ptr));
+ memcpy(&onload, &ptr, sizeof(ptr));
+
+ // Get the linker's version number.
+ const char* ver = get_version_string();
+ int major = 0;
+ int minor = 0;
+ sscanf(ver, "%d.%d", &major, &minor);
+
+ // Allocate and populate a transfer vector.
+ const int tv_fixed_size = 26;
+
+ int tv_size = this->args_.size() + tv_fixed_size;
+ ld_plugin_tv* tv = new ld_plugin_tv[tv_size];
+
+ // Put LDPT_MESSAGE at the front of the list so the plugin can use it
+ // while processing subsequent entries.
+ int i = 0;
+ tv[i].tv_tag = LDPT_MESSAGE;
+ tv[i].tv_u.tv_message = message;
+
+ ++i;
+ tv[i].tv_tag = LDPT_API_VERSION;
+ tv[i].tv_u.tv_val = LD_PLUGIN_API_VERSION;
+
+ ++i;
+ tv[i].tv_tag = LDPT_GOLD_VERSION;
+ tv[i].tv_u.tv_val = major * 100 + minor;
+
+ ++i;
+ tv[i].tv_tag = LDPT_LINKER_OUTPUT;
+ if (parameters->options().relocatable())
+ tv[i].tv_u.tv_val = LDPO_REL;
+ else if (parameters->options().shared())
+ tv[i].tv_u.tv_val = LDPO_DYN;
+ else if (parameters->options().pie())
+ tv[i].tv_u.tv_val = LDPO_PIE;
+ else
+ tv[i].tv_u.tv_val = LDPO_EXEC;
+
+ ++i;
+ tv[i].tv_tag = LDPT_OUTPUT_NAME;
+ tv[i].tv_u.tv_string = parameters->options().output();
+
+ for (unsigned int j = 0; j < this->args_.size(); ++j)
+ {
+ ++i;
+ tv[i].tv_tag = LDPT_OPTION;
+ tv[i].tv_u.tv_string = this->args_[j].c_str();
+ }
+
+ ++i;
+ tv[i].tv_tag = LDPT_REGISTER_CLAIM_FILE_HOOK;
+ tv[i].tv_u.tv_register_claim_file = register_claim_file;
+
+ ++i;
+ tv[i].tv_tag = LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK;
+ tv[i].tv_u.tv_register_all_symbols_read = register_all_symbols_read;
+
+ ++i;
+ tv[i].tv_tag = LDPT_REGISTER_CLEANUP_HOOK;
+ tv[i].tv_u.tv_register_cleanup = register_cleanup;
+
+ ++i;
+ tv[i].tv_tag = LDPT_ADD_SYMBOLS;
+ tv[i].tv_u.tv_add_symbols = add_symbols;
+
+ ++i;
+ tv[i].tv_tag = LDPT_GET_INPUT_FILE;
+ tv[i].tv_u.tv_get_input_file = get_input_file;
+
+ ++i;
+ tv[i].tv_tag = LDPT_GET_VIEW;
+ tv[i].tv_u.tv_get_view = get_view;
+
+ ++i;
+ tv[i].tv_tag = LDPT_RELEASE_INPUT_FILE;
+ tv[i].tv_u.tv_release_input_file = release_input_file;
+
+ ++i;
+ tv[i].tv_tag = LDPT_GET_SYMBOLS;
+ tv[i].tv_u.tv_get_symbols = get_symbols;
+
+ ++i;
+ tv[i].tv_tag = LDPT_GET_SYMBOLS_V2;
+ tv[i].tv_u.tv_get_symbols = get_symbols_v2;
+
+ ++i;
+ tv[i].tv_tag = LDPT_ADD_INPUT_FILE;
+ tv[i].tv_u.tv_add_input_file = add_input_file;
+
+ ++i;
+ tv[i].tv_tag = LDPT_ADD_INPUT_LIBRARY;
+ tv[i].tv_u.tv_add_input_library = add_input_library;
+
+ ++i;
+ tv[i].tv_tag = LDPT_SET_EXTRA_LIBRARY_PATH;
+ tv[i].tv_u.tv_set_extra_library_path = set_extra_library_path;
+
+ ++i;
+ tv[i].tv_tag = LDPT_GET_INPUT_SECTION_COUNT;
+ tv[i].tv_u.tv_get_input_section_count = get_input_section_count;
+
+ ++i;
+ tv[i].tv_tag = LDPT_GET_INPUT_SECTION_TYPE;
+ tv[i].tv_u.tv_get_input_section_type = get_input_section_type;
+
+ ++i;
+ tv[i].tv_tag = LDPT_GET_INPUT_SECTION_NAME;
+ tv[i].tv_u.tv_get_input_section_name = get_input_section_name;
+
+ ++i;
+ tv[i].tv_tag = LDPT_GET_INPUT_SECTION_CONTENTS;
+ tv[i].tv_u.tv_get_input_section_contents = get_input_section_contents;
+
+ ++i;
+ tv[i].tv_tag = LDPT_UPDATE_SECTION_ORDER;
+ tv[i].tv_u.tv_update_section_order = update_section_order;
+
+ ++i;
+ tv[i].tv_tag = LDPT_ALLOW_SECTION_ORDERING;
+ tv[i].tv_u.tv_allow_section_ordering = allow_section_ordering;
+
+ ++i;
+ tv[i].tv_tag = LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS;
+ tv[i].tv_u.tv_allow_unique_segment_for_sections
+ = allow_unique_segment_for_sections;
+
+ ++i;
+ tv[i].tv_tag = LDPT_UNIQUE_SEGMENT_FOR_SECTIONS;
+ tv[i].tv_u.tv_unique_segment_for_sections = unique_segment_for_sections;
+
+ ++i;
+ tv[i].tv_tag = LDPT_NULL;
+ tv[i].tv_u.tv_val = 0;
+
+ gold_assert(i == tv_size - 1);
+
+ // Call the onload entry point.
+ (*onload)(tv);
+
+ delete[] tv;
+#endif // ENABLE_PLUGINS
+}
+
+// Call the plugin claim-file handler.
+
+inline bool
+Plugin::claim_file(struct ld_plugin_input_file* plugin_input_file)
+{
+ int claimed = 0;
+
+ if (this->claim_file_handler_ != NULL)
+ {
+ (*this->claim_file_handler_)(plugin_input_file, &claimed);
+ if (claimed)
+ return true;
+ }
+ return false;
+}
+
+// Call the all-symbols-read handler.
+
+inline void
+Plugin::all_symbols_read()
+{
+ if (this->all_symbols_read_handler_ != NULL)
+ (*this->all_symbols_read_handler_)();
+}
+
+// Call the cleanup handler.
+
+inline void
+Plugin::cleanup()
+{
+ if (this->cleanup_handler_ != NULL && !this->cleanup_done_)
+ {
+ // Set this flag before calling to prevent a recursive plunge
+ // in the event that a plugin's cleanup handler issues a
+ // fatal error.
+ this->cleanup_done_ = true;
+ (*this->cleanup_handler_)();
+ }
+}
+
+// This task is used to rescan archives as needed.
+
+class Plugin_rescan : public Task
+{
+ public:
+ Plugin_rescan(Task_token* this_blocker, Task_token* next_blocker)
+ : this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Plugin_rescan()
+ {
+ delete this->this_blocker_;
+ }
+
+ Task_token*
+ is_runnable()
+ {
+ if (this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ return NULL;
+ }
+
+ void
+ locks(Task_locker* tl)
+ { tl->add(this, this->next_blocker_); }
+
+ void
+ run(Workqueue*)
+ { parameters->options().plugins()->rescan(this); }
+
+ std::string
+ get_name() const
+ { return "Plugin_rescan"; }
+
+ private:
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// Plugin_manager methods.
+
+Plugin_manager::~Plugin_manager()
+{
+ for (Plugin_list::iterator p = this->plugins_.begin();
+ p != this->plugins_.end();
+ ++p)
+ delete *p;
+ this->plugins_.clear();
+ for (Object_list::iterator obj = this->objects_.begin();
+ obj != this->objects_.end();
+ ++obj)
+ delete *obj;
+ this->objects_.clear();
+}
+
+// Load all plugin libraries.
+
+void
+Plugin_manager::load_plugins(Layout* layout)
+{
+ this->layout_ = layout;
+ for (this->current_ = this->plugins_.begin();
+ this->current_ != this->plugins_.end();
+ ++this->current_)
+ (*this->current_)->load();
+}
+
+// Call the plugin claim-file handlers in turn to see if any claim the file.
+
+Pluginobj*
+Plugin_manager::claim_file(Input_file* input_file, off_t offset,
+ off_t filesize, Object* elf_object)
+{
+ if (this->in_replacement_phase_)
+ return NULL;
+
+ unsigned int handle = this->objects_.size();
+ this->input_file_ = input_file;
+ this->plugin_input_file_.name = input_file->filename().c_str();
+ this->plugin_input_file_.fd = input_file->file().descriptor();
+ this->plugin_input_file_.offset = offset;
+ this->plugin_input_file_.filesize = filesize;
+ this->plugin_input_file_.handle = reinterpret_cast<void*>(handle);
+ if (elf_object != NULL)
+ this->objects_.push_back(elf_object);
+ this->in_claim_file_handler_ = true;
+
+ for (this->current_ = this->plugins_.begin();
+ this->current_ != this->plugins_.end();
+ ++this->current_)
+ {
+ if ((*this->current_)->claim_file(&this->plugin_input_file_))
+ {
+ this->any_claimed_ = true;
+ this->in_claim_file_handler_ = false;
+
+ if (this->objects_.size() > handle
+ && this->objects_[handle]->pluginobj() != NULL)
+ return this->objects_[handle]->pluginobj();
+
+ // If the plugin claimed the file but did not call the
+ // add_symbols callback, we need to create the Pluginobj now.
+ Pluginobj* obj = this->make_plugin_object(handle);
+ return obj;
+ }
+ }
+
+ this->in_claim_file_handler_ = false;
+ return NULL;
+}
+
+// Save an archive. This is used so that a plugin can add a file
+// which refers to a symbol which was not previously referenced. In
+// that case we want to pretend that the symbol was referenced before,
+// and pull in the archive object.
+
+void
+Plugin_manager::save_archive(Archive* archive)
+{
+ if (this->in_replacement_phase_ || !this->any_claimed_)
+ delete archive;
+ else
+ this->rescannable_.push_back(Rescannable(archive));
+}
+
+// Save an Input_group. This is like save_archive.
+
+void
+Plugin_manager::save_input_group(Input_group* input_group)
+{
+ if (this->in_replacement_phase_ || !this->any_claimed_)
+ delete input_group;
+ else
+ this->rescannable_.push_back(Rescannable(input_group));
+}
+
+// Call the all-symbols-read handlers.
+
+void
+Plugin_manager::all_symbols_read(Workqueue* workqueue, Task* task,
+ Input_objects* input_objects,
+ Symbol_table* symtab,
+ Dirsearch* dirpath, Mapfile* mapfile,
+ Task_token** last_blocker)
+{
+ this->in_replacement_phase_ = true;
+ this->workqueue_ = workqueue;
+ this->task_ = task;
+ this->input_objects_ = input_objects;
+ this->symtab_ = symtab;
+ this->dirpath_ = dirpath;
+ this->mapfile_ = mapfile;
+ this->this_blocker_ = NULL;
+
+ for (this->current_ = this->plugins_.begin();
+ this->current_ != this->plugins_.end();
+ ++this->current_)
+ (*this->current_)->all_symbols_read();
+
+ if (this->any_added_)
+ {
+ Task_token* next_blocker = new Task_token(true);
+ next_blocker->add_blocker();
+ workqueue->queue(new Plugin_rescan(this->this_blocker_, next_blocker));
+ this->this_blocker_ = next_blocker;
+ }
+
+ *last_blocker = this->this_blocker_;
+}
+
+// This is called when we see a new undefined symbol. If we are in
+// the replacement phase, this means that we may need to rescan some
+// archives we have previously seen.
+
+void
+Plugin_manager::new_undefined_symbol(Symbol* sym)
+{
+ if (this->in_replacement_phase_)
+ this->undefined_symbols_.push_back(sym);
+}
+
+// Rescan archives as needed. This handles the case where a new
+// object file added by a plugin has an undefined reference to some
+// symbol defined in an archive.
+
+void
+Plugin_manager::rescan(Task* task)
+{
+ size_t rescan_pos = 0;
+ size_t rescan_size = this->rescannable_.size();
+ while (!this->undefined_symbols_.empty())
+ {
+ if (rescan_pos >= rescan_size)
+ {
+ this->undefined_symbols_.clear();
+ return;
+ }
+
+ Undefined_symbol_list undefs;
+ undefs.reserve(this->undefined_symbols_.size());
+ this->undefined_symbols_.swap(undefs);
+
+ size_t min_rescan_pos = rescan_size;
+
+ for (Undefined_symbol_list::const_iterator p = undefs.begin();
+ p != undefs.end();
+ ++p)
+ {
+ if (!(*p)->is_undefined())
+ continue;
+
+ this->undefined_symbols_.push_back(*p);
+
+ // Find the first rescan archive which defines this symbol,
+ // starting at the current rescan position. The rescan position
+ // exists so that given -la -lb -lc we don't look for undefined
+ // symbols in -lb back in -la, but instead get the definition
+ // from -lc. Don't bother to look past the current minimum
+ // rescan position.
+ for (size_t i = rescan_pos; i < min_rescan_pos; ++i)
+ {
+ if (this->rescannable_defines(i, *p))
+ {
+ min_rescan_pos = i;
+ break;
+ }
+ }
+ }
+
+ if (min_rescan_pos >= rescan_size)
+ {
+ // We didn't find any rescannable archives which define any
+ // undefined symbols.
+ return;
+ }
+
+ const Rescannable& r(this->rescannable_[min_rescan_pos]);
+ if (r.is_archive)
+ {
+ Task_lock_obj<Archive> tl(task, r.u.archive);
+ r.u.archive->add_symbols(this->symtab_, this->layout_,
+ this->input_objects_, this->mapfile_);
+ }
+ else
+ {
+ size_t next_saw_undefined = this->symtab_->saw_undefined();
+ size_t saw_undefined;
+ do
+ {
+ saw_undefined = next_saw_undefined;
+
+ for (Input_group::const_iterator p = r.u.input_group->begin();
+ p != r.u.input_group->end();
+ ++p)
+ {
+ Task_lock_obj<Archive> tl(task, *p);
+
+ (*p)->add_symbols(this->symtab_, this->layout_,
+ this->input_objects_, this->mapfile_);
+ }
+
+ next_saw_undefined = this->symtab_->saw_undefined();
+ }
+ while (saw_undefined != next_saw_undefined);
+ }
+
+ for (size_t i = rescan_pos; i < min_rescan_pos + 1; ++i)
+ {
+ if (this->rescannable_[i].is_archive)
+ delete this->rescannable_[i].u.archive;
+ else
+ delete this->rescannable_[i].u.input_group;
+ }
+
+ rescan_pos = min_rescan_pos + 1;
+ }
+}
+
+// Return whether the rescannable at index I defines SYM.
+
+bool
+Plugin_manager::rescannable_defines(size_t i, Symbol* sym)
+{
+ const Rescannable& r(this->rescannable_[i]);
+ if (r.is_archive)
+ return r.u.archive->defines_symbol(sym);
+ else
+ {
+ for (Input_group::const_iterator p = r.u.input_group->begin();
+ p != r.u.input_group->end();
+ ++p)
+ {
+ if ((*p)->defines_symbol(sym))
+ return true;
+ }
+ return false;
+ }
+}
+
+// Layout deferred objects.
+
+void
+Plugin_manager::layout_deferred_objects()
+{
+ Deferred_layout_list::iterator obj;
+
+ for (obj = this->deferred_layout_objects_.begin();
+ obj != this->deferred_layout_objects_.end();
+ ++obj)
+ {
+ // 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<const Task*>(-1);
+ Task_lock_obj<Object> tl(dummy_task, *obj);
+ (*obj)->layout_deferred_sections(this->layout_);
+ }
+}
+
+// Call the cleanup handlers.
+
+void
+Plugin_manager::cleanup()
+{
+ if (this->any_added_)
+ {
+ // If any input files were added, close all the input files.
+ // This is because the plugin may want to remove them, and on
+ // Windows you are not allowed to remove an open file.
+ close_all_descriptors();
+ }
+
+ for (this->current_ = this->plugins_.begin();
+ this->current_ != this->plugins_.end();
+ ++this->current_)
+ (*this->current_)->cleanup();
+}
+
+// Make a new Pluginobj object. This is called when the plugin calls
+// the add_symbols API.
+
+Pluginobj*
+Plugin_manager::make_plugin_object(unsigned int handle)
+{
+ // Make sure we aren't asked to make an object for the same handle twice.
+ if (this->objects_.size() != handle
+ && this->objects_[handle]->pluginobj() != NULL)
+ return NULL;
+
+ Pluginobj* obj = make_sized_plugin_object(this->input_file_,
+ this->plugin_input_file_.offset,
+ this->plugin_input_file_.filesize);
+
+
+ // If the elf object for this file was pushed into the objects_ vector, delete
+ // it to make room for the Pluginobj as this file is claimed.
+ if (this->objects_.size() != handle)
+ this->objects_.pop_back();
+
+ this->objects_.push_back(obj);
+ return obj;
+}
+
+// Get the input file information with an open (possibly re-opened)
+// file descriptor.
+
+ld_plugin_status
+Plugin_manager::get_input_file(unsigned int handle,
+ struct ld_plugin_input_file* file)
+{
+ Pluginobj* obj = this->object(handle)->pluginobj();
+ if (obj == NULL)
+ return LDPS_BAD_HANDLE;
+
+ obj->lock(this->task_);
+ file->name = obj->filename().c_str();
+ file->fd = obj->descriptor();
+ file->offset = obj->offset();
+ file->filesize = obj->filesize();
+ file->handle = reinterpret_cast<void*>(handle);
+ return LDPS_OK;
+}
+
+// Release the input file.
+
+ld_plugin_status
+Plugin_manager::release_input_file(unsigned int handle)
+{
+ if (this->object(handle) == NULL)
+ return LDPS_BAD_HANDLE;
+
+ Pluginobj* obj = this->object(handle)->pluginobj();
+
+ if (obj == NULL)
+ return LDPS_BAD_HANDLE;
+
+ obj->unlock(this->task_);
+ return LDPS_OK;
+}
+
+// Get the elf object corresponding to the handle. Return NULL if we
+// found a Pluginobj instead.
+
+Object*
+Plugin_manager::get_elf_object(const void* handle)
+{
+ Object* obj = this->object(
+ static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
+
+ // The object should not be a Pluginobj.
+ if (obj == NULL
+ || obj->pluginobj() != NULL)
+ return NULL;
+
+ return obj;
+}
+
+ld_plugin_status
+Plugin_manager::get_view(unsigned int handle, const void **viewp)
+{
+ off_t offset;
+ size_t filesize;
+ Input_file *input_file;
+ if (this->in_claim_file_handler_)
+ {
+ // We are being called from the claim_file hook.
+ const struct ld_plugin_input_file &f = this->plugin_input_file_;
+ offset = f.offset;
+ filesize = f.filesize;
+ input_file = this->input_file_;
+ }
+ else
+ {
+ // An already claimed file.
+ if (this->object(handle) == NULL)
+ return LDPS_BAD_HANDLE;
+ Pluginobj* obj = this->object(handle)->pluginobj();
+ if (obj == NULL)
+ return LDPS_BAD_HANDLE;
+ offset = obj->offset();
+ filesize = obj->filesize();
+ input_file = obj->input_file();
+ }
+ *viewp = (void*) input_file->file().get_view(offset, 0, filesize, false,
+ false);
+ return LDPS_OK;
+}
+
+// Add a new library path.
+
+ld_plugin_status
+Plugin_manager::set_extra_library_path(const char* path)
+{
+ this->extra_search_path_ = std::string(path);
+ return LDPS_OK;
+}
+
+// Add a new input file.
+
+ld_plugin_status
+Plugin_manager::add_input_file(const char* pathname, bool is_lib)
+{
+ Input_file_argument file(pathname,
+ (is_lib
+ ? Input_file_argument::INPUT_FILE_TYPE_LIBRARY
+ : Input_file_argument::INPUT_FILE_TYPE_FILE),
+ (is_lib
+ ? this->extra_search_path_.c_str()
+ : ""),
+ false,
+ this->options_);
+ Input_argument* input_argument = new Input_argument(file);
+ Task_token* next_blocker = new Task_token(true);
+ next_blocker->add_blocker();
+ if (parameters->incremental())
+ gold_error(_("input files added by plug-ins in --incremental mode not "
+ "supported yet"));
+ this->workqueue_->queue_soon(new Read_symbols(this->input_objects_,
+ this->symtab_,
+ this->layout_,
+ this->dirpath_,
+ 0,
+ this->mapfile_,
+ input_argument,
+ NULL,
+ NULL,
+ this->this_blocker_,
+ next_blocker));
+ this->this_blocker_ = next_blocker;
+ this->any_added_ = true;
+ return LDPS_OK;
+}
+
+// Class Pluginobj.
+
+Pluginobj::Pluginobj(const std::string& name, Input_file* input_file,
+ off_t offset, off_t filesize)
+ : Object(name, input_file, false, offset),
+ nsyms_(0), syms_(NULL), symbols_(), filesize_(filesize), comdat_map_()
+{
+}
+
+// Return TRUE if a defined symbol is referenced from outside the
+// universe of claimed objects. Only references from relocatable,
+// non-IR (unclaimed) objects count as a reference. References from
+// dynamic objects count only as "visible".
+
+static inline bool
+is_referenced_from_outside(Symbol* lsym)
+{
+ if (lsym->in_real_elf())
+ return true;
+ if (parameters->options().relocatable())
+ return true;
+ if (parameters->options().is_undefined(lsym->name()))
+ return true;
+ return false;
+}
+
+// Return TRUE if a defined symbol might be reachable from outside the
+// load module.
+
+static inline bool
+is_visible_from_outside(Symbol* lsym)
+{
+ if (lsym->in_dyn())
+ return true;
+ if (parameters->options().export_dynamic() || parameters->options().shared())
+ return lsym->is_externally_visible();
+ return false;
+}
+
+// Get symbol resolution info.
+
+ld_plugin_status
+Pluginobj::get_symbol_resolution_info(int nsyms,
+ ld_plugin_symbol* syms,
+ int version) const
+{
+ // For version 1 of this interface, we cannot use
+ // LDPR_PREVAILING_DEF_IRONLY_EXP, so we return LDPR_PREVAILING_DEF
+ // instead.
+ const ld_plugin_symbol_resolution ldpr_prevailing_def_ironly_exp
+ = (version > 1
+ ? LDPR_PREVAILING_DEF_IRONLY_EXP
+ : LDPR_PREVAILING_DEF);
+
+ if (nsyms > this->nsyms_)
+ return LDPS_NO_SYMS;
+
+ if (static_cast<size_t>(nsyms) > this->symbols_.size())
+ {
+ // We never decided to include this object. We mark all symbols as
+ // preempted.
+ gold_assert(this->symbols_.size() == 0);
+ for (int i = 0; i < nsyms; i++)
+ syms[i].resolution = LDPR_PREEMPTED_REG;
+ return LDPS_OK;
+ }
+
+ for (int i = 0; i < nsyms; i++)
+ {
+ ld_plugin_symbol* isym = &syms[i];
+ Symbol* lsym = this->symbols_[i];
+ ld_plugin_symbol_resolution res = LDPR_UNKNOWN;
+
+ if (lsym->is_undefined())
+ // The symbol remains undefined.
+ res = LDPR_UNDEF;
+ else if (isym->def == LDPK_UNDEF
+ || isym->def == LDPK_WEAKUNDEF
+ || isym->def == LDPK_COMMON)
+ {
+ // The original symbol was undefined or common.
+ if (lsym->source() != Symbol::FROM_OBJECT)
+ res = LDPR_RESOLVED_EXEC;
+ else if (lsym->object()->pluginobj() == this)
+ {
+ if (is_referenced_from_outside(lsym))
+ res = LDPR_PREVAILING_DEF;
+ else if (is_visible_from_outside(lsym))
+ res = ldpr_prevailing_def_ironly_exp;
+ else
+ res = LDPR_PREVAILING_DEF_IRONLY;
+ }
+ else if (lsym->object()->pluginobj() != NULL)
+ res = LDPR_RESOLVED_IR;
+ else if (lsym->object()->is_dynamic())
+ res = LDPR_RESOLVED_DYN;
+ else
+ res = LDPR_RESOLVED_EXEC;
+ }
+ else
+ {
+ // The original symbol was a definition.
+ if (lsym->source() != Symbol::FROM_OBJECT)
+ res = LDPR_PREEMPTED_REG;
+ else if (lsym->object() == static_cast<const Object*>(this))
+ {
+ if (is_referenced_from_outside(lsym))
+ res = LDPR_PREVAILING_DEF;
+ else if (is_visible_from_outside(lsym))
+ res = ldpr_prevailing_def_ironly_exp;
+ else
+ res = LDPR_PREVAILING_DEF_IRONLY;
+ }
+ else
+ res = (lsym->object()->pluginobj() != NULL
+ ? LDPR_PREEMPTED_IR
+ : LDPR_PREEMPTED_REG);
+ }
+ isym->resolution = res;
+ }
+ return LDPS_OK;
+}
+
+// Return TRUE if the comdat group with key COMDAT_KEY from this object
+// should be kept.
+
+bool
+Pluginobj::include_comdat_group(std::string comdat_key, Layout* layout)
+{
+ std::pair<Comdat_map::iterator, bool> ins =
+ this->comdat_map_.insert(std::make_pair(comdat_key, false));
+
+ // If this is the first time we've seen this comdat key, ask the
+ // layout object whether it should be included.
+ if (ins.second)
+ ins.first->second = layout->find_or_add_kept_section(comdat_key,
+ NULL, 0, true,
+ true, NULL);
+
+ return ins.first->second;
+}
+
+// Class Sized_pluginobj.
+
+template<int size, bool big_endian>
+Sized_pluginobj<size, big_endian>::Sized_pluginobj(
+ const std::string& name,
+ Input_file* input_file,
+ off_t offset,
+ off_t filesize)
+ : Pluginobj(name, input_file, offset, filesize)
+{
+}
+
+// Read the symbols. Not used for plugin objects.
+
+template<int size, bool big_endian>
+void
+Sized_pluginobj<size, big_endian>::do_read_symbols(Read_symbols_data*)
+{
+ gold_unreachable();
+}
+
+// Lay out the input sections. Not used for plugin objects.
+
+template<int size, bool big_endian>
+void
+Sized_pluginobj<size, big_endian>::do_layout(Symbol_table*, Layout*,
+ Read_symbols_data*)
+{
+ gold_unreachable();
+}
+
+// Add the symbols to the symbol table.
+
+template<int size, bool big_endian>
+void
+Sized_pluginobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
+ Read_symbols_data*,
+ Layout* layout)
+{
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ unsigned char symbuf[sym_size];
+ elfcpp::Sym<size, big_endian> sym(symbuf);
+ elfcpp::Sym_write<size, big_endian> osym(symbuf);
+
+ typedef typename elfcpp::Elf_types<size>::Elf_WXword Elf_size_type;
+
+ this->symbols_.resize(this->nsyms_);
+
+ for (int i = 0; i < this->nsyms_; ++i)
+ {
+ const struct ld_plugin_symbol* isym = &this->syms_[i];
+ const char* name = isym->name;
+ const char* ver = isym->version;
+ elfcpp::Elf_Half shndx;
+ elfcpp::STB bind;
+ elfcpp::STV vis;
+
+ if (name != NULL && name[0] == '\0')
+ name = NULL;
+ if (ver != NULL && ver[0] == '\0')
+ ver = NULL;
+
+ switch (isym->def)
+ {
+ case LDPK_WEAKDEF:
+ case LDPK_WEAKUNDEF:
+ bind = elfcpp::STB_WEAK;
+ break;
+ case LDPK_DEF:
+ case LDPK_UNDEF:
+ case LDPK_COMMON:
+ default:
+ bind = elfcpp::STB_GLOBAL;
+ break;
+ }
+
+ switch (isym->def)
+ {
+ case LDPK_DEF:
+ case LDPK_WEAKDEF:
+ shndx = elfcpp::SHN_ABS;
+ break;
+ case LDPK_COMMON:
+ shndx = elfcpp::SHN_COMMON;
+ break;
+ case LDPK_UNDEF:
+ case LDPK_WEAKUNDEF:
+ default:
+ shndx = elfcpp::SHN_UNDEF;
+ break;
+ }
+
+ switch (isym->visibility)
+ {
+ case LDPV_PROTECTED:
+ vis = elfcpp::STV_PROTECTED;
+ break;
+ case LDPV_INTERNAL:
+ vis = elfcpp::STV_INTERNAL;
+ break;
+ case LDPV_HIDDEN:
+ vis = elfcpp::STV_HIDDEN;
+ break;
+ case LDPV_DEFAULT:
+ default:
+ vis = elfcpp::STV_DEFAULT;
+ break;
+ }
+
+ if (isym->comdat_key != NULL
+ && isym->comdat_key[0] != '\0'
+ && !this->include_comdat_group(isym->comdat_key, layout))
+ shndx = elfcpp::SHN_UNDEF;
+
+ osym.put_st_name(0);
+ osym.put_st_value(0);
+ osym.put_st_size(static_cast<Elf_size_type>(isym->size));
+ osym.put_st_info(bind, elfcpp::STT_NOTYPE);
+ osym.put_st_other(vis, 0);
+ osym.put_st_shndx(shndx);
+
+ this->symbols_[i] =
+ symtab->add_from_pluginobj<size, big_endian>(this, name, ver, &sym);
+ }
+}
+
+template<int size, bool big_endian>
+Archive::Should_include
+Sized_pluginobj<size, big_endian>::do_should_include_member(
+ Symbol_table* symtab,
+ Layout* layout,
+ Read_symbols_data*,
+ std::string* why)
+{
+ char* tmpbuf = NULL;
+ size_t tmpbuflen = 0;
+
+ for (int i = 0; i < this->nsyms_; ++i)
+ {
+ const struct ld_plugin_symbol& sym = this->syms_[i];
+ const char* name = sym.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 symbols, calling a visitor class V for each.
+
+template<int size, bool big_endian>
+void
+Sized_pluginobj<size, big_endian>::do_for_all_global_symbols(
+ Read_symbols_data*,
+ Library_base::Symbol_visitor_base* v)
+{
+ for (int i = 0; i < this->nsyms_; ++i)
+ {
+ const struct ld_plugin_symbol& sym = this->syms_[i];
+ if (sym.def != LDPK_UNDEF)
+ v->visit(sym.name);
+ }
+}
+
+// Iterate over local symbols, calling a visitor class V for each GOT offset
+// associated with a local symbol.
+template<int size, bool big_endian>
+void
+Sized_pluginobj<size, big_endian>::do_for_all_local_got_entries(
+ Got_offset_list::Visitor*) const
+{
+ gold_unreachable();
+}
+
+// Get the size of a section. Not used for plugin objects.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_pluginobj<size, big_endian>::do_section_size(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Get the name of a section. Not used for plugin objects.
+
+template<int size, bool big_endian>
+std::string
+Sized_pluginobj<size, big_endian>::do_section_name(unsigned int)
+{
+ gold_unreachable();
+ return std::string();
+}
+
+// Return a view of the contents of a section. Not used for plugin objects.
+
+template<int size, bool big_endian>
+const unsigned char*
+Sized_pluginobj<size, big_endian>::do_section_contents(
+ unsigned int,
+ section_size_type*,
+ bool)
+{
+ gold_unreachable();
+ return NULL;
+}
+
+// Return section flags. Not used for plugin objects.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_pluginobj<size, big_endian>::do_section_flags(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Return section entsize. Not used for plugin objects.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_pluginobj<size, big_endian>::do_section_entsize(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Return section address. Not used for plugin objects.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_pluginobj<size, big_endian>::do_section_address(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Return section type. Not used for plugin objects.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_pluginobj<size, big_endian>::do_section_type(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Return the section link field. Not used for plugin objects.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_pluginobj<size, big_endian>::do_section_link(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Return the section link field. Not used for plugin objects.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_pluginobj<size, big_endian>::do_section_info(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Return the section alignment. Not used for plugin objects.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_pluginobj<size, big_endian>::do_section_addralign(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Return the Xindex structure to use. Not used for plugin objects.
+
+template<int size, bool big_endian>
+Xindex*
+Sized_pluginobj<size, big_endian>::do_initialize_xindex()
+{
+ gold_unreachable();
+ return NULL;
+}
+
+// Get symbol counts. Don't count plugin objects; the replacement
+// files will provide the counts.
+
+template<int size, bool big_endian>
+void
+Sized_pluginobj<size, big_endian>::do_get_global_symbol_counts(
+ const Symbol_table*,
+ size_t* defined,
+ size_t* used) const
+{
+ *defined = 0;
+ *used = 0;
+}
+
+// Get symbols. Not used for plugin objects.
+
+template<int size, bool big_endian>
+const Object::Symbols*
+Sized_pluginobj<size, big_endian>::do_get_global_symbols() const
+{
+ gold_unreachable();
+}
+
+// Class Plugin_finish. This task runs after all replacement files have
+// been added. For now, it's a placeholder for a possible plugin API
+// to allow the plugin to release most of its resources. The cleanup
+// handlers must be called later, because they can remove the temporary
+// object files that are needed until the end of the link.
+
+class Plugin_finish : public Task
+{
+ public:
+ Plugin_finish(Task_token* this_blocker, Task_token* next_blocker)
+ : this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Plugin_finish()
+ {
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ }
+
+ Task_token*
+ is_runnable()
+ {
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ return NULL;
+ }
+
+ void
+ locks(Task_locker* tl)
+ { tl->add(this, this->next_blocker_); }
+
+ void
+ run(Workqueue*)
+ {
+ // We could call early cleanup handlers here.
+ }
+
+ std::string
+ get_name() const
+ { return "Plugin_finish"; }
+
+ private:
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// Class Plugin_hook.
+
+Plugin_hook::~Plugin_hook()
+{
+}
+
+// Return whether a Plugin_hook task is runnable.
+
+Task_token*
+Plugin_hook::is_runnable()
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ return NULL;
+}
+
+// Return a Task_locker for a Plugin_hook task. We don't need any
+// locks here.
+
+void
+Plugin_hook::locks(Task_locker*)
+{
+}
+
+// Run the "all symbols read" plugin hook.
+
+void
+Plugin_hook::run(Workqueue* workqueue)
+{
+ gold_assert(this->options_.has_plugins());
+ Symbol* start_sym = this->symtab_->lookup(parameters->entry());
+ if (start_sym != NULL)
+ start_sym->set_in_real_elf();
+
+ this->options_.plugins()->all_symbols_read(workqueue,
+ this,
+ this->input_objects_,
+ this->symtab_,
+ this->dirpath_,
+ this->mapfile_,
+ &this->this_blocker_);
+ workqueue->queue_soon(new Plugin_finish(this->this_blocker_,
+ this->next_blocker_));
+}
+
+// The C interface routines called by the plugins.
+
+#ifdef ENABLE_PLUGINS
+
+// Register a claim-file handler.
+
+static enum ld_plugin_status
+register_claim_file(ld_plugin_claim_file_handler handler)
+{
+ gold_assert(parameters->options().has_plugins());
+ parameters->options().plugins()->set_claim_file_handler(handler);
+ return LDPS_OK;
+}
+
+// Register an all-symbols-read handler.
+
+static enum ld_plugin_status
+register_all_symbols_read(ld_plugin_all_symbols_read_handler handler)
+{
+ gold_assert(parameters->options().has_plugins());
+ parameters->options().plugins()->set_all_symbols_read_handler(handler);
+ return LDPS_OK;
+}
+
+// Register a cleanup handler.
+
+static enum ld_plugin_status
+register_cleanup(ld_plugin_cleanup_handler handler)
+{
+ gold_assert(parameters->options().has_plugins());
+ parameters->options().plugins()->set_cleanup_handler(handler);
+ return LDPS_OK;
+}
+
+// Add symbols from a plugin-claimed input file.
+
+static enum ld_plugin_status
+add_symbols(void* handle, int nsyms, const ld_plugin_symbol* syms)
+{
+ gold_assert(parameters->options().has_plugins());
+ Pluginobj* obj = parameters->options().plugins()->make_plugin_object(
+ static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
+ if (obj == NULL)
+ return LDPS_ERR;
+ obj->store_incoming_symbols(nsyms, syms);
+ return LDPS_OK;
+}
+
+// Get the input file information with an open (possibly re-opened)
+// file descriptor.
+
+static enum ld_plugin_status
+get_input_file(const void* handle, struct ld_plugin_input_file* file)
+{
+ gold_assert(parameters->options().has_plugins());
+ unsigned int obj_index =
+ static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
+ return parameters->options().plugins()->get_input_file(obj_index, file);
+}
+
+// Release the input file.
+
+static enum ld_plugin_status
+release_input_file(const void* handle)
+{
+ gold_assert(parameters->options().has_plugins());
+ unsigned int obj_index =
+ static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
+ return parameters->options().plugins()->release_input_file(obj_index);
+}
+
+static enum ld_plugin_status
+get_view(const void *handle, const void **viewp)
+{
+ gold_assert(parameters->options().has_plugins());
+ unsigned int obj_index =
+ static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
+ return parameters->options().plugins()->get_view(obj_index, viewp);
+}
+
+// Get the symbol resolution info for a plugin-claimed input file.
+
+static enum ld_plugin_status
+get_symbols(const void* handle, int nsyms, ld_plugin_symbol* syms)
+{
+ gold_assert(parameters->options().has_plugins());
+ Object* obj = parameters->options().plugins()->object(
+ static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
+ if (obj == NULL)
+ return LDPS_ERR;
+ Pluginobj* plugin_obj = obj->pluginobj();
+ if (plugin_obj == NULL)
+ return LDPS_ERR;
+ return plugin_obj->get_symbol_resolution_info(nsyms, syms, 1);
+}
+
+// Version 2 of the above. The only difference is that this version
+// is allowed to return the resolution code LDPR_PREVAILING_DEF_IRONLY_EXP.
+
+static enum ld_plugin_status
+get_symbols_v2(const void* handle, int nsyms, ld_plugin_symbol* syms)
+{
+ gold_assert(parameters->options().has_plugins());
+ Object* obj = parameters->options().plugins()->object(
+ static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
+ if (obj == NULL)
+ return LDPS_ERR;
+ Pluginobj* plugin_obj = obj->pluginobj();
+ if (plugin_obj == NULL)
+ return LDPS_ERR;
+ return plugin_obj->get_symbol_resolution_info(nsyms, syms, 2);
+}
+
+// Add a new (real) input file generated by a plugin.
+
+static enum ld_plugin_status
+add_input_file(const char* pathname)
+{
+ gold_assert(parameters->options().has_plugins());
+ return parameters->options().plugins()->add_input_file(pathname, false);
+}
+
+// Add a new (real) library required by a plugin.
+
+static enum ld_plugin_status
+add_input_library(const char* pathname)
+{
+ gold_assert(parameters->options().has_plugins());
+ return parameters->options().plugins()->add_input_file(pathname, true);
+}
+
+// Set the extra library path to be used by libraries added via
+// add_input_library
+
+static enum ld_plugin_status
+set_extra_library_path(const char* path)
+{
+ gold_assert(parameters->options().has_plugins());
+ return parameters->options().plugins()->set_extra_library_path(path);
+}
+
+// Issue a diagnostic message from a plugin.
+
+static enum ld_plugin_status
+message(int level, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ switch (level)
+ {
+ case LDPL_INFO:
+ parameters->errors()->info(format, args);
+ break;
+ case LDPL_WARNING:
+ parameters->errors()->warning(format, args);
+ break;
+ case LDPL_ERROR:
+ default:
+ parameters->errors()->error(format, args);
+ break;
+ case LDPL_FATAL:
+ parameters->errors()->fatal(format, args);
+ break;
+ }
+
+ va_end(args);
+ return LDPS_OK;
+}
+
+// Get the section count of the object corresponding to the handle. This
+// plugin interface can only be called in the claim_file handler of the plugin.
+
+static enum ld_plugin_status
+get_input_section_count(const void* handle, unsigned int* count)
+{
+ gold_assert(parameters->options().has_plugins());
+
+ if (!parameters->options().plugins()->in_claim_file_handler())
+ return LDPS_ERR;
+
+ Object* obj = parameters->options().plugins()->get_elf_object(handle);
+
+ if (obj == NULL)
+ return LDPS_ERR;
+
+ *count = obj->shnum();
+ return LDPS_OK;
+}
+
+// Get the type of the specified section in the object corresponding
+// to the handle. This plugin interface can only be called in the
+// claim_file handler of the plugin.
+
+static enum ld_plugin_status
+get_input_section_type(const struct ld_plugin_section section,
+ unsigned int* type)
+{
+ gold_assert(parameters->options().has_plugins());
+
+ if (!parameters->options().plugins()->in_claim_file_handler())
+ return LDPS_ERR;
+
+ Object* obj
+ = parameters->options().plugins()->get_elf_object(section.handle);
+
+ if (obj == NULL)
+ return LDPS_BAD_HANDLE;
+
+ *type = obj->section_type(section.shndx);
+ return LDPS_OK;
+}
+
+// Get the name of the specified section in the object corresponding
+// to the handle. This plugin interface can only be called in the
+// claim_file handler of the plugin.
+
+static enum ld_plugin_status
+get_input_section_name(const struct ld_plugin_section section,
+ char** section_name_ptr)
+{
+ gold_assert(parameters->options().has_plugins());
+
+ if (!parameters->options().plugins()->in_claim_file_handler())
+ return LDPS_ERR;
+
+ Object* obj
+ = parameters->options().plugins()->get_elf_object(section.handle);
+
+ if (obj == NULL)
+ return LDPS_BAD_HANDLE;
+
+ // Check if the object is locked before getting the section name.
+ gold_assert(obj->is_locked());
+
+ const std::string section_name = obj->section_name(section.shndx);
+ *section_name_ptr = static_cast<char*>(malloc(section_name.length() + 1));
+ memcpy(*section_name_ptr, section_name.c_str(), section_name.length() + 1);
+ return LDPS_OK;
+}
+
+// Get the contents of the specified section in the object corresponding
+// to the handle. This plugin interface can only be called in the
+// claim_file handler of the plugin.
+
+static enum ld_plugin_status
+get_input_section_contents(const struct ld_plugin_section section,
+ const unsigned char** section_contents_ptr,
+ size_t* len)
+{
+ gold_assert(parameters->options().has_plugins());
+
+ if (!parameters->options().plugins()->in_claim_file_handler())
+ return LDPS_ERR;
+
+ Object* obj
+ = parameters->options().plugins()->get_elf_object(section.handle);
+
+ if (obj == NULL)
+ return LDPS_BAD_HANDLE;
+
+ // Check if the object is locked before getting the section contents.
+ gold_assert(obj->is_locked());
+
+ section_size_type plen;
+ *section_contents_ptr
+ = obj->section_contents(section.shndx, &plen, false);
+ *len = plen;
+ return LDPS_OK;
+}
+
+// Specify the ordering of sections in the final layout. The sections are
+// specified as (handle,shndx) pairs in the two arrays in the order in
+// which they should appear in the final layout.
+
+static enum ld_plugin_status
+update_section_order(const struct ld_plugin_section* section_list,
+ unsigned int num_sections)
+{
+ gold_assert(parameters->options().has_plugins());
+
+ if (num_sections == 0)
+ return LDPS_OK;
+
+ if (section_list == NULL)
+ return LDPS_ERR;
+
+ Layout* layout = parameters->options().plugins()->layout();
+ gold_assert (layout != NULL);
+
+ std::map<Section_id, unsigned int>* order_map
+ = layout->get_section_order_map();
+
+ /* Store the mapping from Section_id to section position in layout's
+ order_map to consult after output sections are added. */
+ for (unsigned int i = 0; i < num_sections; ++i)
+ {
+ Object* obj = parameters->options().plugins()->get_elf_object(
+ section_list[i].handle);
+ if (obj == NULL)
+ return LDPS_BAD_HANDLE;
+ unsigned int shndx = section_list[i].shndx;
+ Section_id secn_id(obj, shndx);
+ (*order_map)[secn_id] = i + 1;
+ }
+
+ return LDPS_OK;
+}
+
+// Let the linker know that the sections could be reordered.
+
+static enum ld_plugin_status
+allow_section_ordering()
+{
+ gold_assert(parameters->options().has_plugins());
+ Layout* layout = parameters->options().plugins()->layout();
+ layout->set_section_ordering_specified();
+ return LDPS_OK;
+}
+
+// Let the linker know that a subset of sections could be mapped
+// to a unique segment.
+
+static enum ld_plugin_status
+allow_unique_segment_for_sections()
+{
+ gold_assert(parameters->options().has_plugins());
+ Layout* layout = parameters->options().plugins()->layout();
+ layout->set_unique_segment_for_sections_specified();
+ return LDPS_OK;
+}
+
+// This function should map the list of sections specified in the
+// SECTION_LIST to a unique segment. ELF segments do not have names
+// and the NAME is used to identify Output Section which should contain
+// the list of sections. This Output Section will then be mapped to
+// a unique segment. FLAGS is used to specify if any additional segment
+// flags need to be set. For instance, a specific segment flag can be
+// set to identify this segment. Unsetting segment flags is not possible.
+// ALIGN specifies the alignment of the segment.
+
+static enum ld_plugin_status
+unique_segment_for_sections(const char* segment_name,
+ uint64_t flags,
+ uint64_t align,
+ const struct ld_plugin_section* section_list,
+ unsigned int num_sections)
+{
+ gold_assert(parameters->options().has_plugins());
+
+ if (num_sections == 0)
+ return LDPS_OK;
+
+ if (section_list == NULL)
+ return LDPS_ERR;
+
+ Layout* layout = parameters->options().plugins()->layout();
+ gold_assert (layout != NULL);
+
+ Layout::Unique_segment_info* s = new Layout::Unique_segment_info;
+ s->name = segment_name;
+ s->flags = flags;
+ s->align = align;
+
+ for (unsigned int i = 0; i < num_sections; ++i)
+ {
+ Object* obj = parameters->options().plugins()->get_elf_object(
+ section_list[i].handle);
+ if (obj == NULL)
+ return LDPS_BAD_HANDLE;
+ unsigned int shndx = section_list[i].shndx;
+ Const_section_id secn_id(obj, shndx);
+ layout->insert_section_segment_map(secn_id, s);
+ }
+
+ return LDPS_OK;
+}
+
+#endif // ENABLE_PLUGINS
+
+// Allocate a Pluginobj object of the appropriate size and endianness.
+
+static Pluginobj*
+make_sized_plugin_object(Input_file* input_file, off_t offset, off_t filesize)
+{
+ Pluginobj* obj = NULL;
+
+ parameters_force_valid_target();
+ const Target& target(parameters->target());
+
+ if (target.get_size() == 32)
+ {
+ if (target.is_big_endian())
+#ifdef HAVE_TARGET_32_BIG
+ obj = new Sized_pluginobj<32, true>(input_file->filename(),
+ input_file, offset, filesize);
+#else
+ gold_error(_("%s: not configured to support "
+ "32-bit big-endian object"),
+ input_file->filename().c_str());
+#endif
+ else
+#ifdef HAVE_TARGET_32_LITTLE
+ obj = new Sized_pluginobj<32, false>(input_file->filename(),
+ input_file, offset, filesize);
+#else
+ gold_error(_("%s: not configured to support "
+ "32-bit little-endian object"),
+ input_file->filename().c_str());
+#endif
+ }
+ else if (target.get_size() == 64)
+ {
+ if (target.is_big_endian())
+#ifdef HAVE_TARGET_64_BIG
+ obj = new Sized_pluginobj<64, true>(input_file->filename(),
+ input_file, offset, filesize);
+#else
+ gold_error(_("%s: not configured to support "
+ "64-bit big-endian object"),
+ input_file->filename().c_str());
+#endif
+ else
+#ifdef HAVE_TARGET_64_LITTLE
+ obj = new Sized_pluginobj<64, false>(input_file->filename(),
+ input_file, offset, filesize);
+#else
+ gold_error(_("%s: not configured to support "
+ "64-bit little-endian object"),
+ input_file->filename().c_str());
+#endif
+ }
+
+ gold_assert(obj != NULL);
+ return obj;
+}
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/plugin.h b/binutils-2.25/gold/plugin.h
new file mode 100644
index 00000000..e4289ff6
--- /dev/null
+++ b/binutils-2.25/gold/plugin.h
@@ -0,0 +1,594 @@
+// plugin.h -- plugin manager for gold -*- C++ -*-
+
+// Copyright 2008, 2009, 2010, 2011, 2013 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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_PLUGIN_H
+#define GOLD_PLUGIN_H
+
+#include <list>
+#include <string>
+
+#include "object.h"
+#include "plugin-api.h"
+#include "workqueue.h"
+
+namespace gold
+{
+
+class General_options;
+class Input_file;
+class Input_objects;
+class Archive;
+class Input_group;
+class Symbol;
+class Symbol_table;
+class Layout;
+class Dirsearch;
+class Mapfile;
+class Task;
+class Task_token;
+class Pluginobj;
+class Plugin_rescan;
+
+// This class represents a single plugin library.
+
+class Plugin
+{
+ public:
+ Plugin(const char* filename)
+ : handle_(NULL),
+ filename_(filename),
+ args_(),
+ claim_file_handler_(NULL),
+ all_symbols_read_handler_(NULL),
+ cleanup_handler_(NULL),
+ cleanup_done_(false)
+ { }
+
+ ~Plugin()
+ { }
+
+ // Load the library and call its entry point.
+ void
+ load();
+
+ // Call the claim-file handler.
+ bool
+ claim_file(struct ld_plugin_input_file* plugin_input_file);
+
+ // Call the all-symbols-read handler.
+ void
+ all_symbols_read();
+
+ // Call the cleanup handler.
+ void
+ cleanup();
+
+ // Register a claim-file handler.
+ void
+ set_claim_file_handler(ld_plugin_claim_file_handler handler)
+ { this->claim_file_handler_ = handler; }
+
+ // Register an all-symbols-read handler.
+ void
+ set_all_symbols_read_handler(ld_plugin_all_symbols_read_handler handler)
+ { this->all_symbols_read_handler_ = handler; }
+
+ // Register a claim-file handler.
+ void
+ set_cleanup_handler(ld_plugin_cleanup_handler handler)
+ { this->cleanup_handler_ = handler; }
+
+ // Add an argument
+ void
+ add_option(const char* arg)
+ {
+ this->args_.push_back(arg);
+ }
+
+ private:
+ Plugin(const Plugin&);
+ Plugin& operator=(const Plugin&);
+
+ // The shared library handle returned by dlopen.
+ void* handle_;
+ // The argument string given to --plugin.
+ std::string filename_;
+ // The list of argument string given to --plugin-opt.
+ std::vector<std::string> args_;
+ // The plugin's event handlers.
+ ld_plugin_claim_file_handler claim_file_handler_;
+ ld_plugin_all_symbols_read_handler all_symbols_read_handler_;
+ ld_plugin_cleanup_handler cleanup_handler_;
+ // TRUE if the cleanup handlers have been called.
+ bool cleanup_done_;
+};
+
+// A manager class for plugins.
+
+class Plugin_manager
+{
+ public:
+ Plugin_manager(const General_options& options)
+ : plugins_(), objects_(), deferred_layout_objects_(), input_file_(NULL),
+ plugin_input_file_(), rescannable_(), undefined_symbols_(),
+ any_claimed_(false), in_replacement_phase_(false), any_added_(false),
+ in_claim_file_handler_(false),
+ options_(options), workqueue_(NULL), task_(NULL), input_objects_(NULL),
+ symtab_(NULL), layout_(NULL), dirpath_(NULL), mapfile_(NULL),
+ this_blocker_(NULL), extra_search_path_()
+ { this->current_ = plugins_.end(); }
+
+ ~Plugin_manager();
+
+ // Add a plugin library.
+ void
+ add_plugin(const char* filename)
+ { this->plugins_.push_back(new Plugin(filename)); }
+
+ // Add an argument to the current plugin.
+ void
+ add_plugin_option(const char* opt)
+ {
+ Plugin* last = this->plugins_.back();
+ last->add_option(opt);
+ }
+
+ // Load all plugin libraries.
+ void
+ load_plugins(Layout* layout);
+
+ // Call the plugin claim-file handlers in turn to see if any claim the file.
+ Pluginobj*
+ claim_file(Input_file* input_file, off_t offset, off_t filesize,
+ Object* elf_object);
+
+ // Get the object associated with the handle and check if it is an elf object.
+ // If it is not a Pluginobj, it is an elf object.
+ Object*
+ get_elf_object(const void* handle);
+
+ // True if the claim_file handler of the plugins is being called.
+ bool
+ in_claim_file_handler()
+ { return in_claim_file_handler_; }
+
+ // Let the plugin manager save an archive for later rescanning.
+ // This takes ownership of the Archive pointer.
+ void
+ save_archive(Archive*);
+
+ // Let the plugin manager save an input group for later rescanning.
+ // This takes ownership of the Input_group pointer.
+ void
+ save_input_group(Input_group*);
+
+ // Call the all-symbols-read handlers.
+ void
+ all_symbols_read(Workqueue* workqueue, Task* task,
+ Input_objects* input_objects, Symbol_table* symtab,
+ Dirsearch* dirpath, Mapfile* mapfile,
+ Task_token** last_blocker);
+
+ // Tell the plugin manager that we've a new undefined symbol which
+ // may require rescanning.
+ void
+ new_undefined_symbol(Symbol*);
+
+ // Run deferred layout.
+ void
+ layout_deferred_objects();
+
+ // Call the cleanup handlers.
+ void
+ cleanup();
+
+ // Register a claim-file handler.
+ void
+ set_claim_file_handler(ld_plugin_claim_file_handler handler)
+ {
+ gold_assert(this->current_ != plugins_.end());
+ (*this->current_)->set_claim_file_handler(handler);
+ }
+
+ // Register an all-symbols-read handler.
+ void
+ set_all_symbols_read_handler(ld_plugin_all_symbols_read_handler handler)
+ {
+ gold_assert(this->current_ != plugins_.end());
+ (*this->current_)->set_all_symbols_read_handler(handler);
+ }
+
+ // Register a claim-file handler.
+ void
+ set_cleanup_handler(ld_plugin_cleanup_handler handler)
+ {
+ gold_assert(this->current_ != plugins_.end());
+ (*this->current_)->set_cleanup_handler(handler);
+ }
+
+ // Make a new Pluginobj object. This is called when the plugin calls
+ // the add_symbols API.
+ Pluginobj*
+ make_plugin_object(unsigned int handle);
+
+ // Return the object associated with the given HANDLE.
+ Object*
+ object(unsigned int handle) const
+ {
+ if (handle >= this->objects_.size())
+ return NULL;
+ return this->objects_[handle];
+ }
+
+ // Return TRUE if any input files have been claimed by a plugin
+ // and we are still in the initial input phase.
+ bool
+ should_defer_layout() const
+ { return this->any_claimed_ && !this->in_replacement_phase_; }
+
+ // Add a regular object to the deferred layout list. These are
+ // objects whose layout has been deferred until after the
+ // replacement files have arrived.
+ void
+ add_deferred_layout_object(Relobj* obj)
+ { this->deferred_layout_objects_.push_back(obj); }
+
+ // Get input file information with an open (possibly re-opened)
+ // file descriptor.
+ ld_plugin_status
+ get_input_file(unsigned int handle, struct ld_plugin_input_file* file);
+
+ ld_plugin_status
+ get_view(unsigned int handle, const void **viewp);
+
+ // Release an input file.
+ ld_plugin_status
+ release_input_file(unsigned int handle);
+
+ // Add a new input file.
+ ld_plugin_status
+ add_input_file(const char* pathname, bool is_lib);
+
+ // Set the extra library path.
+ ld_plugin_status
+ set_extra_library_path(const char* path);
+
+ // Return TRUE if we are in the replacement phase.
+ bool
+ in_replacement_phase() const
+ { return this->in_replacement_phase_; }
+
+ Input_objects*
+ input_objects() const
+ { return this->input_objects_; }
+
+ Layout*
+ layout()
+ { return this->layout_; }
+
+ private:
+ Plugin_manager(const Plugin_manager&);
+ Plugin_manager& operator=(const Plugin_manager&);
+
+ // Plugin_rescan is a Task which calls the private rescan method.
+ friend class Plugin_rescan;
+
+ // An archive or input group which may have to be rescanned if a
+ // plugin adds a new file.
+ struct Rescannable
+ {
+ bool is_archive;
+ union
+ {
+ Archive* archive;
+ Input_group* input_group;
+ } u;
+
+ Rescannable(Archive* archive)
+ : is_archive(true)
+ { this->u.archive = archive; }
+
+ Rescannable(Input_group* input_group)
+ : is_archive(false)
+ { this->u.input_group = input_group; }
+ };
+
+ typedef std::list<Plugin*> Plugin_list;
+ typedef std::vector<Object*> Object_list;
+ typedef std::vector<Relobj*> Deferred_layout_list;
+ typedef std::vector<Rescannable> Rescannable_list;
+ typedef std::vector<Symbol*> Undefined_symbol_list;
+
+ // Rescan archives for undefined symbols.
+ void
+ rescan(Task*);
+
+ // See whether the rescannable at index I defines SYM.
+ bool
+ rescannable_defines(size_t i, Symbol* sym);
+
+ // The list of plugin libraries.
+ Plugin_list plugins_;
+ // A pointer to the current plugin. Used while loading plugins.
+ Plugin_list::iterator current_;
+
+ // The list of plugin objects. The index of an item in this list
+ // serves as the "handle" that we pass to the plugins.
+ Object_list objects_;
+
+ // The list of regular objects whose layout has been deferred.
+ Deferred_layout_list deferred_layout_objects_;
+
+ // The file currently up for claim by the plugins.
+ Input_file* input_file_;
+ struct ld_plugin_input_file plugin_input_file_;
+
+ // A list of archives and input groups being saved for possible
+ // later rescanning.
+ Rescannable_list rescannable_;
+
+ // A list of undefined symbols found in added files.
+ Undefined_symbol_list undefined_symbols_;
+
+ // Whether any input files have been claimed by a plugin.
+ bool any_claimed_;
+
+ // Set to true after the all symbols read event; indicates that we
+ // are processing replacement files whose symbols should replace the
+ // placeholder symbols from the Pluginobj objects.
+ bool in_replacement_phase_;
+
+ // Whether any input files or libraries were added by a plugin.
+ bool any_added_;
+
+ // Set to true when the claim_file handler of a plugin is called.
+ bool in_claim_file_handler_;
+
+ const General_options& options_;
+ Workqueue* workqueue_;
+ Task* task_;
+ Input_objects* input_objects_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Dirsearch* dirpath_;
+ Mapfile* mapfile_;
+ Task_token* this_blocker_;
+
+ // An extra directory to seach for the libraries passed by
+ // add_input_library.
+ std::string extra_search_path_;
+};
+
+
+// An object file claimed by a plugin. This is an abstract base class.
+// The implementation is the template class Sized_pluginobj.
+
+class Pluginobj : public Object
+{
+ public:
+
+ typedef std::vector<Symbol*> Symbols;
+
+ Pluginobj(const std::string& name, Input_file* input_file, off_t offset,
+ off_t filesize);
+
+ // Fill in the symbol resolution status for the given plugin symbols.
+ ld_plugin_status
+ get_symbol_resolution_info(int nsyms,
+ ld_plugin_symbol* syms,
+ int version) const;
+
+ // Store the incoming symbols from the plugin for later processing.
+ void
+ store_incoming_symbols(int nsyms, const struct ld_plugin_symbol* syms)
+ {
+ this->nsyms_ = nsyms;
+ this->syms_ = syms;
+ }
+
+ // Return TRUE if the comdat group with key COMDAT_KEY from this object
+ // should be kept.
+ bool
+ include_comdat_group(std::string comdat_key, Layout* layout);
+
+ // Return the filename.
+ const std::string&
+ filename() const
+ { return this->input_file()->filename(); }
+
+ // Return the file descriptor.
+ int
+ descriptor()
+ { return this->input_file()->file().descriptor(); }
+
+ // Return the size of the file or archive member.
+ off_t
+ filesize()
+ { return this->filesize_; }
+
+ protected:
+ // Return TRUE if this is an object claimed by a plugin.
+ virtual Pluginobj*
+ do_pluginobj()
+ { return this; }
+
+ // The number of symbols provided by the plugin.
+ int nsyms_;
+
+ // The symbols provided by the plugin.
+ const struct ld_plugin_symbol* syms_;
+
+ // The entries in the symbol table for the external symbols.
+ Symbols symbols_;
+
+ private:
+ // Size of the file (or archive member).
+ off_t filesize_;
+ // Map a comdat key symbol to a boolean indicating whether the comdat
+ // group in this object with that key should be kept.
+ typedef Unordered_map<std::string, bool> Comdat_map;
+ Comdat_map comdat_map_;
+};
+
+// A plugin object, size-specific version.
+
+template<int size, bool big_endian>
+class Sized_pluginobj : public Pluginobj
+{
+ public:
+ Sized_pluginobj(const std::string& name, Input_file* input_file,
+ off_t offset, off_t filesize);
+
+ // 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;
+
+ // Add placeholder symbols from a claimed file.
+ ld_plugin_status
+ add_symbols_from_plugin(int nsyms, const ld_plugin_symbol* syms);
+
+ protected:
+
+ private:
+};
+
+// This Task handles handles the "all symbols read" event hook.
+// The plugin may add additional input files at this time, which must
+// be queued for reading.
+
+class Plugin_hook : public Task
+{
+ public:
+ Plugin_hook(const General_options& options, Input_objects* input_objects,
+ Symbol_table* symtab, Layout* /*layout*/, Dirsearch* dirpath,
+ Mapfile* mapfile, Task_token* this_blocker,
+ Task_token* next_blocker)
+ : options_(options), input_objects_(input_objects), symtab_(symtab),
+ dirpath_(dirpath), mapfile_(mapfile),
+ this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Plugin_hook();
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const
+ { return "Plugin_hook"; }
+
+ private:
+ const General_options& options_;
+ Input_objects* input_objects_;
+ Symbol_table* symtab_;
+ Dirsearch* dirpath_;
+ Mapfile* mapfile_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_PLUGIN_H)
diff --git a/binutils-2.25/gold/po/Make-in b/binutils-2.25/gold/po/Make-in
new file mode 100644
index 00000000..3f0fc76b
--- /dev/null
+++ b/binutils-2.25/gold/po/Make-in
@@ -0,0 +1,258 @@
+# Makefile for program source directory in GNU NLS utilities package.
+# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+# Copyright 2003, 2006, 2007, 2009 Free Software Foundation, Inc.
+#
+# This file may be copied and used freely without restrictions. It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+SHELL = /bin/sh
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+top_builddir = @top_builddir@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+datadir = $(prefix)/@DATADIRNAME@
+localedir = $(datadir)/locale
+gnulocaledir = $(prefix)/share/locale
+gettextsrcdir = $(prefix)/share/gettext/po
+subdir = po
+
+DESTDIR =
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+
+CC = @CC@
+GENCAT = @GENCAT@
+GMSGFMT = PATH=../src:$$PATH @GMSGFMT@
+MSGFMT = @MSGFMT@
+XGETTEXT = PATH=../src:$$PATH @XGETTEXT@
+MSGMERGE = PATH=../src:$$PATH msgmerge
+
+DEFS = @DEFS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+
+INCLUDES = -I.. -I$(top_srcdir)/intl
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
+
+SOURCES = cat-id-tbl.c
+POFILES = @POFILES@
+GMOFILES = @GMOFILES@
+DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(PACKAGE).pot \
+stamp-cat-id $(POFILES) $(GMOFILES) $(SOURCES)
+
+POTFILES = \
+
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+INSTOBJEXT = @INSTOBJEXT@
+
+.SUFFIXES:
+.SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat
+
+.c.o:
+ $(COMPILE) $<
+
+.po.pox:
+ $(MAKE) $(PACKAGE).pot
+ $(MSGMERGE) $< $(srcdir)/$(PACKAGE).pot -o $*.pox
+
+.po.mo:
+ $(MSGFMT) -o $@ $<
+
+.po.gmo:
+ file=`echo $* | sed 's,.*/,,'`.gmo \
+ && rm -f $$file && $(GMSGFMT) -o $$file $<
+
+.po.cat:
+ sed -f ../intl/po2msg.sed < $< > $*.msg \
+ && rm -f $@ && $(GENCAT) $@ $*.msg
+
+
+all: all-@USE_NLS@
+
+all-yes: $(CATALOGS) @MAINT@ $(PACKAGE).pot
+all-no:
+
+$(srcdir)/$(PACKAGE).pot: $(POTFILES)
+ $(XGETTEXT) --default-domain=$(PACKAGE) --directory=$(top_srcdir) \
+ --add-comments -C --keyword=_ --keyword=N_ \
+ --msgid-bugs-address=bug-binutils@gnu.org \
+ --files-from=$(srcdir)/POTFILES.in
+ rm -f $(srcdir)/$(PACKAGE).pot
+ mv $(PACKAGE).po $(srcdir)/$(PACKAGE).pot
+
+$(srcdir)/cat-id-tbl.c: stamp-cat-id; @:
+$(srcdir)/stamp-cat-id: $(PACKAGE).pot
+ rm -f cat-id-tbl.tmp
+ sed -f ../intl/po2tbl.sed $(srcdir)/$(PACKAGE).pot \
+ | sed -e "s/@PACKAGE NAME@/$(PACKAGE)/" > cat-id-tbl.tmp
+ if cmp -s cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; then \
+ rm cat-id-tbl.tmp; \
+ else \
+ echo cat-id-tbl.c changed; \
+ rm -f $(srcdir)/cat-id-tbl.c; \
+ mv cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; \
+ fi
+ cd $(srcdir) && rm -f stamp-cat-id && echo timestamp > stamp-cat-id
+
+
+install: install-exec install-data
+install-exec:
+install-info:
+install-html:
+install-pdf:
+install-data: install-data-@USE_NLS@
+install-data-no: all
+install-data-yes: all
+ if test -r $(MKINSTALLDIRS); then \
+ $(MKINSTALLDIRS) $(DESTDIR)$(datadir); \
+ else \
+ $(top_srcdir)/../mkinstalldirs $(DESTDIR)$(datadir); \
+ fi
+ @catalogs='$(CATALOGS)'; \
+ for cat in $$catalogs; do \
+ cat=`basename $$cat`; \
+ case "$$cat" in \
+ *.gmo) destdir=$(gnulocaledir);; \
+ *) destdir=$(localedir);; \
+ esac; \
+ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+ dir=$(DESTDIR)$$destdir/$$lang/LC_MESSAGES; \
+ if test -r $(MKINSTALLDIRS); then \
+ $(MKINSTALLDIRS) $$dir; \
+ else \
+ $(top_srcdir)/mkinstalldirs $$dir; \
+ fi; \
+ if test -r $$cat; then \
+ $(INSTALL_DATA) $$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
+ echo "installing $$cat as $$dir/$(PACKAGE)$(INSTOBJEXT)"; \
+ else \
+ $(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
+ echo "installing $(srcdir)/$$cat as" \
+ "$$dir/$(PACKAGE)$(INSTOBJEXT)"; \
+ fi; \
+ if test -r $$cat.m; then \
+ $(INSTALL_DATA) $$cat.m $$dir/$(PACKAGE)$(INSTOBJEXT).m; \
+ echo "installing $$cat.m as $$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
+ else \
+ if test -r $(srcdir)/$$cat.m ; then \
+ $(INSTALL_DATA) $(srcdir)/$$cat.m \
+ $$dir/$(PACKAGE)$(INSTOBJEXT).m; \
+ echo "installing $(srcdir)/$$cat as" \
+ "$$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
+ else \
+ true; \
+ fi; \
+ fi; \
+ done
+ if test "$(PACKAGE)" = "gettext"; then \
+ if test -r $(MKINSTALLDIRS); then \
+ $(MKINSTALLDIRS) $(DESTDIR)$(gettextsrcdir); \
+ else \
+ $(top_srcdir)/mkinstalldirs $(DESTDIR)$(gettextsrcdir); \
+ fi; \
+ $(INSTALL_DATA) $(srcdir)/Makefile.in.in \
+ $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \
+ else \
+ : ; \
+ fi
+
+# Define this as empty until I found a useful application.
+installcheck:
+
+uninstall:
+ catalogs='$(CATALOGS)'; \
+ for cat in $$catalogs; do \
+ cat=`basename $$cat`; \
+ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+ rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
+ rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
+ rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
+ rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
+ done
+ rm -f $(DESTDIR)$(gettextsrcdir)/po-Makefile.in.in
+
+check: all
+
+cat-id-tbl.o: ../intl/libgettext.h
+
+html dvi pdf ps info tags TAGS ID:
+
+mostlyclean:
+ rm -f core core.* *.pox $(PACKAGE).po *.old.po cat-id-tbl.tmp
+ rm -fr *.o
+
+clean: mostlyclean
+
+distclean: clean
+ rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m
+
+maintainer-clean: distclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+ rm -f $(GMOFILES)
+
+distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
+dist distdir: update-po $(DISTFILES)
+ dists="$(DISTFILES)"; \
+ for file in $$dists; do \
+ ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+ || cp -p $(srcdir)/$$file $(distdir); \
+ done
+
+update-po: Makefile
+ $(MAKE) $(PACKAGE).pot
+ PATH=`pwd`/../src:$$PATH; \
+ cd $(srcdir); \
+ catalogs='$(CATALOGS)'; \
+ for cat in $$catalogs; do \
+ cat=`basename $$cat`; \
+ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+ mv $$lang.po $$lang.old.po; \
+ echo "$$lang:"; \
+ if $(MSGMERGE) $$lang.old.po $(PACKAGE).pot -o $$lang.po; then \
+ rm -f $$lang.old.po; \
+ else \
+ echo "msgmerge for $$cat failed!"; \
+ rm -f $$lang.po; \
+ mv $$lang.old.po $$lang.po; \
+ fi; \
+ done
+
+POTFILES: POTFILES.in
+ ( if test 'x$(srcdir)' != 'x.'; then \
+ posrcprefix='$(top_srcdir)/'; \
+ else \
+ posrcprefix="../"; \
+ fi; \
+ rm -f $@-t $@ \
+ && (sed -e '/^#/d' -e '/^[ ]*$$/d' \
+ -e "s@.*@ $$posrcprefix& \\\\@" < $(srcdir)/$@.in \
+ | sed -e '$$s/\\$$//') > $@-t \
+ && chmod a-w $@-t \
+ && mv $@-t $@ )
+
+POTFILES.in: @MAINT@ ../Makefile
+ cd .. && $(MAKE) po/POTFILES.in
+
+Makefile: Make-in ../config.status POTFILES
+ cd .. \
+ && CONFIG_FILES=$(subdir)/Makefile.in:$(subdir)/Make-in \
+ CONFIG_HEADERS= $(SHELL) ./config.status
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/binutils-2.25/gold/po/POTFILES.in b/binutils-2.25/gold/po/POTFILES.in
new file mode 100644
index 00000000..53ed816d
--- /dev/null
+++ b/binutils-2.25/gold/po/POTFILES.in
@@ -0,0 +1,102 @@
+archive.cc
+archive.h
+arm-reloc-property.cc
+arm-reloc-property.h
+arm.cc
+attributes.cc
+attributes.h
+binary.cc
+binary.h
+common.cc
+common.h
+compressed_output.cc
+compressed_output.h
+copy-relocs.cc
+copy-relocs.h
+cref.cc
+cref.h
+defstd.cc
+defstd.h
+descriptors.cc
+descriptors.h
+dirsearch.cc
+dirsearch.h
+dwarf_reader.cc
+dwarf_reader.h
+dynobj.cc
+dynobj.h
+ehframe.cc
+ehframe.h
+errors.cc
+errors.h
+expression.cc
+fileread.cc
+fileread.h
+freebsd.h
+gc.cc
+gc.h
+gdb-index.cc
+gdb-index.h
+gold-threads.cc
+gold-threads.h
+gold.cc
+gold.h
+i386.cc
+icf.cc
+icf.h
+incremental.cc
+int_encoding.cc
+int_encoding.h
+layout.cc
+layout.h
+mapfile.cc
+mapfile.h
+merge.cc
+merge.h
+nacl.cc
+nacl.h
+object.cc
+object.h
+options.cc
+options.h
+output.cc
+output.h
+parameters.cc
+parameters.h
+plugin.cc
+plugin.h
+powerpc.cc
+readsyms.cc
+readsyms.h
+reduced_debug_output.cc
+reduced_debug_output.h
+reloc-types.h
+reloc.cc
+reloc.h
+resolve.cc
+script-c.h
+script-sections.cc
+script-sections.h
+script.cc
+script.h
+sparc.cc
+stringpool.cc
+stringpool.h
+symtab.cc
+symtab.h
+target-reloc.h
+target-select.cc
+target-select.h
+target.cc
+target.h
+tilegx.cc
+timer.cc
+timer.h
+tls.h
+token.h
+version.cc
+workqueue-internal.h
+workqueue-threads.cc
+workqueue.cc
+workqueue.h
+x86_64.cc
diff --git a/binutils-2.25/gold/po/es.po b/binutils-2.25/gold/po/es.po
new file mode 100644
index 00000000..2683a2ac
--- /dev/null
+++ b/binutils-2.25/gold/po/es.po
@@ -0,0 +1,2286 @@
+# Mensajes en español para gold 2.22.90.
+# Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+# This file is distributed under the same license as the binutils package.
+# Cristian Othón Martínez Vera <cfuga@cfuga.mx>, 2008, 2009, 2010, 2011, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gold 2.22.90\n"
+"Report-Msgid-Bugs-To: bug-binutils@gnu.org\n"
+"POT-Creation-Date: 2010-03-03 15:08+0100\n"
+"PO-Revision-Date: 2012-07-27 17:14-0500\n"
+"Last-Translator: Cristian Othón Martínez Vera <cfuga@cfuga.mx>\n"
+"Language-Team: Spanish <es@li.org>\n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: archive.cc:119
+#, c-format
+msgid "%s: no archive symbol table (run ranlib)"
+msgstr "%s: no existe la tabla de símbolos de archivo (ejecute ranlib)"
+
+#: archive.cc:204
+#, c-format
+msgid "%s: bad archive symbol table names"
+msgstr "%s: nombres de tabla de símbolos de archivo erróneos"
+
+#: archive.cc:236
+#, c-format
+msgid "%s: malformed archive header at %zu"
+msgstr "%s: encabezado de archivo mal formado en %zu"
+
+#: archive.cc:256
+#, c-format
+msgid "%s: malformed archive header size at %zu"
+msgstr "%s: tamaño de encabezado de archivo mal formado en %zu"
+
+#: archive.cc:267
+#, c-format
+msgid "%s: malformed archive header name at %zu"
+msgstr "%s: nombre de encabezado de archivo mal formado en %zu"
+
+#: archive.cc:297
+#, c-format
+msgid "%s: bad extended name index at %zu"
+msgstr "%s: índice de nombre extendido erróneo en %zu"
+
+#: archive.cc:307
+#, c-format
+msgid "%s: bad extended name entry at header %zu"
+msgstr "%s: entrada de nombre extendida errónea en el encabezado %zu"
+
+#: archive.cc:404
+#, c-format
+msgid "%s: short archive header at %zu"
+msgstr "%s: encabezado de archivo corto en %zu"
+
+#: archive.cc:560
+#, c-format
+msgid "%s: member at %zu is not an ELF object"
+msgstr "%s: el miembro en %zu no es un objeto ELF"
+
+#: archive.cc:879
+#, c-format
+msgid "%s: archive libraries: %u\n"
+msgstr "%s: bibliotecas de archivo: %u\n"
+
+#: archive.cc:881
+#, c-format
+msgid "%s: total archive members: %u\n"
+msgstr "%s: miembros de archivo totales: %u\n"
+
+#: archive.cc:883
+#, c-format
+msgid "%s: loaded archive members: %u\n"
+msgstr "%s: miembros de archivo cargados: %u\n"
+
+#: arm.cc:1149 i386.cc:536 sparc.cc:1087 x86_64.cc:565
+msgid "** PLT"
+msgstr "** PLT"
+
+#: arm.cc:1364 i386.cc:880 powerpc.cc:1014 sparc.cc:1502 x86_64.cc:955
+#: x86_64.cc:1265
+#, c-format
+msgid "%s: unsupported reloc %u against local symbol"
+msgstr "%s: no se admite la reubicación %u contra el símbolo local"
+
+#: arm.cc:1404 powerpc.cc:1105 sparc.cc:1592 x86_64.cc:992
+msgid "requires unsupported dynamic reloc; recompile with -fPIC"
+msgstr "se requiere una reubicación dinámica no admitida; recompile con -fPIC"
+
+#. These are relocations which should only be seen by the
+#. dynamic linker, and should never be seen here.
+#: arm.cc:1519 arm.cc:1739 arm.cc:2354 i386.cc:1002 i386.cc:1334
+#: powerpc.cc:1223 powerpc.cc:1432 sparc.cc:1877 sparc.cc:2238 x86_64.cc:1145
+#: x86_64.cc:1453
+#, c-format
+msgid "%s: unexpected reloc %u in object file"
+msgstr "%s: reubicación %u inesperada en el fichero objeto"
+
+#: arm.cc:1538 i386.cc:1171 powerpc.cc:1242 sparc.cc:1896 x86_64.cc:1279
+#: x86_64.cc:1571
+#, c-format
+msgid "%s: unsupported reloc %u against global symbol %s"
+msgstr "%s: no se admite la reubicación %u contra el símbolo global %s"
+
+#: arm.cc:1804 i386.cc:1542
+#, c-format
+msgid "%s: unsupported RELA reloc section"
+msgstr "%s: no se admite la sección de reubicación RELA"
+
+#: arm.cc:2047
+msgid "relocation R_ARM_MOVW_ABS_NC cannot be used when makinga shared object; recompile with -fPIC"
+msgstr "no se puede usar la reubicación R_ARM_MOVW_ABS_NC cuando se hace un objeto compartido; recompile con -fPIC"
+
+#: arm.cc:2056
+msgid "relocation R_ARM_MOVT_ABS cannot be used when makinga shared object; recompile with -fPIC"
+msgstr "no se puede usar la reubicación R_ARM_MOVT_ABS cundo se hace un objeto compartido; recompile con -fPIC"
+
+#: arm.cc:2067
+msgid "relocation R_ARM_THM_MOVW_ABS_NC cannot be used whenmaking a shared object; recompile with -fPIC"
+msgstr "no se puede usar la reubicación R_ARM_THM_MOVW_ABS_NC cuando se hace un objeto compartido; recompile con -fPIC"
+
+#: arm.cc:2077
+msgid "relocation R_ARM_THM_MOVT_ABS cannot be used whenmaking a shared object; recompile with -fPIC"
+msgstr "no se puede usar la reubicación R_ARM_THM_MOVT_ABS cuando se hace un objeto compartido; recompile con -fPIC"
+
+#: arm.cc:2141
+msgid "cannot find origin of R_ARM_BASE_PREL"
+msgstr "no se puede encontrar el origen de R_ARM_BASE_PREL"
+
+#: arm.cc:2169
+msgid "cannot find origin of R_ARM_BASE_ABS"
+msgstr "no se puede encontrar el origen de R_ARM_BASE_ABS"
+
+#: arm.cc:2230 i386.cc:1820 i386.cc:2521 powerpc.cc:1798 sparc.cc:2711
+#: x86_64.cc:1935 x86_64.cc:2518
+#, c-format
+msgid "unexpected reloc %u in object file"
+msgstr "reubicación %u inesperada en el fichero objeto"
+
+#: arm.cc:2236 i386.cc:1852 i386.cc:1931 i386.cc:1983 i386.cc:2014
+#: i386.cc:2076 powerpc.cc:1804 sparc.cc:2717 sparc.cc:2900 sparc.cc:2961
+#: sparc.cc:3068 x86_64.cc:1956 x86_64.cc:2039 x86_64.cc:2094 x86_64.cc:2119
+#, c-format
+msgid "unsupported reloc %u"
+msgstr "no se admite la reubicación %u"
+
+#: arm.cc:2248
+#, c-format
+msgid "relocation overflow in relocation %u"
+msgstr "desbordamiento de reubicación en la reubicación %u"
+
+#: arm.cc:2256
+#, c-format
+msgid "unexpected opcode while processing relocation %u"
+msgstr "código de operación inesperado al procesar la reubicación %u"
+
+#: arm.cc:2359 i386.cc:2535
+#, c-format
+msgid "unsupported reloc %u in object file"
+msgstr "no se admite la reubicación %u en el fichero objeto"
+
+#: binary.cc:129
+#, c-format
+msgid "cannot open %s: %s:"
+msgstr "no se puede abrir %s: %s"
+
+#: compressed_output.cc:128
+msgid "not compressing section data: zlib error"
+msgstr "no se comprime la sección de datos: erro de zlib"
+
+#: cref.cc:244
+#, c-format
+msgid "cannot open symbol count file %s: %s"
+msgstr "no se puede abrir el fichero de cuenta de símbolos %s: %s"
+
+#: descriptors.cc:116
+#, c-format
+msgid "file %s was removed during the link"
+msgstr "se borró el fichero %s durante el enlace"
+
+#: descriptors.cc:169
+msgid "out of file descriptors and couldn't close any"
+msgstr "descriptores de fichero agotados y no se pudo cerrar alguno"
+
+#: descriptors.cc:190 descriptors.cc:226
+#, c-format
+msgid "while closing %s: %s"
+msgstr "al cerrar %s: %s"
+
+#: dirsearch.cc:71
+#, c-format
+msgid "%s: can not read directory: %s"
+msgstr "%s: no se puede leer el directorio: %s"
+
+#: dwarf_reader.cc:53 dwarf_reader.cc:84
+msgid "Unusually large LEB128 decoded, debug information may be corrupted"
+msgstr "Se decodificó un LEB128 inusualmente grande, la información de depuración puede estar corrupta"
+
+#: dynobj.cc:164
+#, c-format
+msgid "unexpected duplicate type %u section: %u, %u"
+msgstr "duplicado inesperado tipo %u sección: %u, %u"
+
+#: dynobj.cc:200
+#, c-format
+msgid "unexpected link in section %u header: %u != %u"
+msgstr "enlace inesperado en la sección %u encabezado: %u != %u"
+
+#: dynobj.cc:236
+#, c-format
+msgid "DYNAMIC section %u link out of range: %u"
+msgstr "enlace de la sección DYNAMIC %u fuera de rango: %u"
+
+#: dynobj.cc:244
+#, c-format
+msgid "DYNAMIC section %u link %u is not a strtab"
+msgstr "sección DYNAMIC %u enlace %u no es un strtab"
+
+#: dynobj.cc:273
+#, c-format
+msgid "DT_SONAME value out of range: %lld >= %lld"
+msgstr "valor de DT_SONAME fuera de rango: %lld >= %lld"
+
+#: dynobj.cc:285
+#, c-format
+msgid "DT_NEEDED value out of range: %lld >= %lld"
+msgstr "valor de DT_NEEDED fuera de rango: %lld >= %lld"
+
+#: dynobj.cc:298
+msgid "missing DT_NULL in dynamic segment"
+msgstr "falta DT_NULL en el segmento dinámico"
+
+#: dynobj.cc:344
+#, c-format
+msgid "invalid dynamic symbol table name index: %u"
+msgstr "índice de nombre de tabla de símbolos dinámicos inválido: %u"
+
+#: dynobj.cc:351
+#, c-format
+msgid "dynamic symbol table name section has wrong type: %u"
+msgstr "la sección de nombre de tabla de símbolos dinámicos tiene un tipo erróneo: %u"
+
+#: dynobj.cc:438 object.cc:463 object.cc:1106
+#, c-format
+msgid "bad section name offset for section %u: %lu"
+msgstr "desplazamiento de nombre de sección erróneo para la sección %u: %lu"
+
+#: dynobj.cc:468
+#, c-format
+msgid "duplicate definition for version %u"
+msgstr "definición duplicada para la versión %u"
+
+#: dynobj.cc:497
+#, c-format
+msgid "unexpected verdef version %u"
+msgstr "versión verdef %u inesperada"
+
+#: dynobj.cc:513
+#, c-format
+msgid "verdef vd_cnt field too small: %u"
+msgstr "campo vd_cnt verdef demasiado pequeño: %u"
+
+#: dynobj.cc:521
+#, c-format
+msgid "verdef vd_aux field out of range: %u"
+msgstr "campo vd_aux verder fuera de rango: %u"
+
+#: dynobj.cc:532
+#, c-format
+msgid "verdaux vda_name field out of range: %u"
+msgstr "campo vda_name verdaux fuera de rango: %u"
+
+#: dynobj.cc:542
+#, c-format
+msgid "verdef vd_next field out of range: %u"
+msgstr "campo vd_next verdef fuera de rango: %u"
+
+#: dynobj.cc:576
+#, c-format
+msgid "unexpected verneed version %u"
+msgstr "versión verneed %u inesperada"
+
+#: dynobj.cc:585
+#, c-format
+msgid "verneed vn_aux field out of range: %u"
+msgstr "campo vn_aux verneed fuera de rango: %u"
+
+#: dynobj.cc:599
+#, c-format
+msgid "vernaux vna_name field out of range: %u"
+msgstr "campo vna_name vernaux fuera de rango: %u"
+
+#: dynobj.cc:610
+#, c-format
+msgid "verneed vna_next field out of range: %u"
+msgstr "campo vna_next verneed fuera de rango: %u"
+
+#: dynobj.cc:621
+#, c-format
+msgid "verneed vn_next field out of range: %u"
+msgstr "campo vn_next verneed fuera de rango: %u"
+
+#: dynobj.cc:670
+msgid "size of dynamic symbols is not multiple of symbol size"
+msgstr "el tamaño de los símbolos dinámicos no es un múltiplo del tamaño de símbolo"
+
+#: dynobj.cc:1435
+#, c-format
+msgid "symbol %s has undefined version %s"
+msgstr "el símbolo %s tiene la versión sin definir %s"
+
+#: ehframe.h:82
+msgid "** eh_frame_hdr"
+msgstr "** eh_frame_hdr"
+
+#: ehframe.h:353
+msgid "** eh_frame"
+msgstr "** eh_frame"
+
+#: errors.cc:81
+#, c-format
+msgid "%s: fatal error: "
+msgstr "%s: error fatal: "
+
+#: errors.cc:92
+#, c-format
+msgid "%s: error: "
+msgstr "%s: error: "
+
+#: errors.cc:104
+#, c-format
+msgid "%s: warning: "
+msgstr "%s: aviso: "
+
+#: errors.cc:128
+#, c-format
+msgid "%s: %s: error: "
+msgstr "%s: %s: error: "
+
+#: errors.cc:144
+#, c-format
+msgid "%s: %s: warning: "
+msgstr "%s: %s: aviso: "
+
+#: errors.cc:167
+#, c-format
+msgid "%s: %s: error: undefined reference to '%s'\n"
+msgstr "%s: %s: error: referencia a '%s' sin definir\n"
+
+#: errors.cc:172
+#, c-format
+msgid "%s: %s: error: undefined reference to '%s', version '%s'\n"
+msgstr "%s: %s: error: referencia a '%s' sin definir, versión '%s'\n"
+
+#: errors.cc:182
+#, c-format
+msgid "%s: "
+msgstr "%s: "
+
+#: expression.cc:172
+#, c-format
+msgid "undefined symbol '%s' referenced in expression"
+msgstr "se hace referencia al símbolo sin definir '%s' en la expresión"
+
+#: expression.cc:209
+msgid "invalid reference to dot symbol outside of SECTIONS clause"
+msgstr "referencia inválida al símbolo dot fuera de la cláusula SECTIONS"
+
+#. Handle unary operators. We use a preprocessor macro as a hack to
+#. capture the C operator.
+#: expression.cc:278
+msgid "unary "
+msgstr "unario "
+
+#. 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.
+#: expression.cc:400
+msgid "binary "
+msgstr "binario "
+
+#: expression.cc:404
+msgid " by zero"
+msgstr " por cero"
+
+#: expression.cc:575
+msgid "max applied to section relative value"
+msgstr "se aplicó max al valor relativo de la sección"
+
+#: expression.cc:610
+msgid "min applied to section relative value"
+msgstr "se aplicó min al valor relativo de la sección"
+
+#: expression.cc:740
+msgid "aligning to section relative value"
+msgstr "se alinea al valor relativo de la sección"
+
+#: expression.cc:895
+#, c-format
+msgid "unknown constant %s"
+msgstr "constante %s desconocida"
+
+#: expression.cc:1126
+msgid "SEGMENT_START not implemented"
+msgstr "no se admite SEGMENT_START"
+
+#: expression.cc:1135
+msgid "ORIGIN not implemented"
+msgstr "no se admite ORIGIN"
+
+#: expression.cc:1141
+msgid "LENGTH not implemented"
+msgstr "no se admite LENGTH"
+
+#: fileread.cc:65
+#, c-format
+msgid "munmap failed: %s"
+msgstr "falló munmap: %s"
+
+#: fileread.cc:129
+#, c-format
+msgid "%s: fstat failed: %s"
+msgstr "%s: falló fstat: %s"
+
+#: fileread.cc:169
+#, c-format
+msgid "could not reopen file %s"
+msgstr "no se puede reabrir el fichero %s"
+
+#: fileread.cc:302
+#, c-format
+msgid "%s: pread failed: %s"
+msgstr "%s: falló pread: %s"
+
+#: fileread.cc:308
+#, c-format
+msgid "%s: file too short: read only %lld of %lld bytes at %lld"
+msgstr "%s: el fichero era demasiado pequeño: sólo se leyeron %lld de %lld bytes en %lld"
+
+#: fileread.cc:372
+#, c-format
+msgid "%s: attempt to map %lld bytes at offset %lld exceeds size of file; the file may be corrupt"
+msgstr "%s: al intentar mapear %lld bytes en el desplazamiento %lld se excedió el tamaño del fichero; el fichero tal vez se corrompió"
+
+#: fileread.cc:402
+#, c-format
+msgid "%s: mmap offset %lld size %lld failed: %s"
+msgstr "%s: falló el desplazamiento mmap %lld tamaño %lld: %s"
+
+#: fileread.cc:548
+#, c-format
+msgid "%s: lseek failed: %s"
+msgstr "%s: falló lseek: %s"
+
+#: fileread.cc:554
+#, c-format
+msgid "%s: readv failed: %s"
+msgstr "%s: falló readv: %s"
+
+#: fileread.cc:557
+#, c-format
+msgid "%s: file too short: read only %zd of %zd bytes at %lld"
+msgstr "%s: el fichero era demasiado pequeño: sólo se leyeron %zd de %zd bytes en %lld"
+
+#: fileread.cc:706
+#, c-format
+msgid "%s: total bytes mapped for read: %llu\n"
+msgstr "%s: total de bytes mapeados para lectura: %llu\n"
+
+#: fileread.cc:708
+#, c-format
+msgid "%s: maximum bytes mapped for read at one time: %llu\n"
+msgstr "%s: máximo de bytes mapeados para lectura de una sola vez: %llu\n"
+
+#: fileread.cc:791
+#, c-format
+msgid "%s: stat failed: %s"
+msgstr "%s: falló stat: %s"
+
+#: fileread.cc:849
+#, c-format
+msgid "cannot find %s%s"
+msgstr "no se puede encontrar %s%s"
+
+#: fileread.cc:880
+#, c-format
+msgid "cannot find %s"
+msgstr "no se puede encontrar %s"
+
+#: fileread.cc:904
+#, c-format
+msgid "cannot open %s: %s"
+msgstr "no se puede abrir %s: %s"
+
+#: gold-threads.cc:103
+#, c-format
+msgid "pthead_mutextattr_init failed: %s"
+msgstr "falló pthread_mutextattr_init: %s"
+
+#: gold-threads.cc:107
+#, c-format
+msgid "pthread_mutextattr_settype failed: %s"
+msgstr "falló pthread_mutextattr_settype: %s"
+
+#: gold-threads.cc:112
+#, c-format
+msgid "pthread_mutex_init failed: %s"
+msgstr "falló pthread_mutex_init: %s"
+
+#: gold-threads.cc:116
+#, c-format
+msgid "pthread_mutexattr_destroy failed: %s"
+msgstr "falló pthread_mutexattr_destroy: %s"
+
+#: gold-threads.cc:123
+#, c-format
+msgid "pthread_mutex_destroy failed: %s"
+msgstr "falló pthread_mutex_destroy: %s"
+
+#: gold-threads.cc:131 gold-threads.cc:382
+#, c-format
+msgid "pthread_mutex_lock failed: %s"
+msgstr "falló pthread_mutex_lock: %s"
+
+#: gold-threads.cc:139 gold-threads.cc:394
+#, c-format
+msgid "pthread_mutex_unlock failed: %s"
+msgstr "falló pthread_mutex_unlock: %s"
+
+#: gold-threads.cc:220
+#, c-format
+msgid "pthread_cond_init failed: %s"
+msgstr "falló pthread_cond_init: %s"
+
+#: gold-threads.cc:227
+#, c-format
+msgid "pthread_cond_destroy failed: %s"
+msgstr "falló pthread_cond_destroy: %s"
+
+#: gold-threads.cc:236
+#, c-format
+msgid "pthread_cond_wait failed: %s"
+msgstr "falló pthread_cond_wait: %s"
+
+#: gold-threads.cc:244
+#, c-format
+msgid "pthread_cond_signal failed: %s"
+msgstr "falló pthread_cond_signal: %s"
+
+#: gold-threads.cc:252
+#, c-format
+msgid "pthread_cond_broadcast failed: %s"
+msgstr "falló pthread_cond_broadcast: %s"
+
+#: gold-threads.cc:388
+#, c-format
+msgid "pthread_once failed: %s"
+msgstr "falló pthread_once: %s"
+
+#: gold.cc:91
+#, c-format
+msgid "%s: internal error in %s, at %s:%d\n"
+msgstr "%s: error interno en %s, en %s:%d\n"
+
+#: gold.cc:173
+msgid "no input files"
+msgstr "no hay ficheros de entrada"
+
+#: gold.cc:226
+msgid "cannot mix -r with --gc-sections or --icf"
+msgstr "no se puede mezclar -r con --gc-sections o --icf"
+
+#: gold.cc:407
+#, c-format
+msgid "cannot mix -static with dynamic object %s"
+msgstr "no se puede mezclar -static con el objeto dinámico %s"
+
+#: gold.cc:411
+#, c-format
+msgid "cannot mix -r with dynamic object %s"
+msgstr "no se puede mezclar -r con el objeto dinámico %s"
+
+#: gold.cc:415
+#, c-format
+msgid "cannot use non-ELF output format with dynamic object %s"
+msgstr "no se puede usar un formato de salida diferente a ELF con el objeto dinámico %s"
+
+#: gold.cc:427
+#, c-format
+msgid "cannot mix split-stack '%s' and non-split-stack '%s' when using -r"
+msgstr "no se puede mezclar la división-pila '%s' y la no-división-pila '%s' al usar -r"
+
+#. FIXME: This needs to specify the location somehow.
+#: i386.cc:232 i386.cc:1669 sparc.cc:234 sparc.cc:2395 x86_64.cc:237
+#: x86_64.cc:1732
+msgid "missing expected TLS relocation"
+msgstr "falta la reubicación TLS esperada"
+
+#: i386.cc:944 x86_64.cc:1068
+#, c-format
+msgid "section symbol %u has bad shndx %u"
+msgstr "el símbolo de sección %u tiene shndx %u erróneo"
+
+#: i386.cc:1036 i386.cc:1060 sparc.cc:1777 x86_64.cc:1176 x86_64.cc:1204
+#, c-format
+msgid "local symbol %u has bad shndx %u"
+msgstr "el símbolo local %u tiene shndx %u erróneo"
+
+#: i386.cc:1991
+msgid "both SUN and GNU model TLS relocations"
+msgstr "reubicaciones TLS tanto de modelo GNU como SUN"
+
+#: i386.cc:2730 x86_64.cc:2719
+#, c-format
+msgid "failed to match split-stack sequence at section %u offset %0zx"
+msgstr "falló al coincidir la secuencia dividir-pila en la sección %u desplazamiento %0zx"
+
+#: icf.cc:616
+#, c-format
+msgid "%s: ICF Converged after %u iteration(s)"
+msgstr "%s: Convergió ICF después de %u iteracion(es)"
+
+#: icf.cc:619
+#, c-format
+msgid "%s: ICF stopped after %u iteration(s)"
+msgstr "%s: Se detiene ICF después de %u iteracion(es)"
+
+#: icf.cc:633
+#, c-format
+msgid "Could not find symbol %s to unfold\n"
+msgstr "No se puede encontrar el símbolo %s para desincorporar\n"
+
+#: incremental.cc:242
+#, c-format
+msgid "the link might take longer: cannot perform incremental link: %s"
+msgstr "el enlazado puede tardar más: no se puede realizar el enlazado incremental: %s"
+
+#: incremental.cc:302
+msgid "no incremental data from previous build"
+msgstr "no se encontraron datos incrementales de la compilación anterior"
+
+#: incremental.cc:309 incremental.cc:332
+msgid "invalid incremental build data"
+msgstr "datos de compilación incremental inválidos"
+
+#: incremental.cc:321
+msgid "different version of incremental build data"
+msgstr "versión diferente de datos de compilación incremental"
+
+#: incremental.cc:338
+msgid "command line changed"
+msgstr "cambió la línea de órdenes"
+
+#: incremental.cc:362
+#, c-format
+msgid "unsupported ELF machine number %d"
+msgstr "no se admite el número de máquina ELF %d"
+
+#: incremental.cc:387
+msgid "output is not an ELF file."
+msgstr "la salida no es un fichero ELF."
+
+#: incremental.cc:410
+msgid "unsupported file: 32-bit, big-endian"
+msgstr "no se admite el fichero: 32-bit, big-endian"
+
+#: incremental.cc:419
+msgid "unsupported file: 32-bit, little-endian"
+msgstr "no se admite el fichero: 32-bit, little-endian"
+
+#: incremental.cc:431
+msgid "unsupported file: 64-bit, big-endian"
+msgstr "no se admite el fichero: 64-bit, big-endian"
+
+#: incremental.cc:440
+msgid "unsupported file: 64-bit, little-endian"
+msgstr "no se admite el fichero: 64-bit, little-endian"
+
+#: layout.cc:1887
+#, c-format
+msgid "--build-id=uuid failed: could not open /dev/urandom: %s"
+msgstr "falló --build-id=uuid: no se puede abrir /dev/urandom: %s"
+
+#: layout.cc:1894
+#, c-format
+msgid "/dev/urandom: read failed: %s"
+msgstr "/dev/urandom: falló la lectura: %s"
+
+#: layout.cc:1896
+#, c-format
+msgid "/dev/urandom: expected %zu bytes, got %zd bytes"
+msgstr "/dev/urandom: se esperaban %zu bytes, se obtuvieron %zd bytes"
+
+#: layout.cc:1918
+#, c-format
+msgid "--build-id argument '%s' not a valid hex number"
+msgstr "el argumento '%s' de --build-id no es un número hexadecimal válido"
+
+#: layout.cc:1924
+#, c-format
+msgid "unrecognized --build-id argument '%s'"
+msgstr "no se reconoce el argumento '%s' de --build-id"
+
+#: layout.cc:2337
+#, c-format
+msgid "load segment overlap [0x%llx -> 0x%llx] and [0x%llx -> 0x%llx]"
+msgstr "traslape en el segmento de carga [0x%llx -> 0x%llx] y [0x%llx -> 0x%llx]"
+
+#: mapfile.cc:70
+#, c-format
+msgid "cannot open map file %s: %s"
+msgstr "no se puede abrir el fichero de mapeo %s: %s"
+
+#: mapfile.cc:84
+#, c-format
+msgid "cannot close map file: %s"
+msgstr "no se puede cerrar el fichero de mapeo: %s"
+
+#: mapfile.cc:116
+#, c-format
+msgid ""
+"Archive member included because of file (symbol)\n"
+"\n"
+msgstr ""
+"Se incluyó el miembro del archivo debido al fichero (símbolo)\n"
+"\n"
+
+#: mapfile.cc:159
+#, c-format
+msgid ""
+"\n"
+"Allocating common symbols\n"
+msgstr ""
+"\n"
+"Se asignan los símbolos comunes\n"
+
+#: mapfile.cc:161
+#, c-format
+msgid ""
+"Common symbol size file\n"
+"\n"
+msgstr ""
+"Símbolo común tamaño fichero\n"
+"\n"
+
+#: mapfile.cc:195
+#, c-format
+msgid ""
+"\n"
+"Memory map\n"
+"\n"
+msgstr ""
+"\n"
+"Mapa de la memoria\n"
+"\n"
+
+#: mapfile.cc:361
+#, c-format
+msgid ""
+"\n"
+"Discarded input sections\n"
+"\n"
+msgstr ""
+"\n"
+"Secciones de salida descartadas\n"
+"\n"
+
+#: merge.cc:455
+#, c-format
+msgid "%s: %s merged constants size: %lu; input: %zu; output: %zu\n"
+msgstr "%s: %s constantes mezcladas tamaño: %lu; entrada: %zu; salida: %zu\n"
+
+#: merge.cc:478
+msgid "mergeable string section length not multiple of character size"
+msgstr "la longitud de la sección de cadenas mezclables no es un múltiplo del tamaño de carácter"
+
+#: merge.cc:494
+#, c-format
+msgid "%s: last entry in mergeable string section '%s' not null terminated"
+msgstr "%s: la última entrada en la sección de cadenas mezclables '%s' no está terminada con null"
+
+#: merge.cc:613
+#, c-format
+msgid "%s: %s input: %zu\n"
+msgstr "%s: %s entrada: %zu\n"
+
+#: merge.h:300
+msgid "** merge constants"
+msgstr "** mezclar constantes"
+
+#: merge.h:422
+msgid "** merge strings"
+msgstr "** mezclar cadenas"
+
+#: object.cc:75
+msgid "missing SHT_SYMTAB_SHNDX section"
+msgstr "falta la sección SHT_SYMTAB_SHNDX"
+
+#: object.cc:119
+#, c-format
+msgid "symbol %u out of range for SHT_SYMTAB_SHNDX section"
+msgstr "el símbolo %u está fuera de rango para la sección SHT_SYMTAB_SHNDX"
+
+#: object.cc:126
+#, c-format
+msgid "extended index for symbol %u out of range: %u"
+msgstr "el índice extendido para el símbolo %u está fuera de rango: %u"
+
+#: object.cc:148 object.cc:2331 output.cc:4052
+#, c-format
+msgid "%s: %s"
+msgstr "%s: %s"
+
+#: object.cc:190
+#, c-format
+msgid "section name section has wrong type: %u"
+msgstr "la sección de nombre de sección tiene tipo erróneo: %u"
+
+#: object.cc:546
+#, c-format
+msgid "invalid symbol table name index: %u"
+msgstr "índice de nombre de tabla de símbolos erróneo: %u"
+
+#: object.cc:552
+#, c-format
+msgid "symbol table name section has wrong type: %u"
+msgstr "la sección de nombre de tabla de símbolos tiene tipo erróneo: %u"
+
+#: object.cc:641
+#, c-format
+msgid "section group %u info %u out of range"
+msgstr "la sección grupo %u info %u está fuera de rango"
+
+#: object.cc:660
+#, c-format
+msgid "symbol %u name offset %u out of range"
+msgstr "el símbolo %u nombre desplazamiento %u está fuera de rango"
+
+#: object.cc:678
+#, c-format
+msgid "symbol %u invalid section index %u"
+msgstr "el símbolo %u tiene un índice de sección %u inválido"
+
+#: object.cc:723
+#, c-format
+msgid "section %u in section group %u out of range"
+msgstr "la sección %u en el grupo de sección %u está fuera de rango"
+
+#: object.cc:731
+#, c-format
+msgid "invalid section group %u refers to earlier section %u"
+msgstr "el grupo de sección %u inválido se refiere a la sección %u anterior"
+
+#: object.cc:1037 reloc.cc:271 reloc.cc:838
+#, c-format
+msgid "relocation section %u has bad info %u"
+msgstr "la sección de reubicación %u tiene información %u errónea"
+
+#: object.cc:1231
+#, c-format
+msgid "%s: removing unused section from '%s' in file '%s'"
+msgstr "%s: se borra la sección sin usar de '%s' en el fichero '%s'"
+
+#: object.cc:1257
+#, c-format
+msgid "%s: ICF folding section '%s' in file '%s'into '%s' in file '%s'"
+msgstr "%s: la sección de incorporación ICF '%s' en el fichero '%s' dentro de '%s' en el fichero '%s'"
+
+#: object.cc:1454
+msgid "size of symbols is not multiple of symbol size"
+msgstr "el tamaño de los símbolos no es un múltiplo del tamaño de símbolo"
+
+#: object.cc:1563
+#, c-format
+msgid "local symbol %u section name out of range: %u >= %u"
+msgstr "el nombre de sección del símbolo local %u está fuera de rango: %u >= %u"
+
+#: object.cc:1652
+#, c-format
+msgid "unknown section index %u for local symbol %u"
+msgstr "índice de sección %u desconocido para el símbolo local %u"
+
+#: object.cc:1661
+#, c-format
+msgid "local symbol %u section index %u out of range"
+msgstr "el símbolo local %u índice de sección %u está fuera de rango"
+
+#: object.cc:2169
+#, c-format
+msgid "%s is not supported but is required for %s in %s"
+msgstr "no se admite %s pero se requiere para %s en %s"
+
+#: object.cc:2273
+#, c-format
+msgid "%s: unsupported ELF machine number %d"
+msgstr "%s: no se admite el número de máquina ELF %d"
+
+#: object.cc:2283
+#, c-format
+msgid "%s: incompatible target"
+msgstr "%s: objetivo incompatible"
+
+#: object.cc:2347 plugin.cc:1019
+#, c-format
+msgid "%s: not configured to support 32-bit big-endian object"
+msgstr "%s: no se configuró para admitir objetos big-endian de 32-bit"
+
+#: object.cc:2363 plugin.cc:1028
+#, c-format
+msgid "%s: not configured to support 32-bit little-endian object"
+msgstr "%s: no se configuró para admitir objetos little-endian de 32-bit"
+
+#: object.cc:2382 plugin.cc:1040
+#, c-format
+msgid "%s: not configured to support 64-bit big-endian object"
+msgstr "%s: no se configuró para admitir objetos big-endian de 64-bit"
+
+#: object.cc:2398 plugin.cc:1049
+#, c-format
+msgid "%s: not configured to support 64-bit little-endian object"
+msgstr "%s: no se configuró para admitir objetos little-endian de 64-bit"
+
+#: options.cc:156
+#, c-format
+msgid ""
+"Usage: %s [options] file...\n"
+"Options:\n"
+msgstr ""
+"Modo de empleo: %s [opciones] fichero...\n"
+"Opciones:\n"
+
+#. config.guess and libtool.m4 look in ld --help output for the
+#. string "supported targets".
+#: options.cc:164
+#, c-format
+msgid "%s: supported targets:"
+msgstr "%s: objetivos admitidos:"
+
+#: options.cc:176
+#, c-format
+msgid "Report bugs to %s\n"
+msgstr "Reporte bichos a %s\n"
+
+#: options.cc:193 options.cc:203 options.cc:213
+#, c-format
+msgid "%s: invalid option value (expected an integer): %s"
+msgstr "%s: valor de opción inválido (se esperaba un entero): %s"
+
+#: options.cc:223
+#, c-format
+msgid "%s: invalid option value (expected a floating point number): %s"
+msgstr "%s: valor de opción inválido (se esperaba un número de coma flotante): %s"
+
+#: options.cc:232
+#, c-format
+msgid "%s: must take a non-empty argument"
+msgstr "%s: debe tomar un argumento que no esté vacío"
+
+#: options.cc:273
+#, c-format
+msgid "%s: must take one of the following arguments: %s"
+msgstr "%s: debe tomar uno de los siguientes argumentos: %s"
+
+#: options.cc:300
+#, c-format
+msgid " Supported targets:\n"
+msgstr " Objetivos admitidos:\n"
+
+#: options.cc:409
+#, c-format
+msgid "unable to parse script file %s"
+msgstr "no se puede decodificar el fichero de guión %s"
+
+#: options.cc:417
+#, c-format
+msgid "unable to parse version script file %s"
+msgstr "no se puede decodificar el fichero de guión de versión %s"
+
+#: options.cc:425
+#, c-format
+msgid "unable to parse dynamic-list script file %s"
+msgstr "no se puede decodificar el fichero de guión de lista dinámica %s"
+
+#: options.cc:522
+#, c-format
+msgid "format '%s' not supported; treating as elf (supported formats: elf, binary)"
+msgstr "no se admite el formato '%s'; se trata como elf (formatos admitidos: elf, binary)"
+
+#: options.cc:538
+#, c-format
+msgid "%s: use the --help option for usage information\n"
+msgstr "%s: use la opción --help para información de modo de empleo\n"
+
+#: options.cc:547
+#, c-format
+msgid "%s: %s: %s\n"
+msgstr "%s: %s: %s\n"
+
+#: options.cc:651
+msgid "unexpected argument"
+msgstr "argumento inesperado"
+
+#: options.cc:664 options.cc:725
+msgid "missing argument"
+msgstr "falta un argumento"
+
+#: options.cc:736
+msgid "unknown -z option"
+msgstr "opción -z desconocida"
+
+#: options.cc:935
+#, c-format
+msgid "ignoring --threads: %s was compiled without thread support"
+msgstr "se descarta --threads: %s se compiló sin soporte para hilos"
+
+#: options.cc:942
+#, c-format
+msgid "ignoring --thread-count: %s was compiled without thread support"
+msgstr "se descarta --thread-count: %s se compiló sin soporte para hilos"
+
+#: options.cc:981
+#, c-format
+msgid "unable to open -retain-symbols-file file %s: %s"
+msgstr "no se puede abrir el fichero -retain-symbols-file %s: %s"
+
+#: options.cc:1003
+msgid "-shared and -static are incompatible"
+msgstr "-shared y -static son incompatibles"
+
+#: options.cc:1005
+msgid "-shared and -pie are incompatible"
+msgstr "-shared y -pie son incompatibles"
+
+#: options.cc:1008
+msgid "-shared and -r are incompatible"
+msgstr "-shared y -r son incompatibles"
+
+#: options.cc:1010
+msgid "-pie and -r are incompatible"
+msgstr "-pie y -r son incompatibles"
+
+#: options.cc:1014
+msgid "-retain-symbols-file does not yet work with -r"
+msgstr "-retain-symbols-file aún no funciona con -r"
+
+#: options.cc:1020
+msgid "binary output format not compatible with -shared or -pie or -r"
+msgstr "el formato de salida binario no es compatible con -shared o -pie o -r"
+
+#: options.cc:1026
+#, c-format
+msgid "--hash-bucket-empty-fraction value %g out of range [0.0, 1.0)"
+msgstr "el valor %g de --hash-bucket-empty-fraction está fuera de rango [0.0, 1.0]"
+
+#: options.cc:1031
+msgid "Options --incremental-changed, --incremental-unchanged, --incremental-unknown require the use of --incremental"
+msgstr "Las opciones --incremental-changed, --incremental-unchanged, --incremental-unknown requieren el uso de --incremental"
+
+#: options.cc:1097
+msgid "May not nest groups"
+msgstr "No se deben anidar grupos"
+
+#: options.cc:1109
+msgid "Group end without group start"
+msgstr "Fin de grupo sin inicio de grupo"
+
+#. I guess it's neither a long option nor a short option.
+#: options.cc:1174
+msgid "unknown option"
+msgstr "opción desconocida"
+
+#: options.cc:1201
+#, c-format
+msgid "%s: missing group end\n"
+msgstr "%s: falta el fin de grupo\n"
+
+#: options.h:571
+msgid "Report usage information"
+msgstr "Muestra la información de uso"
+
+#: options.h:573
+msgid "Report version information"
+msgstr "Muestra la información de la versión"
+
+#: options.h:575
+msgid "Report version and target information"
+msgstr "Muestra la información de la versión y el objetivo"
+
+#: options.h:584 options.h:635
+msgid "Not supported"
+msgstr "No se admite"
+
+#: options.h:585 options.h:636
+msgid "Do not copy DT_NEEDED tags from shared libraries"
+msgstr "No copiar las etiquetas DT_NEEDED desde bibliotecas compartidas"
+
+#: options.h:588
+msgid "Allow unresolved references in shared libraries"
+msgstr "Permite referencias sin resolver en bibliotecas compartidas"
+
+#: options.h:589
+msgid "Do not allow unresolved references in shared libraries"
+msgstr "No permite referencias sin resolver en bibliotecas compartidas"
+
+#: options.h:592
+msgid "Only set DT_NEEDED for shared libraries if used"
+msgstr "Sólo establece DT_NEEDED para las bibliotecas compartidas si se usan"
+
+#: options.h:593
+msgid "Always DT_NEEDED for shared libraries"
+msgstr "Siempre establece DT_NEEDED para las bibliotecas compartidas"
+
+#: options.h:600
+msgid "Set input format"
+msgstr "Establece el formato de salida"
+
+#: options.h:603
+msgid "-l searches for shared libraries"
+msgstr "-l busca bibliotecas compartidas"
+
+#: options.h:605
+msgid "-l does not search for shared libraries"
+msgstr "-l no busca bibliotecas compartidas"
+
+#: options.h:609
+msgid "Bind defined symbols locally"
+msgstr "Enlaza los símbolos definidos localmente"
+
+#: options.h:612
+msgid "Bind defined function symbols locally"
+msgstr "Enlaza los símbolos de función localmente"
+
+#: options.h:615
+msgid "Generate build ID note"
+msgstr "Genera una nota de ID de build"
+
+#: options.h:616 options.h:655
+msgid "[=STYLE]"
+msgstr "[=ESTILO]"
+
+#: options.h:619
+msgid "Check segment addresses for overlaps (default)"
+msgstr "Revisa las direcciones de segmento por traslapes (por defecto)"
+
+#: options.h:620
+msgid "Do not check segment addresses for overlaps"
+msgstr "No revisa las direcciones de segmento por traslapes"
+
+#: options.h:624 options.h:629
+msgid "Compress .debug_* sections in the output file"
+msgstr "Comprime las secciones .debug_* en el fichero de salida"
+
+#: options.h:630
+msgid "[none]"
+msgstr "[ninguno]"
+
+#: options.h:639
+msgid "Define common symbols"
+msgstr "Define símbolos comunes"
+
+#: options.h:640
+msgid "Do not define common symbols"
+msgstr "No define símbolos comunes"
+
+#: options.h:642 options.h:644
+msgid "Alias for -d"
+msgstr "Igual que -d"
+
+#: options.h:647
+msgid "Turn on debugging"
+msgstr "Activa la depuración"
+
+#: options.h:648
+msgid "[all,files,script,task][,...]"
+msgstr "[all,files,script,task][,...]"
+
+#: options.h:651
+msgid "Define a symbol"
+msgstr "Define un símbolo"
+
+#: options.h:651
+msgid "SYMBOL=EXPRESSION"
+msgstr "SÍMBOLO=EXPRESIÓN"
+
+#: options.h:654
+msgid "Demangle C++ symbols in log messages"
+msgstr "Desenreda los símbolos C++ en los mensajes de registro"
+
+#: options.h:658
+msgid "Do not demangle C++ symbols in log messages"
+msgstr "No desenreda los símbolos C++ en los mensajes de registro"
+
+#: options.h:662
+msgid "Try to detect violations of the One Definition Rule"
+msgstr "Trata de detectar las violaciones de la Regla de Una Definición"
+
+#: options.h:666
+msgid "Delete all temporary local symbols"
+msgstr "Borra todos los símbolos locales temporales"
+
+#: options.h:669
+msgid "Add data symbols to dynamic symbols"
+msgstr "Agrega los símbolos de datos a los símbolos dinámicos"
+
+#: options.h:672
+msgid "Add C++ operator new/delete to dynamic symbols"
+msgstr "Agrega el operador de C++ new/delete a los símbolos dinámicos"
+
+#: options.h:675
+msgid "Add C++ typeinfo to dynamic symbols"
+msgstr "Agrega la información de tipo C++ a los símbolos dinámicos"
+
+#: options.h:678
+msgid "Read a list of dynamic symbols"
+msgstr "Lee una lista de símbolos dinámicos"
+
+#: options.h:678 options.h:732 options.h:766 options.h:893 options.h:921
+msgid "FILE"
+msgstr "FICHERO"
+
+#: options.h:681
+msgid "Set program start address"
+msgstr "Establece la dirección de inicio del programa"
+
+#: options.h:681 options.h:908 options.h:910 options.h:912
+msgid "ADDRESS"
+msgstr "DIRECCIÓN"
+
+#: options.h:684
+msgid "Exclude libraries from automatic export"
+msgstr "Excluye las bibliotecas de la exportación automática"
+
+#: options.h:688
+msgid "Export all dynamic symbols"
+msgstr "Exporta todos los símbolos dinámicos"
+
+#: options.h:689
+msgid "Do not export all dynamic symbols (default)"
+msgstr "No exporta todos los símbolos dinámicos (por defecto)"
+
+#: options.h:692
+msgid "Create exception frame header"
+msgstr "Crea un encabezado de marco de excepción"
+
+#: options.h:695
+msgid "Treat warnings as errors"
+msgstr "Trata los avisos como errores"
+
+#: options.h:696
+msgid "Do not treat warnings as errors"
+msgstr "No trata los avisos como errores"
+
+#: options.h:699
+msgid "Call SYMBOL at unload-time"
+msgstr "Llama a SYMBOL al momento de descarga"
+
+#: options.h:699 options.h:729 options.h:873 options.h:915 options.h:936
+#: options.h:939
+msgid "SYMBOL"
+msgstr "SÍMBOLO"
+
+#: options.h:702
+msgid "Set shared library name"
+msgstr "Establece el nombre de la biblioteca compartida"
+
+#: options.h:702 options.h:792
+msgid "FILENAME"
+msgstr "FICHERO"
+
+#: options.h:705
+msgid "Min fraction of empty buckets in dynamic hash"
+msgstr "Fracción mínima de las cubos vacíos en la asociación dinámica"
+
+#: options.h:706
+msgid "FRACTION"
+msgstr "FRACCIÓN"
+
+#: options.h:709
+msgid "Dynamic hash style"
+msgstr "Estilo de asociación dinámica"
+
+#: options.h:709
+msgid "[sysv,gnu,both]"
+msgstr "[sysv,gnu,both]"
+
+#: options.h:713
+msgid "Set dynamic linker path"
+msgstr "Establece la ruta del enlazador dinámico"
+
+#: options.h:713
+msgid "PROGRAM"
+msgstr "PROGRAMA"
+
+#: options.h:716
+msgid "Work in progress; do not use"
+msgstr "Trabajo en progreso; no usar"
+
+#: options.h:717
+msgid "Do a full build"
+msgstr "Hace una compilación completa"
+
+#: options.h:720
+msgid "Assume files changed"
+msgstr "Asume que los ficheros cambiaron"
+
+#: options.h:723
+msgid "Assume files didn't change"
+msgstr "Asume que los ficheros no cambiaron"
+
+#: options.h:726
+msgid "Use timestamps to check files (default)"
+msgstr "Usa marcas de tiempo para verificar los ficheros (por defecto)"
+
+#: options.h:729
+msgid "Call SYMBOL at load-time"
+msgstr "Llama a SYMBOL al momento de cargar"
+
+#: options.h:732
+msgid "Read only symbol values from FILE"
+msgstr "Lee sólo valores de símbolos del FICHERO"
+
+#: options.h:735
+msgid "Search for library LIBNAME"
+msgstr "Busca la biblioteca NOMBREBIB"
+
+#: options.h:735
+msgid "LIBNAME"
+msgstr "NOMBREBIB"
+
+#: options.h:738
+msgid "Add directory to search path"
+msgstr "Agrega el directorio a la ruta de búsqueda"
+
+#: options.h:738 options.h:813 options.h:816 options.h:820 options.h:887
+msgid "DIR"
+msgstr "DIR"
+
+#: options.h:741
+msgid "Ignored for compatibility"
+msgstr "Se descarta por compatibilidad"
+
+#: options.h:741
+msgid "EMULATION"
+msgstr "EMULACIÓN"
+
+#: options.h:744
+msgid "Write map file on standard output"
+msgstr "Escribe el fichero mapa en la salida estándar"
+
+#: options.h:745
+msgid "Write map file"
+msgstr "Escribe un fichero mapa"
+
+#: options.h:746
+msgid "MAPFILENAME"
+msgstr "FICHEROMAPA"
+
+#: options.h:749
+msgid "Do not page align data"
+msgstr "No pagina los datos alineados"
+
+#: options.h:751
+msgid "Do not page align data, do not make text readonly"
+msgstr "No pagina los datos alineados, no hace el texto de sólo lectura"
+
+#: options.h:752
+msgid "Page align data, make text readonly"
+msgstr "Pagina los datos alineados, hace el texto de sólo lectura"
+
+#: options.h:755
+msgid "Enable use of DT_RUNPATH and DT_FLAGS"
+msgstr "Activa el uso de DT_RUNPATH y DT_FLAGS"
+
+#: options.h:756
+msgid "Disable use of DT_RUNPATH and DT_FLAGS"
+msgstr "Desactiva el uso de DT_RUNPATH y DT_FLAGS"
+
+#: options.h:759
+msgid "Create an output file even if errors occur"
+msgstr "Crea un fichero de salida aún si ocurren errores"
+
+#: options.h:762 options.h:958
+msgid "Report undefined symbols (even with --shared)"
+msgstr "Reporta símbolos sin definir (aún con --shared)"
+
+#: options.h:766
+msgid "Set output file name"
+msgstr "Establece el nombre del fichero de salida"
+
+#: options.h:769
+msgid "Optimize output file size"
+msgstr "Optimiza el tamaño del fichero de salida"
+
+#: options.h:769
+msgid "LEVEL"
+msgstr "NIVEL"
+
+#: options.h:772
+msgid "Set output format"
+msgstr "Establece el formato de salida"
+
+#: options.h:772
+msgid "[binary]"
+msgstr "[binary]"
+
+#: options.h:775 options.h:777
+msgid "Create a position independent executable"
+msgstr "Crea un ejecutable independiente de posición"
+
+#: options.h:782
+msgid "Load a plugin library"
+msgstr "Carga una biblioteca de plugin"
+
+#: options.h:782
+msgid "PLUGIN"
+msgstr "PLUGIN"
+
+#: options.h:784
+msgid "Pass an option to the plugin"
+msgstr "Pasa una opción al plugin"
+
+#: options.h:784
+msgid "OPTION"
+msgstr "OPCIÓN"
+
+#: options.h:788
+msgid "Preread archive symbols when multi-threaded"
+msgstr "Prelee los símbolos de archivo cuando es multi-hilos"
+
+#: options.h:791
+msgid "Print symbols defined and used for each input"
+msgstr "Muestra los símbolos definidos y usados por cada entrada"
+
+#: options.h:795
+msgid "Ignored for SVR4 compatibility"
+msgstr "Se descarta por compatibilidad con SVR4"
+
+#: options.h:798
+msgid "Generate relocations in output"
+msgstr "Genera reubicaciones en la salida"
+
+#: options.h:801
+msgid "Generate relocatable output"
+msgstr "Genera salida reubicable"
+
+#: options.h:804
+msgid "Relax branches on certain targets"
+msgstr "Relaja ramificaciones en ciertos objetivos"
+
+#: options.h:807
+msgid "keep only symbols listed in this file"
+msgstr "mantiene sólo los símbolos enlistados en este fichero"
+
+#: options.h:807
+msgid "[file]"
+msgstr "[fichero]"
+
+#: options.h:813 options.h:816
+msgid "Add DIR to runtime search path"
+msgstr "Agrega el DIRectorio a la ruta de búsqueda de tiempo de ejecución"
+
+#: options.h:819
+msgid "Add DIR to link time shared library search path"
+msgstr "Agrega el DIRectorio a la ruta de búsqueda de bibliotecas compartidas en tiempo de enlace"
+
+#: options.h:823
+msgid "Strip all symbols"
+msgstr "Descarta todos los símbolos"
+
+#: options.h:825
+msgid "Strip debugging information"
+msgstr "Descarta la información de depuración"
+
+#: options.h:827
+msgid "Emit only debug line number information"
+msgstr "Sólo emite la información de número de línea de depuración"
+
+#: options.h:829
+msgid "Strip debug symbols that are unused by gdb (at least versions <= 6.7)"
+msgstr "Descarta los símbolos de depuración que no usa gdb (por lo menos las versiones <= 6.7)"
+
+#: options.h:832
+msgid "Strip LTO intermediate code sections"
+msgstr "Descarta las secciones de código intermedio LTO"
+
+#: options.h:835
+msgid "(ARM only) The maximum distance from instructions in a group of sections to their stubs. Negative values mean stubs are always after the group. 1 means using default size.\n"
+msgstr "(Sólo ARM) La distancia máxima de las instrucciones en un grupo de secciones a sus cabos. Los valores negativos significan que los cabos siempre van después del grupo. 1 significa usar el tamaño por defecto.\n"
+
+#: options.h:838 options.h:852 options.h:956 options.h:975
+msgid "SIZE"
+msgstr "TAMAÑO"
+
+#: options.h:841
+msgid "Use less memory and more disk I/O (included only for compatibility with GNU ld)"
+msgstr "Usa menos memoria y más E/S de disco (sólo se incluye por compatibilidad con ld de GNU)"
+
+#: options.h:845 options.h:848
+msgid "Generate shared library"
+msgstr "Genera una biblioteca compartida"
+
+#: options.h:851
+msgid "Stack size when -fsplit-stack function calls non-split"
+msgstr "Tamaño de la pila cuando la función -fsplit-stack llama a algo que no está dividido"
+
+#: options.h:857
+msgid "Do not link against shared libraries"
+msgstr "No enlaza contra bibliotecas compartidas"
+
+#: options.h:860
+msgid "Identical Code Folding. '--icf=safe' folds only ctors and dtors."
+msgstr "Incorporación de Código Idéntico (ICF por sus siglas en inglés). '--icf=safe' sólo incorpora ctors y dtors."
+
+#: options.h:866
+msgid "Number of iterations of ICF (default 2)"
+msgstr "Número de iteraciones de ICF (por defecto 2)"
+
+#: options.h:866 options.h:899 options.h:901 options.h:903 options.h:905
+msgid "COUNT"
+msgstr "CUENTA"
+
+#: options.h:869
+msgid "List folded identical sections on stderr"
+msgstr "Enlista las secciones idénticas incorporadas en la salida de error estándar"
+
+#: options.h:870
+msgid "Do not list folded identical sections"
+msgstr "No enlista las secciones idénticas incorporadas"
+
+#: options.h:873
+msgid "Do not fold this symbol during ICF"
+msgstr "No incorpora este símbolo durante ICF"
+
+#: options.h:876
+msgid "Remove unused sections"
+msgstr "Borra las secciones sin uso"
+
+#: options.h:877
+msgid "Don't remove unused sections (default)"
+msgstr "No borra las secciones sin uso (por defecto)"
+
+#: options.h:880
+msgid "List removed unused sections on stderr"
+msgstr "Enlista las secciones sin uso borradas en la salida de error estándar"
+
+#: options.h:881
+msgid "Do not list removed unused sections"
+msgstr "No enlista las secciones sin uso borradas"
+
+#: options.h:884
+msgid "Print resource usage statistics"
+msgstr "Muestra las estadísticas de uso de recursos"
+
+#: options.h:887
+msgid "Set target system root directory"
+msgstr "Establece el directorio raíz del sistema objetivo"
+
+#: options.h:890
+msgid "Print the name of each input file"
+msgstr "Muestra el nombre de cada fichero de entrada"
+
+#: options.h:893
+msgid "Read linker script"
+msgstr "Lee el guión del enlazador"
+
+#: options.h:896
+msgid "Run the linker multi-threaded"
+msgstr "Ejecuta el enlazador multi-hilos"
+
+#: options.h:897
+msgid "Do not run the linker multi-threaded"
+msgstr "No ejecuta el enlazador multi-hilos"
+
+#: options.h:899
+msgid "Number of threads to use"
+msgstr "Número de hilos a usar"
+
+#: options.h:901
+msgid "Number of threads to use in initial pass"
+msgstr "Número de hilos a usar en el paso inicial"
+
+#: options.h:903
+msgid "Number of threads to use in middle pass"
+msgstr "Número de hilos a usar en el paso medio"
+
+#: options.h:905
+msgid "Number of threads to use in final pass"
+msgstr "Número de hilos a usar en el paso final"
+
+#: options.h:908
+msgid "Set the address of the bss segment"
+msgstr "Establece la dirección del segmento bss"
+
+#: options.h:910
+msgid "Set the address of the data segment"
+msgstr "Establece la dirección del segmento data"
+
+#: options.h:912
+msgid "Set the address of the text segment"
+msgstr "Establece la dirección del segmento text"
+
+#: options.h:915
+msgid "Create undefined reference to SYMBOL"
+msgstr "Crea una referencia sin definir hacia el SÍMBOLO"
+
+#: options.h:918
+msgid "Synonym for --debug=files"
+msgstr "Sinónimo para --debug=files"
+
+#: options.h:921
+msgid "Read version script"
+msgstr "Lee el guión de versión"
+
+#: options.h:924
+msgid "Warn about duplicate common symbols"
+msgstr "Avisa sobre símbolos comunes duplicados"
+
+#: options.h:925
+msgid "Do not warn about duplicate common symbols (default)"
+msgstr "No avisa sobre símbolos comunes duplicados (por defecto)"
+
+#: options.h:928
+msgid "Warn when skipping an incompatible library"
+msgstr "Avisa cuando se salta una biblioteca incompatible"
+
+#: options.h:929
+msgid "Don't warn when skipping an incompatible library"
+msgstr "No avisa cuando se salta una biblioteca incompatible"
+
+#: options.h:932
+msgid "Include all archive contents"
+msgstr "Incluye todos los contenidos del archivo"
+
+#: options.h:933
+msgid "Include only needed archive contents"
+msgstr "Incluye sólo los contenidos del archivo necesarios"
+
+#: options.h:936
+msgid "Use wrapper functions for SYMBOL"
+msgstr "Usa funciones de envoltura para el SÍMBOLO"
+
+#: options.h:939
+msgid "Trace references to symbol"
+msgstr "Rastrea las referencias al símbolo"
+
+#: options.h:942
+msgid "Default search path for Solaris compatibility"
+msgstr "Ruta de búsqueda por defecto para compatibilidad con Solaris"
+
+#: options.h:943
+msgid "PATH"
+msgstr "RUTA"
+
+#: options.h:946
+msgid "Start a library search group"
+msgstr "Inicia un grupo de búsqueda de bibliotecas"
+
+#: options.h:948
+msgid "End a library search group"
+msgstr "Termina un grupo de búsqueda de bibliotecas"
+
+#: options.h:953
+msgid "Sort dynamic relocs"
+msgstr "Ordena las reubicaciones dinámicas"
+
+#: options.h:954
+msgid "Do not sort dynamic relocs"
+msgstr "No ordena las reubicaciones dinámicas"
+
+#: options.h:956
+msgid "Set common page size to SIZE"
+msgstr "Establece el tamaño de página común a TAMAÑO"
+
+#: options.h:961
+msgid "Mark output as requiring executable stack"
+msgstr "Marca la salida para requerir pila ejecutable"
+
+#: options.h:963
+msgid "Mark DSO to be initialized first at runtime"
+msgstr "Marca el DSO para inicializarse primero en tiempo de ejecución"
+
+#: options.h:966
+msgid "Mark object to interpose all DSOs but executable"
+msgstr "Marca el objeto para interponer todos los DSOs pero ejecutable"
+
+#: options.h:969
+msgid "Mark object for lazy runtime binding (default)"
+msgstr "Marca el objeto para enlazado en tiempo de ejecución laxo (por defecto)"
+
+#: options.h:972
+msgid "Mark object requiring immediate process"
+msgstr "Marca el objeto para requerir proceso inmediato"
+
+#: options.h:975
+msgid "Set maximum page size to SIZE"
+msgstr "Establece el tamaño máximo de página a TAMAÑO"
+
+#: options.h:978
+msgid "Do not create copy relocs"
+msgstr "No crea reubicaciones de copia"
+
+#: options.h:980
+msgid "Mark object not to use default search paths"
+msgstr "Marca el objeto para no usar las rutas de búsqueda por defecto"
+
+#: options.h:983
+msgid "Mark DSO non-deletable at runtime"
+msgstr "Marca el DSO como no eliminable en tiempo de ejecución"
+
+#: options.h:986
+msgid "Mark DSO not available to dlopen"
+msgstr "Marca el DSO como no disponible para dlopen"
+
+#: options.h:989
+msgid "Mark DSO not available to dldump"
+msgstr "Marca el DSO como no disponible para dldump"
+
+#: options.h:992
+msgid "Mark output as not requiring executable stack"
+msgstr "Marca la salida para no requerir pila ejecutable"
+
+#: options.h:994
+msgid "Mark object for immediate function binding"
+msgstr "Marca el objeto para enlace de función inmediato"
+
+#: options.h:997
+msgid "Mark DSO to indicate that needs immediate $ORIGIN processing at runtime"
+msgstr "Marca el DSO para indicar que requiere procesamiento de $ORIGIN inmediato en tiempo de ejecución"
+
+#: options.h:1000
+msgid "Where possible mark variables read-only after relocation"
+msgstr "Marca las variables como sólo lectura después de la reubicación cuando es posible"
+
+#: options.h:1001
+msgid "Don't mark variables read-only after relocation"
+msgstr "No marca las variables como sólo lectura después de la reubicación"
+
+#: output.cc:1132
+msgid "section group retained but group element discarded"
+msgstr "se retiene el grupo de sección pero se descarta el elemento de grupo"
+
+#: output.cc:1860
+#, c-format
+msgid "invalid alignment %lu for section \"%s\""
+msgstr "alineación %lu inválida para la sección \"%s\""
+
+#: output.cc:3573
+#, c-format
+msgid "dot moves backward in linker script from 0x%llx to 0x%llx"
+msgstr "el punto se mueve hacia atrás en el guión del enlazador de 0x%llx a 0x%llx"
+
+#: output.cc:3576
+#, c-format
+msgid "address of section '%s' moves backward from 0x%llx to 0x%llx"
+msgstr "la dirección de la sección '%s' se mueve hacia atrás de 0x%llx a 0x%llx"
+
+#: output.cc:3755
+#, c-format
+msgid "nobits section %s may not precede progbits section %s in same segment"
+msgstr "la sección nobits %s puede no preceder a la sección progbits %s en el mismo segmento"
+
+#: output.cc:3907 output.cc:3975
+#, c-format
+msgid "%s: open: %s"
+msgstr "%s: open: %s"
+
+#: output.cc:3996
+#, c-format
+msgid "%s: mremap: %s"
+msgstr "%s: mremap: %s"
+
+#: output.cc:4005
+#, c-format
+msgid "%s: mmap: %s"
+msgstr "%s: mmap: %s"
+
+#: output.cc:4085
+#, c-format
+msgid "%s: mmap: failed to allocate %lu bytes for output file: %s"
+msgstr "%s: mmap: falló al reservar %lu bytes para el fichero de salida: %s"
+
+#: output.cc:4096
+#, c-format
+msgid "%s: munmap: %s"
+msgstr "%s: munmap: %s"
+
+#: output.cc:4115
+#, c-format
+msgid "%s: write: unexpected 0 return-value"
+msgstr "%s: wirte: valor de devolución 0 inesperado"
+
+#: output.cc:4117
+#, c-format
+msgid "%s: write: %s"
+msgstr "%s: write: %s"
+
+#: output.cc:4132
+#, c-format
+msgid "%s: close: %s"
+msgstr "%s: close: %s"
+
+#: output.h:520
+msgid "** section headers"
+msgstr "** encabezados de sección"
+
+#: output.h:565
+msgid "** segment headers"
+msgstr "** encabezados de segmento"
+
+#: output.h:613
+msgid "** file header"
+msgstr "** encabezado de fichero"
+
+#: output.h:833
+msgid "** fill"
+msgstr "** relleno"
+
+#: output.h:987
+msgid "** string table"
+msgstr "** tabla de cadenas"
+
+#: output.h:1300
+msgid "** dynamic relocs"
+msgstr "** reubicaciones dinámicas"
+
+#: output.h:1301 output.h:1637
+msgid "** relocs"
+msgstr "** reubicaciones"
+
+#: output.h:1662
+msgid "** group"
+msgstr "** grupo"
+
+#: output.h:1774
+msgid "** GOT"
+msgstr "** GOT"
+
+#: output.h:1916
+msgid "** dynamic"
+msgstr "** dinámico"
+
+#: output.h:2039
+msgid "** symtab xindex"
+msgstr "** xindex symtab"
+
+#: parameters.cc:172
+#, c-format
+msgid "unrecognized output format %s"
+msgstr "no se reconoce el formato de salida %s"
+
+#: plugin.cc:106
+#, c-format
+msgid "%s: could not load plugin library"
+msgstr "%s: no se puede cargar la biblioteca de plugin"
+
+#: plugin.cc:116
+#, c-format
+msgid "%s: could not find onload entry point"
+msgstr "%s: no se puede encontrar el punto de entrada de carga"
+
+#: plugin.cc:426
+msgid "Input files added by plug-ins in --incremental mode not supported yet.\n"
+msgstr "Aún no se admiten los ficheros de entrada agregados por plug-ins en el modo --incremental.\n"
+
+#: powerpc.cc:1502 sparc.cc:2307 x86_64.cc:1632
+#, c-format
+msgid "%s: unsupported REL reloc section"
+msgstr "%s: no se admite la sección de reubicación REL"
+
+#: readsyms.cc:191
+#, c-format
+msgid "%s: file is empty"
+msgstr "%s: el fichero está vacío"
+
+#. Here we have to handle any other input file types we need.
+#: readsyms.cc:575
+#, c-format
+msgid "%s: not an object or archive"
+msgstr "%s: no es un objeto o un archivo"
+
+#: reduced_debug_output.cc:236
+msgid "Debug abbreviations extend beyond .debug_abbrev section; failed to reduce debug abbreviations"
+msgstr "Las abreviaciones de depuración se extienden más allá de la sección .debug_abbrev; falló al reducir las abreviaciones de depuración"
+
+#: reduced_debug_output.cc:322
+msgid "Extremely large compile unit in debug info; failed to reduce debug info"
+msgstr "Unidad de compilación extremadamente grande en la información de depuración; falló al reducir la información de depuración"
+
+#: reduced_debug_output.cc:330
+msgid "Debug info extends beyond .debug_info section;failed to reduce debug info"
+msgstr "La información de depuración se extiende más allá de la sección .debug_info; falló al reducir la información de depuración"
+
+#: reduced_debug_output.cc:350 reduced_debug_output.cc:392
+msgid "Invalid DIE in debug info; failed to reduce debug info"
+msgstr "DIE inválido en la información de depuración; falló al reducir la información de depuración"
+
+#: reduced_debug_output.cc:373
+msgid "Debug info extends beyond .debug_info section; failed to reduce debug info"
+msgstr "La información de depuración se extiende más allá de la sección .debug_info; falló al reducir la información de depuración"
+
+#: reloc.cc:297 reloc.cc:858
+#, c-format
+msgid "relocation section %u uses unexpected symbol table %u"
+msgstr "la sección de reubicación %u usa la tabla de símbolos inesperada %u"
+
+#: reloc.cc:312 reloc.cc:875
+#, c-format
+msgid "unexpected entsize for reloc section %u: %lu != %u"
+msgstr "tamaño de entidad inesperado para la sección de reubicación %u: %lu != %u"
+
+#: reloc.cc:321 reloc.cc:884
+#, c-format
+msgid "reloc section %u size %lu uneven"
+msgstr "sección de reubicación %u tamaño %lu disparejo"
+
+#: reloc.cc:1203
+#, c-format
+msgid "could not convert call to '%s' to '%s'"
+msgstr "no se puede convertir la llamada de '%s' a '%s'"
+
+#: reloc.cc:1343
+#, c-format
+msgid "reloc section size %zu is not a multiple of reloc size %d\n"
+msgstr "el tamaño de la sección de reubicación %zu no es un múltiplo del tamaño de reubicación %d\n"
+
+#. We should only see externally visible symbols in the symbol
+#. table.
+#: resolve.cc:191
+msgid "invalid STB_LOCAL symbol in external symbols"
+msgstr "símbolo STB_LOCAL inválido en símbolos externos"
+
+#. Any target which wants to handle STB_LOOS, etc., needs to
+#. define a resolve method.
+#: resolve.cc:197
+msgid "unsupported symbol binding"
+msgstr "no se admite el enlace de símbolos"
+
+#. A dynamic object cannot reference a hidden or internal symbol
+#. defined in another object.
+#: resolve.cc:266
+#, c-format
+msgid "%s symbol '%s' in %s is referenced by DSO %s"
+msgstr "%s símbolo '%s' en %s es referenciado por el DSO %s"
+
+#: resolve.cc:326
+#, c-format
+msgid "common of '%s' overriding smaller common"
+msgstr "el común de '%s' sobreescribe un común más pequeño"
+
+#: resolve.cc:331
+#, c-format
+msgid "common of '%s' overidden by larger common"
+msgstr "el común de '%s' es sobreescrito por un común más grande"
+
+#: resolve.cc:336
+#, c-format
+msgid "multiple common of '%s'"
+msgstr "comunes múltiples de '%s'"
+
+#: resolve.cc:442
+#, c-format
+msgid "multiple definition of '%s'"
+msgstr "definición múltiple de '%s'"
+
+#: resolve.cc:481
+#, c-format
+msgid "definition of '%s' overriding common"
+msgstr "la definición de '%s' sobreescribe el común"
+
+#: resolve.cc:516
+#, c-format
+msgid "definition of '%s' overriding dynamic common definition"
+msgstr "la definición de '%s' sobreescribe la definición común dinámica"
+
+#: resolve.cc:636
+#, c-format
+msgid "common '%s' overridden by previous definition"
+msgstr "el común '%s' se sobreescribe por la definición previa"
+
+#: resolve.cc:766 resolve.cc:778
+msgid "command line"
+msgstr "línea de órdenes"
+
+#: script-sections.cc:690
+msgid "dot may not move backward"
+msgstr "dot tal vez mueve hacia atrás"
+
+#: script-sections.cc:757
+msgid "** expression"
+msgstr "** expresión"
+
+#: script-sections.cc:941
+msgid "fill value is not absolute"
+msgstr "el valor de relleno no es absoluto"
+
+#: script-sections.cc:1913
+#, c-format
+msgid "alignment of section %s is not absolute"
+msgstr "la alineación de la sección %s no es absoluta"
+
+#: script-sections.cc:1957
+#, c-format
+msgid "subalign of section %s is not absolute"
+msgstr "la subalineación de la sección %s no es absoluta"
+
+#: script-sections.cc:1972
+#, c-format
+msgid "fill of section %s is not absolute"
+msgstr "el relleno de la sección %s no es absoluto"
+
+#: script-sections.cc:2048
+msgid "SPECIAL constraints are not implemented"
+msgstr "no se admiten las restricciones SPECIAL"
+
+#: script-sections.cc:2090
+msgid "mismatched definition for constrained sections"
+msgstr "no coincide la definición para las secciones restringidas"
+
+#: script-sections.cc:2634
+msgid "DATA_SEGMENT_ALIGN may only appear once in a linker script"
+msgstr "DATA_SEGMENT_ALIGN sólo puede aparecer una vez en un guión de enlazado"
+
+#: script-sections.cc:2649
+msgid "DATA_SEGMENT_RELRO_END may only appear once in a linker script"
+msgstr "DATA_SEGMENT_RELRO_END sólo puede aparecer una vez en un guión de enlazado"
+
+#: script-sections.cc:2654
+msgid "DATA_SEGMENT_RELRO_END must follow DATA_SEGMENT_ALIGN"
+msgstr "DATA_SEGMENT_RELRO_END debe seguir a DATA_SEGMENT_ALIGN"
+
+#: script-sections.cc:2826
+msgid "no matching section constraint"
+msgstr "no coincide la restricción de sección"
+
+#: script-sections.cc:3151
+msgid "TLS sections are not adjacent"
+msgstr "las secciones TLS no son adyacentes"
+
+#: script-sections.cc:3280
+msgid "allocated section not in any segment"
+msgstr "la sección alojada no está en ningún segmento"
+
+#: script-sections.cc:3309
+#, c-format
+msgid "no segment %s"
+msgstr "no existe el segmento %s"
+
+#: script-sections.cc:3323
+msgid "section in two PT_LOAD segments"
+msgstr "sección en dos segmentos PT_LOAD"
+
+#: script-sections.cc:3330
+msgid "allocated section not in any PT_LOAD segment"
+msgstr "la sección alojada no está en ningún segmento PT_LOAD"
+
+#: script-sections.cc:3358
+msgid "may only specify load address for PT_LOAD segment"
+msgstr "sólo se puede especificar dirección de carga para un segmento PT_LOAD"
+
+#: script-sections.cc:3382
+#, c-format
+msgid "PHDRS load address overrides section %s load address"
+msgstr "la dirección de carga PHDRS sobreescribe la dirección de carga de la sección %s"
+
+#. We could support this if we wanted to.
+#: script-sections.cc:3393
+msgid "using only one of FILEHDR and PHDRS is not currently supported"
+msgstr "no se admite sólo usar uno de FILEHDR y PHDRS"
+
+#: script-sections.cc:3408
+msgid "sections loaded on first page without room for file and program headers are not supported"
+msgstr "no se admiten las secciones cargadas en la primera página sin espacio para ficheros y encabezados de programa"
+
+#: script-sections.cc:3414
+msgid "using FILEHDR and PHDRS on more than one PT_LOAD segment is not currently supported"
+msgstr "no se admite usar FILEHDR y PHDRS en más de un segmento PT_LOAD"
+
+#: script.cc:1072
+msgid "invalid use of PROVIDE for dot symbol"
+msgstr "uso inválido de PROVIDE para el símbolo dot"
+
+#: script.cc:2132
+#, c-format
+msgid "%s:%d:%d: %s"
+msgstr "%s:%d:%d: %s"
+
+#. There are some options that we could handle here--e.g.,
+#. -lLIBRARY. Should we bother?
+#: script.cc:2297
+#, c-format
+msgid "%s:%d:%d: ignoring command OPTION; OPTION is only valid for scripts specified via -T/--script"
+msgstr "%s:%d:%d se descarta la orden OPTION; OPTION sólo es válido para guiones especificados a través de -T/--script"
+
+#: script.cc:2362
+#, c-format
+msgid "%s:%d:%d: ignoring SEARCH_DIR; SEARCH_DIR is only valid for scripts specified via -T/--script"
+msgstr "%s:%d:%d: se descarta SEARCH_DIR; SEARCH_DIR sólo es válido para guiones especificados a través de -T/--script"
+
+#: script.cc:2606 script.cc:2620
+#, c-format
+msgid "%s:%d:%d: DATA_SEGMENT_ALIGN not in SECTIONS clause"
+msgstr "%s:%d:%d: DATA_SEGMENT_ALIGN no está en la cláusula SECTIONS"
+
+#: script.cc:2739
+msgid "unknown PHDR type (try integer)"
+msgstr "tipo PHDR desconocido (pruebe con entero)"
+
+#: stringpool.cc:528
+#, c-format
+msgid "%s: %s entries: %zu; buckets: %zu\n"
+msgstr "%s: entradas %s: %zu: cubos: %zu\n"
+
+#: stringpool.cc:532
+#, c-format
+msgid "%s: %s entries: %zu\n"
+msgstr "%s: entradas %s: %zu\n"
+
+#: stringpool.cc:535
+#, c-format
+msgid "%s: %s Stringdata structures: %zu\n"
+msgstr "%s: estructuras Stringdata %s: %zu\n"
+
+#: symtab.cc:857
+#, c-format
+msgid "%s: reference to %s"
+msgstr "%s: referencia a %s"
+
+#: symtab.cc:859
+#, c-format
+msgid "%s: definition of %s"
+msgstr "%s: definición de '%s'"
+
+#: symtab.cc:1052
+#, c-format
+msgid "bad global symbol name offset %u at %zu"
+msgstr "desplazamiento de nombres de símbol global %u erróneo en %zu"
+
+#: symtab.cc:1278
+msgid "--just-symbols does not make sense with a shared object"
+msgstr "--just-symbols no tiene sentido con un objeto compartido"
+
+#: symtab.cc:1284
+msgid "too few symbol versions"
+msgstr "faltan versiones de símbolo"
+
+#: symtab.cc:1333
+#, c-format
+msgid "bad symbol name offset %u at %zu"
+msgstr "desplazamiento de nombre de símbolo %u erróneno en %zu"
+
+#: symtab.cc:1396
+#, c-format
+msgid "versym for symbol %zu out of range: %u"
+msgstr "versym para el símbolo %zu está fuera de rango: %u"
+
+#: symtab.cc:1404
+#, c-format
+msgid "versym for symbol %zu has no name: %u"
+msgstr "versym para el símbolo %zu no tienen nombre: %u"
+
+#: symtab.cc:2549 symtab.cc:2681
+#, c-format
+msgid "%s: unsupported symbol section 0x%x"
+msgstr "%s: no se admitide la sección de símbolo 0x%x"
+
+#: symtab.cc:2933
+#, c-format
+msgid "%s: symbol table entries: %zu; buckets: %zu\n"
+msgstr "%s: entradas de tabla de símbolos: %zu; cubos: %zu\n"
+
+#: symtab.cc:2936
+#, c-format
+msgid "%s: symbol table entries: %zu\n"
+msgstr "%s: entradas de tabla de símbolo: %zu\n"
+
+#: symtab.cc:3007
+#, c-format
+msgid "while linking %s: symbol '%s' defined in multiple places (possible ODR violation):"
+msgstr "al enlazar %s: se definió el símbolo '%s' en varios lugares (posible violación ODR):"
+
+#: target-reloc.h:259
+msgid "relocation refers to discarded comdat section"
+msgstr "la reubicación se refiere a la sección comdat descartada"
+
+#: target-reloc.h:298
+#, c-format
+msgid "reloc has bad offset %zu"
+msgstr "la reubicación tiene un desplazamiento %zu erróneo"
+
+#: target.cc:90
+#, c-format
+msgid "%s: unsupported ELF file type %d"
+msgstr "%s: no se admite el tipo de fichero ELF %d"
+
+#: target.cc:157
+#, c-format
+msgid "linker does not include stack split support required by %s"
+msgstr "el enlazador no incluye el soporte de división de pila requerido por %s"
+
+#: tls.h:59
+msgid "TLS relocation out of range"
+msgstr "reubicación TLS fuera de rango"
+
+#: tls.h:73
+msgid "TLS relocation against invalid instruction"
+msgstr "reubicación TLS contra una instrucción inválida"
+
+#. This output is intended to follow the GNU standards.
+#: version.cc:65
+#, c-format
+msgid "Copyright 2008 Free Software Foundation, Inc.\n"
+msgstr "Copyright 2008 Free Software Foundation, Inc.\n"
+
+#: version.cc:66
+#, c-format
+msgid ""
+"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) a later version.\n"
+"This program has absolutely no warranty.\n"
+msgstr ""
+"Este programa es software libre; se puede redistribuir bajo los términos de\n"
+"la Licencia Pública General de GNU versión 3 o (a su elección) una versión\n"
+"posterior.\n"
+"Este programa no tiene absolutamente ninguna garantía.\n"
+
+#: workqueue-threads.cc:106
+#, c-format
+msgid "%s failed: %s"
+msgstr "falló %s: %s"
+
+#: x86_64.cc:2184
+#, c-format
+msgid "unsupported reloc type %u"
+msgstr "no se admite el tipo de reubicación %u"
+
+#: x86_64.cc:2524
+#, c-format
+msgid "unsupported reloc %u against local symbol"
+msgstr "no se admite la reubicación %u contra un símbolo local"
+
+#~ msgid " applied to section relative value"
+#~ msgstr " se aplica al valor relativo a la sección"
+
+#~ msgid "cannot find -l%s"
+#~ msgstr "no se puede encontrar -l%s"
+
+#~ msgid "%s: ELF file too short"
+#~ msgstr "%s: el fichero ELF es demasiado corto"
+
+#~ msgid "%s: invalid ELF version 0"
+#~ msgstr "%s: versión ELF 0 inválida"
+
+#~ msgid "%s: unsupported ELF version %d"
+#~ msgstr "%s: no se admite la versión ELF %d"
+
+#~ msgid "%s: invalid ELF class 0"
+#~ msgstr "%s: clase ELF 0 inválida"
+
+#~ msgid "%s: unsupported ELF class %d"
+#~ msgstr "%s: no se admite la clase ELF %d"
+
+#~ msgid "%s: invalid ELF data encoding"
+#~ msgstr "%s: codificación de datos ELF inválida"
+
+#~ msgid "%s: unsupported ELF data encoding %d"
+#~ msgstr "%s: no se admite la codificación de datos ELF %d"
+
+#~ msgid "%s: lseek: %s"
+#~ msgstr "%s: lseek: %s"
+
+#~ msgid "invalid assignment to dot outside of SECTIONS"
+#~ msgstr "asignación inválida a dot fuera de SECTIONS"
+
+#~ msgid "%s: undefined reference to '%s', version '%s'"
+#~ msgstr "%s: referencia a '%s' sin definir, versión '%s'"
+
+#~ msgid "%s: undefined reference to '%s'"
+#~ msgstr "%s: referencia a '%s' sin definir"
diff --git a/binutils-2.25/gold/po/fi.po b/binutils-2.25/gold/po/fi.po
new file mode 100644
index 00000000..59f28eba
--- /dev/null
+++ b/binutils-2.25/gold/po/fi.po
@@ -0,0 +1,2284 @@
+# Finnish messages for gold.
+# Copyright © 2010, 2011 Free Software Foundation, Inc.
+# This file is distributed under the same license as the binutils package.
+# Jorma Karvonen <karvonen.jorma@gmail.com>, 2010-2011.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gold 2.21.53\n"
+"Report-Msgid-Bugs-To: bug-binutils@gnu.org\n"
+"POT-Creation-Date: 2010-03-03 15:08+0100\n"
+"PO-Revision-Date: 2011-09-23 13:25+0200\n"
+"Last-Translator: Jorma Karvonen <karvonen.jorma@gmail.com>\n"
+"Language-Team: Finnish <translation-team-fi@lists.sourceforge.net>\n"
+"Language: fi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: archive.cc:119
+#, c-format
+msgid "%s: no archive symbol table (run ranlib)"
+msgstr "%s: ei arkistosymbolitaulua (suorita ranlib)"
+
+#: archive.cc:204
+#, c-format
+msgid "%s: bad archive symbol table names"
+msgstr "%s: virheelliset arkistosymbolitaulunimet"
+
+#: archive.cc:236
+#, c-format
+msgid "%s: malformed archive header at %zu"
+msgstr "%s: vääränmuotoinen arkisto-otsake siirrososoitteessa %zu"
+
+#: archive.cc:256
+#, c-format
+msgid "%s: malformed archive header size at %zu"
+msgstr "%s: vääränmuotoinen arkisto-otsakekoko siirrososoitteessa %zu"
+
+#: archive.cc:267
+#, c-format
+msgid "%s: malformed archive header name at %zu"
+msgstr "%s: vääränmuotoinen arkisto-otsakenimi siirrososoitteessa %zu"
+
+#: archive.cc:297
+#, c-format
+msgid "%s: bad extended name index at %zu"
+msgstr "%s: väärä laajennettu nimi-indeksi siirrososoitteessa %zu"
+
+#: archive.cc:307
+#, c-format
+msgid "%s: bad extended name entry at header %zu"
+msgstr "%s: väärä laajennettu nimimerkintä otsakeosoitteessa %zu"
+
+#: archive.cc:404
+#, c-format
+msgid "%s: short archive header at %zu"
+msgstr "%s: lyhyt arkisto-otsake siirrososoitteessa %zu"
+
+#: archive.cc:560
+#, c-format
+msgid "%s: member at %zu is not an ELF object"
+msgstr "%s: jäsen siirrososoitteessa %zu ei ole ELF-objekti"
+
+#: archive.cc:879
+#, c-format
+msgid "%s: archive libraries: %u\n"
+msgstr "%s: arkistokirjastot: %u\n"
+
+#: archive.cc:881
+#, c-format
+msgid "%s: total archive members: %u\n"
+msgstr "%s: yhteensä arkistojäseniä: %u\n"
+
+#: archive.cc:883
+#, c-format
+msgid "%s: loaded archive members: %u\n"
+msgstr "%s: ladattuja arkistojäseniä: %u\n"
+
+#: arm.cc:1149 i386.cc:536 sparc.cc:1087 x86_64.cc:565
+msgid "** PLT"
+msgstr "** PLT"
+
+# Report an unsupported relocation against a local symbol.
+#: arm.cc:1364 i386.cc:880 powerpc.cc:1014 sparc.cc:1502 x86_64.cc:955
+#: x86_64.cc:1265
+#, c-format
+msgid "%s: unsupported reloc %u against local symbol"
+msgstr "%s: tukematon sijoitus %u paikallista symbolia kohtaan"
+
+#: arm.cc:1404 powerpc.cc:1105 sparc.cc:1592 x86_64.cc:992
+msgid "requires unsupported dynamic reloc; recompile with -fPIC"
+msgstr "vaatii tukematonta dynaamista reloc-tietuetta, käännä uudelleen valitsimella -fPIC"
+
+#. These are relocations which should only be seen by the
+#. dynamic linker, and should never be seen here.
+#: arm.cc:1519 arm.cc:1739 arm.cc:2354 i386.cc:1002 i386.cc:1334
+#: powerpc.cc:1223 powerpc.cc:1432 sparc.cc:1877 sparc.cc:2238 x86_64.cc:1145
+#: x86_64.cc:1453
+#, c-format
+msgid "%s: unexpected reloc %u in object file"
+msgstr "%s: odottamaton sijoitus %u objektitiedostossa"
+
+# Report an unsupported relocation against a global symbol.
+#: arm.cc:1538 i386.cc:1171 powerpc.cc:1242 sparc.cc:1896 x86_64.cc:1279
+#: x86_64.cc:1571
+#, c-format
+msgid "%s: unsupported reloc %u against global symbol %s"
+msgstr "%s: tukematon sijoitus %u yleissymbolia %s kohtaan"
+
+# Scan relocations for a section.
+#: arm.cc:1804 i386.cc:1542
+#, c-format
+msgid "%s: unsupported RELA reloc section"
+msgstr "%s: tukematon RELA-sijoituslohko"
+
+#: arm.cc:2047
+msgid "relocation R_ARM_MOVW_ABS_NC cannot be used when makinga shared object; recompile with -fPIC"
+msgstr "sijoitusta R_ARM_MOVW_ABS_NC ei voi käyttää kun tehdään jaettua objektia: käännä uudelleen valitsimella -fPIC"
+
+#: arm.cc:2056
+msgid "relocation R_ARM_MOVT_ABS cannot be used when makinga shared object; recompile with -fPIC"
+msgstr "sijoitusta R_ARM_MOVT_ABS ei voi käyttää kun tehdään jaettua objektia: käännä uudelleen valitsimella -fPIC"
+
+#: arm.cc:2067
+msgid "relocation R_ARM_THM_MOVW_ABS_NC cannot be used whenmaking a shared object; recompile with -fPIC"
+msgstr "sijoitusta R_ARM_THM_MOVW_ABS_NC ei voi käyttää kun tehdään jaettua objektia: käännä uudelleen valitsimella -fPIC"
+
+#: arm.cc:2077
+msgid "relocation R_ARM_THM_MOVT_ABS cannot be used whenmaking a shared object; recompile with -fPIC"
+msgstr "sijoitusta R_ARM_THM_MOVT_ABS ei voi käyttää kun tehdään jaettua objektia: käännä uudelleen valitsimella -fPIC"
+
+#: arm.cc:2141
+msgid "cannot find origin of R_ARM_BASE_PREL"
+msgstr "ei voida löytää R_ARM_BASE_PREL-alkua"
+
+#: arm.cc:2169
+msgid "cannot find origin of R_ARM_BASE_ABS"
+msgstr "ei voida löytää R_ARM_BASE_ABS-alkua"
+
+#: arm.cc:2230 i386.cc:1820 i386.cc:2521 powerpc.cc:1798 sparc.cc:2711
+#: x86_64.cc:1935 x86_64.cc:2518
+#, c-format
+msgid "unexpected reloc %u in object file"
+msgstr "tukematon sijoitus %u objektitiedostossa"
+
+#: arm.cc:2236 i386.cc:1852 i386.cc:1931 i386.cc:1983 i386.cc:2014
+#: i386.cc:2076 powerpc.cc:1804 sparc.cc:2717 sparc.cc:2900 sparc.cc:2961
+#: sparc.cc:3068 x86_64.cc:1956 x86_64.cc:2039 x86_64.cc:2094 x86_64.cc:2119
+#, c-format
+msgid "unsupported reloc %u"
+msgstr "tukematon sijoitus %u"
+
+#: arm.cc:2248
+#, c-format
+msgid "relocation overflow in relocation %u"
+msgstr "sijoitusylivuoto sijoituksessa %u"
+
+#: arm.cc:2256
+#, c-format
+msgid "unexpected opcode while processing relocation %u"
+msgstr "odottamaton käskykoodi käsiteltäessä sijoitusta %u"
+
+#: arm.cc:2359 i386.cc:2535
+#, c-format
+msgid "unsupported reloc %u in object file"
+msgstr "tukematon sijoitus %u objektitiedostossa"
+
+#: binary.cc:129
+#, c-format
+msgid "cannot open %s: %s:"
+msgstr "ei voi avata syötetiedostoa %s: %s:"
+
+#: compressed_output.cc:128
+msgid "not compressing section data: zlib error"
+msgstr "ei tiivistetä lohkodataa: zlib-virhe"
+
+#: cref.cc:244
+#, c-format
+msgid "cannot open symbol count file %s: %s"
+msgstr "ei voi avata symbolilukumäärätiedostoa %s: %s"
+
+#: descriptors.cc:116
+#, c-format
+msgid "file %s was removed during the link"
+msgstr "tiedosto %s poistettiin linkityksen aikana"
+
+#: descriptors.cc:169
+msgid "out of file descriptors and couldn't close any"
+msgstr "ei ole enää tiedostokuvaajia eikä voitu sulkea yhtään"
+
+#: descriptors.cc:190 descriptors.cc:226
+#, c-format
+msgid "while closing %s: %s"
+msgstr "suljetaessa tiedostokuvaajaa %s: %s"
+
+#: dirsearch.cc:71
+#, c-format
+msgid "%s: can not read directory: %s"
+msgstr "%s: ei voi lukea hakemistoa: %s"
+
+#: dwarf_reader.cc:53 dwarf_reader.cc:84
+msgid "Unusually large LEB128 decoded, debug information may be corrupted"
+msgstr "Epätavallisen iso LEB128 dekoodattu, vianjäljitystiedot saattavat olla vääristyneitä"
+
+#: dynobj.cc:164
+#, c-format
+msgid "unexpected duplicate type %u section: %u, %u"
+msgstr "odottamaton kaksoiskappaletyyppi %u lohko: %u, %u"
+
+#: dynobj.cc:200
+#, c-format
+msgid "unexpected link in section %u header: %u != %u"
+msgstr "odottamaton linkitys lohkossa %u otsake: %u != %u"
+
+#: dynobj.cc:236
+#, c-format
+msgid "DYNAMIC section %u link out of range: %u"
+msgstr "DYNAAMINEN lohko %u linkki lukualueen ulkopuolella: %u"
+
+#: dynobj.cc:244
+#, c-format
+msgid "DYNAMIC section %u link %u is not a strtab"
+msgstr "DYNAAMINEN lohko %u linkki %u ei ole ”strtab”"
+
+#: dynobj.cc:273
+#, c-format
+msgid "DT_SONAME value out of range: %lld >= %lld"
+msgstr "DT_SONAME-arvo lukualueen ulkopuolella: %lld >= %lld"
+
+#: dynobj.cc:285
+#, c-format
+msgid "DT_NEEDED value out of range: %lld >= %lld"
+msgstr "DT_NEEDED-arvo lukualueen ulkopuolella: %lld >= %lld"
+
+#: dynobj.cc:298
+msgid "missing DT_NULL in dynamic segment"
+msgstr "puuttuva DT_NULL dynaamisessa segmentissä"
+
+#: dynobj.cc:344
+#, c-format
+msgid "invalid dynamic symbol table name index: %u"
+msgstr "virheellinen dynaaminen symbolitaulunimi-indeksi: %u"
+
+#: dynobj.cc:351
+#, c-format
+msgid "dynamic symbol table name section has wrong type: %u"
+msgstr "dynaamisella symbolitaulunimilohkolla on väärä tyyppi: %u"
+
+#: dynobj.cc:438 object.cc:463 object.cc:1106
+#, c-format
+msgid "bad section name offset for section %u: %lu"
+msgstr "väärä lohkonimisiirrososoite lohkolle %u: %lu"
+
+#: dynobj.cc:468
+#, c-format
+msgid "duplicate definition for version %u"
+msgstr "kaksoiskappalemäärittely versiolle %u"
+
+#: dynobj.cc:497
+#, c-format
+msgid "unexpected verdef version %u"
+msgstr "odottamaton verdef-versio %u"
+
+#: dynobj.cc:513
+#, c-format
+msgid "verdef vd_cnt field too small: %u"
+msgstr "verdef vd_cnt-kenttä liian pieni: %u"
+
+#: dynobj.cc:521
+#, c-format
+msgid "verdef vd_aux field out of range: %u"
+msgstr "verdef vd_aux-kenttä lukualueen ulkopuolella: %u"
+
+#: dynobj.cc:532
+#, c-format
+msgid "verdaux vda_name field out of range: %u"
+msgstr "verdaux vda_name -kenttä lukualueen ulkopuolella: %u"
+
+#: dynobj.cc:542
+#, c-format
+msgid "verdef vd_next field out of range: %u"
+msgstr "verdef vd_next -kenttä lukualueen ulkopuolella: %u"
+
+#: dynobj.cc:576
+#, c-format
+msgid "unexpected verneed version %u"
+msgstr "odottamaton verneed-versio %u"
+
+#: dynobj.cc:585
+#, c-format
+msgid "verneed vn_aux field out of range: %u"
+msgstr "verneed vn_aux-kenttä lukualueen ulkopuolella: %u"
+
+#: dynobj.cc:599
+#, c-format
+msgid "vernaux vna_name field out of range: %u"
+msgstr "vernaux vna_name-kenttä lukualueen ulkopuolella: %u"
+
+#: dynobj.cc:610
+#, c-format
+msgid "verneed vna_next field out of range: %u"
+msgstr "verneed vna_next-kenttä lukualueen ulkopuolella: %u"
+
+#: dynobj.cc:621
+#, c-format
+msgid "verneed vn_next field out of range: %u"
+msgstr "verneed vn_next-kenttä lukualueen ulkopuolella: %u"
+
+#: dynobj.cc:670
+msgid "size of dynamic symbols is not multiple of symbol size"
+msgstr "dynaamisten symbolien koko ei ole symbolikoon monikerta"
+
+#: dynobj.cc:1435
+#, c-format
+msgid "symbol %s has undefined version %s"
+msgstr "symbolilla %s on määrittelemätön versio %s"
+
+#: ehframe.h:82
+msgid "** eh_frame_hdr"
+msgstr "** eh_frame_hdr"
+
+#: ehframe.h:353
+msgid "** eh_frame"
+msgstr "** eh_frame"
+
+#: errors.cc:81
+#, c-format
+msgid "%s: fatal error: "
+msgstr "%s: kohtalokas virhe: "
+
+#: errors.cc:92
+#, c-format
+msgid "%s: error: "
+msgstr "%s: virhe: "
+
+#: errors.cc:104
+#, c-format
+msgid "%s: warning: "
+msgstr "%s: varoitus: "
+
+#: errors.cc:128
+#, c-format
+msgid "%s: %s: error: "
+msgstr "%s: %s: virhe: "
+
+#: errors.cc:144
+#, c-format
+msgid "%s: %s: warning: "
+msgstr "%s: %s: varoitus: "
+
+#: errors.cc:167
+#, c-format
+msgid "%s: %s: error: undefined reference to '%s'\n"
+msgstr "%s: %s: virhe: määrittelemätön viite kohteeseen ’%s’\n"
+
+#: errors.cc:172
+#, c-format
+msgid "%s: %s: error: undefined reference to '%s', version '%s'\n"
+msgstr "%s: %s: virhe: määrittelemätön viite kohteeseen ’%s’, versio ’%s’\n"
+
+#: errors.cc:182
+#, c-format
+msgid "%s: "
+msgstr "%s: "
+
+#: expression.cc:172
+#, c-format
+msgid "undefined symbol '%s' referenced in expression"
+msgstr "määrittelemättömään symboliin ’%s’ viitattu lausekkeessa"
+
+#: expression.cc:209
+msgid "invalid reference to dot symbol outside of SECTIONS clause"
+msgstr "virheellinen viite dot-symboliin SECTIONS-lauseen ulkopuolella"
+
+#. Handle unary operators. We use a preprocessor macro as a hack to
+#. capture the C operator.
+#: expression.cc:278
+msgid "unary "
+msgstr "unaari "
+
+#. 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.
+#: expression.cc:400
+msgid "binary "
+msgstr "binaarinen "
+
+#: expression.cc:404
+msgid " by zero"
+msgstr " nollalla"
+
+#: expression.cc:575
+msgid "max applied to section relative value"
+msgstr "maksimisovellettu lohkosuhteelliseen arvoon"
+
+#: expression.cc:610
+msgid "min applied to section relative value"
+msgstr "minimisovellettu lohkosuhteelliseen arvoon"
+
+#: expression.cc:740
+msgid "aligning to section relative value"
+msgstr "tasaus lohkosuhteelliseen arvoon"
+
+#: expression.cc:895
+#, c-format
+msgid "unknown constant %s"
+msgstr "tuntematon vakio %s"
+
+#: expression.cc:1126
+msgid "SEGMENT_START not implemented"
+msgstr "SEGMENT_START on toteuttamatta"
+
+#: expression.cc:1135
+msgid "ORIGIN not implemented"
+msgstr "ORIGIN on toteuttamatta"
+
+#: expression.cc:1141
+msgid "LENGTH not implemented"
+msgstr "LENGTH on toteuttamatta"
+
+#: fileread.cc:65
+#, c-format
+msgid "munmap failed: %s"
+msgstr "munmap epäonnistui: %s"
+
+#: fileread.cc:129
+#, c-format
+msgid "%s: fstat failed: %s"
+msgstr "%s: fstat epäonnistui: %s"
+
+#: fileread.cc:169
+#, c-format
+msgid "could not reopen file %s"
+msgstr "ei voitu avata uudelleen tiedostoa %s"
+
+#: fileread.cc:302
+#, c-format
+msgid "%s: pread failed: %s"
+msgstr "%s: pread epäonnistui: %s"
+
+#: fileread.cc:308
+#, c-format
+msgid "%s: file too short: read only %lld of %lld bytes at %lld"
+msgstr "%s: tiedosto on liian lyhyt: lue vain %lld / %lld tavua osoitteesta %lld"
+
+#: fileread.cc:372
+#, c-format
+msgid "%s: attempt to map %lld bytes at offset %lld exceeds size of file; the file may be corrupt"
+msgstr "%s: yritys kuvata %lld tavua siirrososoitteessa %lld ylittää tiedoston koon; tiedosto on ehkä rikkinäinen"
+
+#: fileread.cc:402
+#, c-format
+msgid "%s: mmap offset %lld size %lld failed: %s"
+msgstr "%s: mmap siirrososoite %lld koko %lld epäonnistui: %s"
+
+#: fileread.cc:548
+#, c-format
+msgid "%s: lseek failed: %s"
+msgstr "%s: lseek epäonnistui: %s"
+
+#: fileread.cc:554
+#, c-format
+msgid "%s: readv failed: %s"
+msgstr "%s: readv epäonnistui: %s"
+
+#: fileread.cc:557
+#, c-format
+msgid "%s: file too short: read only %zd of %zd bytes at %lld"
+msgstr "%s: tiedosto on liian lyhyt: lue vain %zd / %zd tavua osoitteesta %lld"
+
+#: fileread.cc:706
+#, c-format
+msgid "%s: total bytes mapped for read: %llu\n"
+msgstr "%s: yhteensä tavuja kuvattu lukemista varten: %llu\n"
+
+#: fileread.cc:708
+#, c-format
+msgid "%s: maximum bytes mapped for read at one time: %llu\n"
+msgstr "%s: maksimitavuja kuvattu kertalukemista varten: %llu\n"
+
+#: fileread.cc:791
+#, c-format
+msgid "%s: stat failed: %s"
+msgstr "%s: stat epäonnistui: %s"
+
+#: fileread.cc:849
+#, c-format
+msgid "cannot find %s%s"
+msgstr "ei voi löytää kohdetta %s%s"
+
+#: fileread.cc:880
+#, c-format
+msgid "cannot find %s"
+msgstr "ei voi löytää kohdetta %s"
+
+#: fileread.cc:904
+#, c-format
+msgid "cannot open %s: %s"
+msgstr "ei voi avata kohdetta %s: %s"
+
+#: gold-threads.cc:103
+#, c-format
+msgid "pthead_mutextattr_init failed: %s"
+msgstr "pthead_mutextattr_init epäonnistui: %s"
+
+#: gold-threads.cc:107
+#, c-format
+msgid "pthread_mutextattr_settype failed: %s"
+msgstr "pthread_mutextattr_settype epäonnistui: %s"
+
+#: gold-threads.cc:112
+#, c-format
+msgid "pthread_mutex_init failed: %s"
+msgstr "pthread_mutex_init epäonnistui: %s"
+
+#: gold-threads.cc:116
+#, c-format
+msgid "pthread_mutexattr_destroy failed: %s"
+msgstr "pthread_mutexattr_destroy epäonnistui: %s"
+
+#: gold-threads.cc:123
+#, c-format
+msgid "pthread_mutex_destroy failed: %s"
+msgstr "pthread_mutex_destroy epäonnistui: %s"
+
+#: gold-threads.cc:131 gold-threads.cc:382
+#, c-format
+msgid "pthread_mutex_lock failed: %s"
+msgstr "pthread_mutex_lock epäonnistui: %s"
+
+#: gold-threads.cc:139 gold-threads.cc:394
+#, c-format
+msgid "pthread_mutex_unlock failed: %s"
+msgstr "pthread_mutex_unlock epäonnistui: %s"
+
+#: gold-threads.cc:220
+#, c-format
+msgid "pthread_cond_init failed: %s"
+msgstr "pthread_cond_init epäonnistui: %s"
+
+#: gold-threads.cc:227
+#, c-format
+msgid "pthread_cond_destroy failed: %s"
+msgstr "pthread_cond_destroy epäonnistui: %s"
+
+#: gold-threads.cc:236
+#, c-format
+msgid "pthread_cond_wait failed: %s"
+msgstr "pthread_cond_wait epäonnistui: %s"
+
+#: gold-threads.cc:244
+#, c-format
+msgid "pthread_cond_signal failed: %s"
+msgstr "pthread_cond_signal epäonnistui: %s"
+
+#: gold-threads.cc:252
+#, c-format
+msgid "pthread_cond_broadcast failed: %s"
+msgstr "pthread_cond_broadcast epäonnistui: %s"
+
+#: gold-threads.cc:388
+#, c-format
+msgid "pthread_once failed: %s"
+msgstr "pthread_once epäonnistui: %s"
+
+#: gold.cc:91
+#, c-format
+msgid "%s: internal error in %s, at %s:%d\n"
+msgstr "%s: sisäinen virhe funktiossa %s, tiedostossa %s:%d\n"
+
+#: gold.cc:173
+msgid "no input files"
+msgstr "ei syötetiedostoja"
+
+#: gold.cc:226
+msgid "cannot mix -r with --gc-sections or --icf"
+msgstr "ei voi sekoittaa valitsinta -r valitsimen --gc-sections tai --icf kanssa"
+
+#: gold.cc:407
+#, c-format
+msgid "cannot mix -static with dynamic object %s"
+msgstr "ei voi sekoittaa valitsinta -static dynaamisen objektin %s kanssa"
+
+#: gold.cc:411
+#, c-format
+msgid "cannot mix -r with dynamic object %s"
+msgstr "ei voi sekoittaa valitsinta -r dynaamisen objektin %s kanssa"
+
+#: gold.cc:415
+#, c-format
+msgid "cannot use non-ELF output format with dynamic object %s"
+msgstr "ei voi käyttää ei-ELF-tulostemuotoa dynaamisen objektin %s kanssa"
+
+#: gold.cc:427
+#, c-format
+msgid "cannot mix split-stack '%s' and non-split-stack '%s' when using -r"
+msgstr "ei voida sekoittaa jaettua pinoa ’%s’ ja ei-jaettua pinoa ’%s’ kun käytetään valitsinta -r"
+
+#. FIXME: This needs to specify the location somehow.
+#: i386.cc:232 i386.cc:1669 sparc.cc:234 sparc.cc:2395 x86_64.cc:237
+#: x86_64.cc:1732
+msgid "missing expected TLS relocation"
+msgstr "puuttuu odotettu TLS-sijoitus"
+
+#: i386.cc:944 x86_64.cc:1068
+#, c-format
+msgid "section symbol %u has bad shndx %u"
+msgstr "lohkosymbolilla %u on virheellinen shndx-lohko %u"
+
+#: i386.cc:1036 i386.cc:1060 sparc.cc:1777 x86_64.cc:1176 x86_64.cc:1204
+#, c-format
+msgid "local symbol %u has bad shndx %u"
+msgstr "paikallisella symbolilla %u on virheellinen shndx-lohko %u"
+
+#: i386.cc:1991
+msgid "both SUN and GNU model TLS relocations"
+msgstr "sekä SUN- että GNU-mallisia TLS-sijoituksia"
+
+#: i386.cc:2730 x86_64.cc:2719
+#, c-format
+msgid "failed to match split-stack sequence at section %u offset %0zx"
+msgstr "jaetun pinon täsmääminen epäonnistui lohkossa %u siirros %0zx"
+
+#: icf.cc:616
+#, c-format
+msgid "%s: ICF Converged after %u iteration(s)"
+msgstr "%s: ICF lähentyi %u iteroinnin jälkeen"
+
+#: icf.cc:619
+#, c-format
+msgid "%s: ICF stopped after %u iteration(s)"
+msgstr "%s: ICF pysähtyi %u iteroinnin jälkeen"
+
+#: icf.cc:633
+#, c-format
+msgid "Could not find symbol %s to unfold\n"
+msgstr "Ei voitu löytää symbolia %s paljastettavaksi\n"
+
+#: incremental.cc:242
+#, c-format
+msgid "the link might take longer: cannot perform incremental link: %s"
+msgstr "linkki ei ehkä enää toimi: ei voida suorittaa askelkasvatuslinkitystä: %s"
+
+#: incremental.cc:302
+msgid "no incremental data from previous build"
+msgstr "ei askelkasvatusdataa edellisestä rakentamisesta"
+
+#: incremental.cc:309 incremental.cc:332
+msgid "invalid incremental build data"
+msgstr "virheellinen askelkasvatusrakentamisdata"
+
+#: incremental.cc:321
+msgid "different version of incremental build data"
+msgstr "askelkasvatusrakentamisdatan eri versio"
+
+#: incremental.cc:338
+msgid "command line changed"
+msgstr "komentorivi vaihtunut"
+
+#: incremental.cc:362
+#, c-format
+msgid "unsupported ELF machine number %d"
+msgstr "tukematon ELF-konenumero %d"
+
+#: incremental.cc:387
+msgid "output is not an ELF file."
+msgstr "tuloste ei ole ELF-tiedosto."
+
+#: incremental.cc:410
+msgid "unsupported file: 32-bit, big-endian"
+msgstr "tukematon tiedosto: 32-bittinen, big-endian"
+
+#: incremental.cc:419
+msgid "unsupported file: 32-bit, little-endian"
+msgstr "tukematon tiedosto: 32-bittinen, little-endian"
+
+#: incremental.cc:431
+msgid "unsupported file: 64-bit, big-endian"
+msgstr "tukematon tiedosto: 64-bittinen, big-endian"
+
+#: incremental.cc:440
+msgid "unsupported file: 64-bit, little-endian"
+msgstr "tukematon tiedosto: 64-bittinen, little-endian"
+
+#: layout.cc:1887
+#, c-format
+msgid "--build-id=uuid failed: could not open /dev/urandom: %s"
+msgstr "--build-id=uuid epäonnistui: ei voitu avata merkkierikoistiedostoa /dev/urandom: %s"
+
+#: layout.cc:1894
+#, c-format
+msgid "/dev/urandom: read failed: %s"
+msgstr "/dev/urandom: lukeminen epäonnistui: %s"
+
+#: layout.cc:1896
+#, c-format
+msgid "/dev/urandom: expected %zu bytes, got %zd bytes"
+msgstr "/dev/urandom: odotettiin %zu tavua, saatiin %zd tavua"
+
+#: layout.cc:1918
+#, c-format
+msgid "--build-id argument '%s' not a valid hex number"
+msgstr "--build-id argumentti ’%s’ ei ole oikea heksadesimaalinumero"
+
+#: layout.cc:1924
+#, c-format
+msgid "unrecognized --build-id argument '%s'"
+msgstr "tunnistamaton --build-id argumentti ’%s’"
+
+#: layout.cc:2337
+#, c-format
+msgid "load segment overlap [0x%llx -> 0x%llx] and [0x%llx -> 0x%llx]"
+msgstr "lataa segmenttilimitys [0x%llx -> 0x%llx] ja [0x%llx -> 0x%llx]"
+
+#: mapfile.cc:70
+#, c-format
+msgid "cannot open map file %s: %s"
+msgstr "ei voi avata kuvaustiedostoa %s: %s"
+
+#: mapfile.cc:84
+#, c-format
+msgid "cannot close map file: %s"
+msgstr "ei voi sulkea kuvaustiedostoa: %s"
+
+#: mapfile.cc:116
+#, c-format
+msgid ""
+"Archive member included because of file (symbol)\n"
+"\n"
+msgstr ""
+"Arkistojäsen sisällytetty tiedoston (symboli) vuoksi\n"
+"\n"
+
+#: mapfile.cc:159
+#, c-format
+msgid ""
+"\n"
+"Allocating common symbols\n"
+msgstr ""
+"\n"
+"Varataan yhteissymbolit\n"
+
+#: mapfile.cc:161
+#, c-format
+msgid ""
+"Common symbol size file\n"
+"\n"
+msgstr ""
+"Yhteissymboli koko tiedosto\n"
+"\n"
+
+#: mapfile.cc:195
+#, c-format
+msgid ""
+"\n"
+"Memory map\n"
+"\n"
+msgstr ""
+"\n"
+"Muistikuvaus\n"
+"\n"
+
+#: mapfile.cc:361
+#, c-format
+msgid ""
+"\n"
+"Discarded input sections\n"
+"\n"
+msgstr ""
+"\n"
+"Hylätyt syötelohkot\n"
+"\n"
+
+#: merge.cc:455
+#, c-format
+msgid "%s: %s merged constants size: %lu; input: %zu; output: %zu\n"
+msgstr "%s: %s yhdistetty vakioiden koko: %lu; syöte: %zu; tuloste: %zu\n"
+
+#: merge.cc:478
+msgid "mergeable string section length not multiple of character size"
+msgstr "yhdistettävän merkkijonolohkon pituus ei ole merkkikoon monikerta"
+
+#: merge.cc:494
+#, c-format
+msgid "%s: last entry in mergeable string section '%s' not null terminated"
+msgstr "%s: viimeinen alkio yhdistettävässä merkkijonolohkossa ’%s’ ei ole null-päätteinen"
+
+#: merge.cc:613
+#, c-format
+msgid "%s: %s input: %zu\n"
+msgstr "%s: %s syöte: %zu\n"
+
+#: merge.h:300
+msgid "** merge constants"
+msgstr "** yhdistä vakiot"
+
+#: merge.h:422
+msgid "** merge strings"
+msgstr "** yhdistä merkkijonot"
+
+#: object.cc:75
+msgid "missing SHT_SYMTAB_SHNDX section"
+msgstr "puuttuva SHT_SYMTAB_SHNDX-lohko"
+
+#: object.cc:119
+#, c-format
+msgid "symbol %u out of range for SHT_SYMTAB_SHNDX section"
+msgstr "symboli %u lukualueen ulkopuolella lohkolle SHT_SYMTAB_SHNDX"
+
+#: object.cc:126
+#, c-format
+msgid "extended index for symbol %u out of range: %u"
+msgstr "laajennettu hakemisto symbolille %u lukualueen ulkopuolella: %u"
+
+#: object.cc:148 object.cc:2331 output.cc:4052
+#, c-format
+msgid "%s: %s"
+msgstr "%s: %s"
+
+#: object.cc:190
+#, c-format
+msgid "section name section has wrong type: %u"
+msgstr "lohkonimilohko on väärän tyyppinen: %u"
+
+#: object.cc:546
+#, c-format
+msgid "invalid symbol table name index: %u"
+msgstr "virheellinen symbolitaulunimi-indeksi: %u"
+
+#: object.cc:552
+#, c-format
+msgid "symbol table name section has wrong type: %u"
+msgstr "symbolitaulunimilohko on väärän tyyppinen: %u"
+
+#: object.cc:641
+#, c-format
+msgid "section group %u info %u out of range"
+msgstr "lohkoryhmä %u tiedot %u lukualueen ulkopuolella"
+
+#: object.cc:660
+#, c-format
+msgid "symbol %u name offset %u out of range"
+msgstr "symbolin %u nimisiirros %u lukualueen ulkopuolella"
+
+#: object.cc:678
+#, c-format
+msgid "symbol %u invalid section index %u"
+msgstr "symboli %u virheellinen lohkoindeksi %u"
+
+#: object.cc:723
+#, c-format
+msgid "section %u in section group %u out of range"
+msgstr "lohko %u lohkoryhmässä %u lukualueen ulkopuolella"
+
+#: object.cc:731
+#, c-format
+msgid "invalid section group %u refers to earlier section %u"
+msgstr "virheellinen lohkoryhmä %u viittaa aikaisempaan lohkoon %u"
+
+#: object.cc:1037 reloc.cc:271 reloc.cc:838
+#, c-format
+msgid "relocation section %u has bad info %u"
+msgstr "sijoituslohkolla %u on väärät tiedot %u"
+
+#: object.cc:1231
+#, c-format
+msgid "%s: removing unused section from '%s' in file '%s'"
+msgstr "%s: poistetaan käyttämättömät lohkot kohteesta ’%s’ tiedostossa ’%s’"
+
+#: object.cc:1257
+#, c-format
+msgid "%s: ICF folding section '%s' in file '%s'into '%s' in file '%s'"
+msgstr "%s: ICF-laskostumislohko ’%s’ tiedostossa ’%s’ kohteeseen ’%s’ tiedostossa ’%s’"
+
+#: object.cc:1454
+msgid "size of symbols is not multiple of symbol size"
+msgstr "symboleiden koko ei ole symbolikoon monikerta"
+
+#: object.cc:1563
+#, c-format
+msgid "local symbol %u section name out of range: %u >= %u"
+msgstr "paikallisen symbolin %u lohkonimi lukualueen ulkopuolella: %u >= %u"
+
+#: object.cc:1652
+#, c-format
+msgid "unknown section index %u for local symbol %u"
+msgstr "tuntematon lohkoindeksi %u paikalliselle symbolille %u"
+
+#: object.cc:1661
+#, c-format
+msgid "local symbol %u section index %u out of range"
+msgstr "paikallisen symbolin %u lohkoindeksi %u lukualueen ulkopuolella"
+
+#: object.cc:2169
+#, c-format
+msgid "%s is not supported but is required for %s in %s"
+msgstr "%s ei ole tuettu, mutta vaaditaan kohteelle %s kohteessa %s"
+
+#: object.cc:2273
+#, c-format
+msgid "%s: unsupported ELF machine number %d"
+msgstr "%s: tukematon ELF-konenumero %d"
+
+#: object.cc:2283
+#, c-format
+msgid "%s: incompatible target"
+msgstr "%s: yhteensopimaton kohde"
+
+#: object.cc:2347 plugin.cc:1019
+#, c-format
+msgid "%s: not configured to support 32-bit big-endian object"
+msgstr "%s: ei ole asetettu tukemaan 32-bittistä big-endian-objektia"
+
+#: object.cc:2363 plugin.cc:1028
+#, c-format
+msgid "%s: not configured to support 32-bit little-endian object"
+msgstr "%s: ei ole asetettu tukemaan 32-bittistä little-endian-objektia"
+
+#: object.cc:2382 plugin.cc:1040
+#, c-format
+msgid "%s: not configured to support 64-bit big-endian object"
+msgstr "%s: ei ole asetettu tukemaan 64-bittistä big-endian-objektia"
+
+#: object.cc:2398 plugin.cc:1049
+#, c-format
+msgid "%s: not configured to support 64-bit little-endian object"
+msgstr "%s: ei ole asetettu tukemaan 64-bittistä little-endian-objektia"
+
+#: options.cc:156
+#, c-format
+msgid ""
+"Usage: %s [options] file...\n"
+"Options:\n"
+msgstr ""
+"Käyttö: %s [valitsimet] tiedosto...\n"
+"Valitsimet:\n"
+
+#. config.guess and libtool.m4 look in ld --help output for the
+#. string "supported targets".
+#: options.cc:164
+#, c-format
+msgid "%s: supported targets:"
+msgstr "%s: tuetut kohteet:"
+
+#: options.cc:176
+#, c-format
+msgid "Report bugs to %s\n"
+msgstr ""
+"Ilmoita virheistä (englanniksi) osoitteeseen %s\n"
+"Ilmoita suomennosvirheistä osoitteeseen <translation-team-fi@lists.sourceforge.net>\n"
+
+#: options.cc:193 options.cc:203 options.cc:213
+#, c-format
+msgid "%s: invalid option value (expected an integer): %s"
+msgstr "%s: virheellinen valitsinarvo (odotettiin kokonaislukua): %s"
+
+#: options.cc:223
+#, c-format
+msgid "%s: invalid option value (expected a floating point number): %s"
+msgstr "%s: virheellinen valitsinarvo (odotettiin liukulukunumeroa): %s"
+
+#: options.cc:232
+#, c-format
+msgid "%s: must take a non-empty argument"
+msgstr "%s: täytyy olla ei-tyhjä argumentti"
+
+#: options.cc:273
+#, c-format
+msgid "%s: must take one of the following arguments: %s"
+msgstr "%s: täytyy olla yksi seuraavista argumenteista: %s"
+
+#: options.cc:300
+#, c-format
+msgid " Supported targets:\n"
+msgstr " Tuetut kohteet:\n"
+
+#: options.cc:409
+#, c-format
+msgid "unable to parse script file %s"
+msgstr "ei kyetä jäsentämään skriptitiedostoa %s"
+
+#: options.cc:417
+#, c-format
+msgid "unable to parse version script file %s"
+msgstr "ei kyetä jäsentämään versioskriptitiedostoa %s"
+
+#: options.cc:425
+#, c-format
+msgid "unable to parse dynamic-list script file %s"
+msgstr "ei kyetä jäsentämään dynaamisluetteloista skriptitiedostoa %s"
+
+#: options.cc:522
+#, c-format
+msgid "format '%s' not supported; treating as elf (supported formats: elf, binary)"
+msgstr "muotoa ’%s’ ei tueta; käsitellään elf-objektina (tuetut muodot: elf, binaari)"
+
+#: options.cc:538
+#, c-format
+msgid "%s: use the --help option for usage information\n"
+msgstr "%s: käytä valitsinta --help käyttötietojen saamiseksi\n"
+
+#: options.cc:547
+#, c-format
+msgid "%s: %s: %s\n"
+msgstr "%s: %s: %s\n"
+
+#: options.cc:651
+msgid "unexpected argument"
+msgstr "odottamaton argumentti"
+
+#: options.cc:664 options.cc:725
+msgid "missing argument"
+msgstr "puuttuva argumentti"
+
+#: options.cc:736
+msgid "unknown -z option"
+msgstr "tuntematon valitsin -z"
+
+#: options.cc:935
+#, c-format
+msgid "ignoring --threads: %s was compiled without thread support"
+msgstr "ei oteta huomioon valitsinta --threads: %s käännettiin ilman säietukea"
+
+#: options.cc:942
+#, c-format
+msgid "ignoring --thread-count: %s was compiled without thread support"
+msgstr "ohitetaan --thread-count: %s käännettiin ilman säietukea"
+
+#: options.cc:981
+#, c-format
+msgid "unable to open -retain-symbols-file file %s: %s"
+msgstr "ei kyetä avaamaan -retain-symbols-file -tiedostoa %s: %s"
+
+#: options.cc:1003
+msgid "-shared and -static are incompatible"
+msgstr "valitsimet -shared ja -static ovat yhteensopimattomat"
+
+#: options.cc:1005
+msgid "-shared and -pie are incompatible"
+msgstr "valitsimet -shared ja -pie ovat yhteensopimattomat"
+
+#: options.cc:1008
+msgid "-shared and -r are incompatible"
+msgstr "valitsimet -shared ja -r ovat yhteensopimattomat"
+
+#: options.cc:1010
+msgid "-pie and -r are incompatible"
+msgstr "valitsimet -pie ja -r ovat yhteensopimattomat"
+
+#: options.cc:1014
+msgid "-retain-symbols-file does not yet work with -r"
+msgstr "-retain-symbols-file ei vielä toimi valitsimen -r kanssa"
+
+#: options.cc:1020
+msgid "binary output format not compatible with -shared or -pie or -r"
+msgstr "binaaritulostemuoto ei ole yhteensopiva valitsimien -shared, -pie tai -r kanssa"
+
+#: options.cc:1026
+#, c-format
+msgid "--hash-bucket-empty-fraction value %g out of range [0.0, 1.0)"
+msgstr "--hash-bucket-empty-fraction arvo %g lukualueen ulkopuolella [0.0, 1.0)"
+
+#: options.cc:1031
+msgid "Options --incremental-changed, --incremental-unchanged, --incremental-unknown require the use of --incremental"
+msgstr "Valitsimet --incremental-changed, --incremental-unchanged, --incremental-unknown vaativat valitsimen --incremental käytön"
+
+#: options.cc:1097
+msgid "May not nest groups"
+msgstr "Ei saa sisäkkäistää ryhmiä"
+
+#: options.cc:1109
+msgid "Group end without group start"
+msgstr "Ryhmäloppu ilman ryhmäalkua"
+
+#. I guess it's neither a long option nor a short option.
+#: options.cc:1174
+msgid "unknown option"
+msgstr "tuntematon valitsin"
+
+#: options.cc:1201
+#, c-format
+msgid "%s: missing group end\n"
+msgstr "%s: puuttuva ryhmäloppu\n"
+
+#: options.h:571
+msgid "Report usage information"
+msgstr "Ilmoita käyttötiedot"
+
+#: options.h:573
+msgid "Report version information"
+msgstr "Ilmoita versiotiedot"
+
+#: options.h:575
+msgid "Report version and target information"
+msgstr "Ilmoita versio- ja kohdetiedot"
+
+#: options.h:584 options.h:635
+msgid "Not supported"
+msgstr "Ei tuettu"
+
+#: options.h:585 options.h:636
+msgid "Do not copy DT_NEEDED tags from shared libraries"
+msgstr "Älä kopioi DT_NEEDED-tunnisteita jaettuihin kirjastoihin"
+
+#: options.h:588
+msgid "Allow unresolved references in shared libraries"
+msgstr "Salli ratkaisemattomat viitteet jaettuihin kirjastoihin"
+
+#: options.h:589
+msgid "Do not allow unresolved references in shared libraries"
+msgstr "Älä salli ratkaisemattomia viitteitä jaettuihin kirjastoihin"
+
+#: options.h:592
+msgid "Only set DT_NEEDED for shared libraries if used"
+msgstr "Aseta DT_NEEDED jaetuille kirjastoille vain jos käytetty"
+
+#: options.h:593
+msgid "Always DT_NEEDED for shared libraries"
+msgstr "Aina DT_NEEDED jaetuille kirjastoille"
+
+#: options.h:600
+msgid "Set input format"
+msgstr "Aseta syötemuoto"
+
+#: options.h:603
+msgid "-l searches for shared libraries"
+msgstr "-l etsii jaettuja kirjastoja"
+
+#: options.h:605
+msgid "-l does not search for shared libraries"
+msgstr "-l ei etsi jaettuja kirjastoja"
+
+#: options.h:609
+msgid "Bind defined symbols locally"
+msgstr "Sido määritellyt symbolit paikallisesti"
+
+#: options.h:612
+msgid "Bind defined function symbols locally"
+msgstr "Sido määritellyt funktiosymbolit paikallisesti"
+
+#: options.h:615
+msgid "Generate build ID note"
+msgstr "Tuota rakentamistunnisteilmoitus"
+
+#: options.h:616 options.h:655
+msgid "[=STYLE]"
+msgstr "[=TYYLI]"
+
+#: options.h:619
+msgid "Check segment addresses for overlaps (default)"
+msgstr "Tarkista segmenttiosoitteet päällekkäisyyksien varalta (oletus)"
+
+#: options.h:620
+msgid "Do not check segment addresses for overlaps"
+msgstr "Älä tarkista segmenttiosoitteiden päällekkäisyyksiä"
+
+#: options.h:624 options.h:629
+msgid "Compress .debug_* sections in the output file"
+msgstr "Tiivistä .debug_* -lohkot tulostetiedostossa"
+
+#: options.h:630
+msgid "[none]"
+msgstr "[ei mitään]"
+
+#: options.h:639
+msgid "Define common symbols"
+msgstr "Anna yhteissymbolit"
+
+#: options.h:640
+msgid "Do not define common symbols"
+msgstr "Älä anna yhteissymboleja"
+
+#: options.h:642 options.h:644
+msgid "Alias for -d"
+msgstr "Alias valitsimelle -d"
+
+#: options.h:647
+msgid "Turn on debugging"
+msgstr "Käännä päälle vianjäljitys"
+
+#: options.h:648
+msgid "[all,files,script,task][,...]"
+msgstr "[kaikki,tiedostot,skripti,tehtävä][,...]"
+
+#: options.h:651
+msgid "Define a symbol"
+msgstr "Määrittele symboli"
+
+#: options.h:651
+msgid "SYMBOL=EXPRESSION"
+msgstr "SYMBOLI=LAUSEKE"
+
+#: options.h:654
+msgid "Demangle C++ symbols in log messages"
+msgstr "Elvytä C++ -symbolit lokiviesteissä"
+
+#: options.h:658
+msgid "Do not demangle C++ symbols in log messages"
+msgstr "Älä elvytä C++ -symboleja lokiviesteissä"
+
+#: options.h:662
+msgid "Try to detect violations of the One Definition Rule"
+msgstr "Yritä havaita yhden määrittelysäännön rikkomukset"
+
+#: options.h:666
+msgid "Delete all temporary local symbols"
+msgstr "Poista kaikki tilapäiset paikalliset symbolit"
+
+#: options.h:669
+msgid "Add data symbols to dynamic symbols"
+msgstr "Lisää datasymbolit dynaamisiin symboleihin"
+
+#: options.h:672
+msgid "Add C++ operator new/delete to dynamic symbols"
+msgstr "Lisää C++-operaattori new/delete dynaamisiin symboleihin"
+
+#: options.h:675
+msgid "Add C++ typeinfo to dynamic symbols"
+msgstr "Lisää C++-typeinfo dynaamisiin symboleihin"
+
+#: options.h:678
+msgid "Read a list of dynamic symbols"
+msgstr "Lue dynaamisten symbolien luettelo"
+
+#: options.h:678 options.h:732 options.h:766 options.h:893 options.h:921
+msgid "FILE"
+msgstr "TIEDOSTO"
+
+#: options.h:681
+msgid "Set program start address"
+msgstr "Aseta ohjelman aloitusosoite"
+
+#: options.h:681 options.h:908 options.h:910 options.h:912
+msgid "ADDRESS"
+msgstr "OSOITE"
+
+#: options.h:684
+msgid "Exclude libraries from automatic export"
+msgstr "Jätä kirjastot pois automaattisesta viennistä"
+
+#: options.h:688
+msgid "Export all dynamic symbols"
+msgstr "Vie kaikki dynaamiset symbolit"
+
+#: options.h:689
+msgid "Do not export all dynamic symbols (default)"
+msgstr "Älä vie kaikkia dynaamisia symboleita (oletus)"
+
+#: options.h:692
+msgid "Create exception frame header"
+msgstr "Luo poikkeuskehysotsake"
+
+#: options.h:695
+msgid "Treat warnings as errors"
+msgstr "Käsittele varoituksia virheinä"
+
+#: options.h:696
+msgid "Do not treat warnings as errors"
+msgstr "Älä käsittele varoituksia virheinä"
+
+#: options.h:699
+msgid "Call SYMBOL at unload-time"
+msgstr "Kutsu SYMBOLIa sulkemishetkellä"
+
+#: options.h:699 options.h:729 options.h:873 options.h:915 options.h:936
+#: options.h:939
+msgid "SYMBOL"
+msgstr "SYMBOLI"
+
+#: options.h:702
+msgid "Set shared library name"
+msgstr "Aseta jaettu kirjastonimi"
+
+#: options.h:702 options.h:792
+msgid "FILENAME"
+msgstr "TIEDOSTONIMI"
+
+#: options.h:705
+msgid "Min fraction of empty buckets in dynamic hash"
+msgstr "Tyhjien lohkojen pienin murto-osa dynaamisessa hash-funktiossa"
+
+#: options.h:706
+msgid "FRACTION"
+msgstr "MURTO-OSA"
+
+#: options.h:709
+msgid "Dynamic hash style"
+msgstr "Dynaaminen hash-tyyli"
+
+#: options.h:709
+msgid "[sysv,gnu,both]"
+msgstr "[sysv,gnu,both]"
+
+#: options.h:713
+msgid "Set dynamic linker path"
+msgstr "Aseta dynaaminen linkittäjäpolku"
+
+#: options.h:713
+msgid "PROGRAM"
+msgstr "OHJELMA"
+
+#: options.h:716
+msgid "Work in progress; do not use"
+msgstr "Työ käynnissä; älä käytä"
+
+#: options.h:717
+msgid "Do a full build"
+msgstr "Tee täysi rakentaminen"
+
+#: options.h:720
+msgid "Assume files changed"
+msgstr "Otaksu tiedostojen muuttuneen"
+
+#: options.h:723
+msgid "Assume files didn't change"
+msgstr "Otaksu, että tiedostot eivät ole muuttuneet"
+
+#: options.h:726
+msgid "Use timestamps to check files (default)"
+msgstr "Käytä aikaleimoja tiedostojen tarkistamiseen (oletus)"
+
+#: options.h:729
+msgid "Call SYMBOL at load-time"
+msgstr "Kutsu SYMBOLIa latausaikana"
+
+#: options.h:732
+msgid "Read only symbol values from FILE"
+msgstr "Lue vain symboliarvot TIEDOSTOsta"
+
+#: options.h:735
+msgid "Search for library LIBNAME"
+msgstr "Haku kirjastolle LIBNAME"
+
+#: options.h:735
+msgid "LIBNAME"
+msgstr "LIBNAME"
+
+#: options.h:738
+msgid "Add directory to search path"
+msgstr "Lisää hakemisto hakupolkuun"
+
+#: options.h:738 options.h:813 options.h:816 options.h:820 options.h:887
+msgid "DIR"
+msgstr "DIR"
+
+#: options.h:741
+msgid "Ignored for compatibility"
+msgstr "Ei oteta huomioon yhteensopivuussyistä"
+
+#: options.h:741
+msgid "EMULATION"
+msgstr "EMULOINTI"
+
+#: options.h:744
+msgid "Write map file on standard output"
+msgstr "Kirjoita kuvaustiedosto vakiotulosteeseen"
+
+#: options.h:745
+msgid "Write map file"
+msgstr "Kirjoita kuvaustiedosto"
+
+#: options.h:746
+msgid "MAPFILENAME"
+msgstr "KUVAUSTIEDOSTONIMI"
+
+#: options.h:749
+msgid "Do not page align data"
+msgstr "Älä tasaa dataa sivun kokoisiin osiin"
+
+#: options.h:751
+msgid "Do not page align data, do not make text readonly"
+msgstr "Älä tasaa dataa sivun kokoisiin osiin, älä kirjoitussuojaa tekstiä"
+
+#: options.h:752
+msgid "Page align data, make text readonly"
+msgstr "Sivutasausdataa, tee tekstistä kirjoitussuojattu"
+
+#: options.h:755
+msgid "Enable use of DT_RUNPATH and DT_FLAGS"
+msgstr "Ota käyttöön DT_RUNPATH-hakemistot ja DT_FLAGS-liput"
+
+#: options.h:756
+msgid "Disable use of DT_RUNPATH and DT_FLAGS"
+msgstr "Ota pois käytöstä DT_RUNPATH-hakemistot ja DT_FLAGS-liput"
+
+#: options.h:759
+msgid "Create an output file even if errors occur"
+msgstr "Luo tulostetiedosto myös silloin kun tapahtuu virhe"
+
+#: options.h:762 options.h:958
+msgid "Report undefined symbols (even with --shared)"
+msgstr "Ilmoita määrittelemättömistä symboleista (jopa valitsimella --shared)"
+
+#: options.h:766
+msgid "Set output file name"
+msgstr "Aseta tulostetiedostonimi"
+
+#: options.h:769
+msgid "Optimize output file size"
+msgstr "Optimoi tulostetiedostokoko"
+
+#: options.h:769
+msgid "LEVEL"
+msgstr "TASO"
+
+#: options.h:772
+msgid "Set output format"
+msgstr "Aseta tulostusmuoto"
+
+#: options.h:772
+msgid "[binary]"
+msgstr "[binaari]"
+
+#: options.h:775 options.h:777
+msgid "Create a position independent executable"
+msgstr "Luo paikkariippumaton suoritettava tiedosto"
+
+#: options.h:782
+msgid "Load a plugin library"
+msgstr "Lataa lisäosakirjasto"
+
+#: options.h:782
+msgid "PLUGIN"
+msgstr "LISÄOSA"
+
+#: options.h:784
+msgid "Pass an option to the plugin"
+msgstr "Välitä valitsin lisäosalle"
+
+#: options.h:784
+msgid "OPTION"
+msgstr "VALITSIN"
+
+#: options.h:788
+msgid "Preread archive symbols when multi-threaded"
+msgstr "Ennakkoluetut arkistosymbolit monisäikeitä käytettäessä"
+
+#: options.h:791
+msgid "Print symbols defined and used for each input"
+msgstr "Tulosta jokaiselle syötteelle määritellyt ja käytetyt symbolit"
+
+#: options.h:795
+msgid "Ignored for SVR4 compatibility"
+msgstr "Älä ota huomioon SVR4-yhteensopivuutta"
+
+#: options.h:798
+msgid "Generate relocations in output"
+msgstr "Tuota sijoitukset tulosteeseen"
+
+#: options.h:801
+msgid "Generate relocatable output"
+msgstr "Tuota sijoitettava tuloste"
+
+#: options.h:804
+msgid "Relax branches on certain targets"
+msgstr "Relax-projektin haarat tietyissä kohteissa"
+
+#: options.h:807
+msgid "keep only symbols listed in this file"
+msgstr "pidä vain tässä tiedostossa luetellut symbolit"
+
+#: options.h:807
+msgid "[file]"
+msgstr "[tiedosto]"
+
+#: options.h:813 options.h:816
+msgid "Add DIR to runtime search path"
+msgstr "Lisää DIR ajoaikaiseen hakupolkuun"
+
+#: options.h:819
+msgid "Add DIR to link time shared library search path"
+msgstr "Lisää DIR linkitysaikana jaettuun kirjastohakupolkuun"
+
+#: options.h:823
+msgid "Strip all symbols"
+msgstr "Riisu kaikki symbolit"
+
+#: options.h:825
+msgid "Strip debugging information"
+msgstr "Riisu vianjäljitystiedot"
+
+#: options.h:827
+msgid "Emit only debug line number information"
+msgstr "Lähetä vain vianjäljitysrivinumerotiedot"
+
+#: options.h:829
+msgid "Strip debug symbols that are unused by gdb (at least versions <= 6.7)"
+msgstr "Riisu vianjäljityssymbolit, joita gdb ei käytä (vähintään versioissa <= 6.7)"
+
+#: options.h:832
+msgid "Strip LTO intermediate code sections"
+msgstr "Riisu LTO-keskikoodilohkot"
+
+#: options.h:835
+msgid "(ARM only) The maximum distance from instructions in a group of sections to their stubs. Negative values mean stubs are always after the group. 1 means using default size.\n"
+msgstr "(vain ARM) Käskyjen enimmäisetäisyys niiden stub-koodeihin lohkojen ryhmässä. Negatiiviset arvot tarkoittavat, että stub-koodit ovat ryhmän jäljessä. 1 tarkoittaa oletuskokoa.\n"
+
+#: options.h:838 options.h:852 options.h:956 options.h:975
+msgid "SIZE"
+msgstr "KOKO"
+
+#: options.h:841
+msgid "Use less memory and more disk I/O (included only for compatibility with GNU ld)"
+msgstr "Käytä vähemmän muistia ja enemmän levysiirräntää (sisällytetty GNU ld -yhteensopivuussyistä)"
+
+#: options.h:845 options.h:848
+msgid "Generate shared library"
+msgstr "Tuota jaettu kirjasto"
+
+#: options.h:851
+msgid "Stack size when -fsplit-stack function calls non-split"
+msgstr "Pinokoko kun -fsplit-stack -funktio kutsuu non-split -pinoa"
+
+#: options.h:857
+msgid "Do not link against shared libraries"
+msgstr "Älä linkitä jaettuihin kirjastoihin"
+
+#: options.h:860
+msgid "Identical Code Folding. '--icf=safe' folds only ctors and dtors."
+msgstr "Identtinen koodilaskostuminen. ’--icf=safe’ laskostaa vain kohteet ctors ja dtors."
+
+#: options.h:866
+msgid "Number of iterations of ICF (default 2)"
+msgstr "ICF-iterointien lukumäärä (oletus 2)"
+
+#: options.h:866 options.h:899 options.h:901 options.h:903 options.h:905
+msgid "COUNT"
+msgstr "LASKURI"
+
+#: options.h:869
+msgid "List folded identical sections on stderr"
+msgstr "Luettele laskostetut identtiset lohkot vakiovirheessä"
+
+#: options.h:870
+msgid "Do not list folded identical sections"
+msgstr "Älä luettele laskostettuja identtisiä lohkoja"
+
+#: options.h:873
+msgid "Do not fold this symbol during ICF"
+msgstr "Älä laskosta tätä symbolia ICF:n aikana"
+
+#: options.h:876
+msgid "Remove unused sections"
+msgstr "Poista käyttämättömät lohkot"
+
+#: options.h:877
+msgid "Don't remove unused sections (default)"
+msgstr "Älä poista käyttämättömiä lohkoja (oletus)"
+
+#: options.h:880
+msgid "List removed unused sections on stderr"
+msgstr "Luettele poistetut käyttämättömät lohkot vakiovirheessä"
+
+#: options.h:881
+msgid "Do not list removed unused sections"
+msgstr "Älä luettele poistettuja käyttämättömiä lohkoja"
+
+#: options.h:884
+msgid "Print resource usage statistics"
+msgstr "Tulosta resurssikäyttötilastot"
+
+#: options.h:887
+msgid "Set target system root directory"
+msgstr "Aseta kohdejärjestelmän juurihakemisto"
+
+#: options.h:890
+msgid "Print the name of each input file"
+msgstr "Tulosta jokaisen syötetiedoston nimi"
+
+#: options.h:893
+msgid "Read linker script"
+msgstr "Lue linkkeriskripti"
+
+#: options.h:896
+msgid "Run the linker multi-threaded"
+msgstr "Suorita linkkeri monisäikeisesti"
+
+#: options.h:897
+msgid "Do not run the linker multi-threaded"
+msgstr "Älä suorita linkkeriä monisäikeisesti"
+
+#: options.h:899
+msgid "Number of threads to use"
+msgstr "Käytettävien säikeiden lukumäärä"
+
+#: options.h:901
+msgid "Number of threads to use in initial pass"
+msgstr "Alustavassa ajossa käytettyjen säikeiden lukumäärä"
+
+#: options.h:903
+msgid "Number of threads to use in middle pass"
+msgstr "Keskimmäisessä ajossa käytettyjen säikeiden lukumäärä"
+
+#: options.h:905
+msgid "Number of threads to use in final pass"
+msgstr "Lopullisessa ajossa käytettyjen säikeiden lukumäärä"
+
+#: options.h:908
+msgid "Set the address of the bss segment"
+msgstr "Aseta bss-lohkon osoite"
+
+#: options.h:910
+msgid "Set the address of the data segment"
+msgstr "Aseta data-segmentin osoite"
+
+#: options.h:912
+msgid "Set the address of the text segment"
+msgstr "Aseta text-segmentin osoite"
+
+#: options.h:915
+msgid "Create undefined reference to SYMBOL"
+msgstr "Luo määrittelemätön viite SYMBOLIin"
+
+#: options.h:918
+msgid "Synonym for --debug=files"
+msgstr "Synonyymi valitsimelle --debug=tiedostot"
+
+#: options.h:921
+msgid "Read version script"
+msgstr "Lue versioskripti"
+
+#: options.h:924
+msgid "Warn about duplicate common symbols"
+msgstr "Varoita yhteissymbolien kaksoiskappaleista"
+
+#: options.h:925
+msgid "Do not warn about duplicate common symbols (default)"
+msgstr "Älä varoita yhteissymbolien kaksoiskappaleista (oletus)"
+
+#: options.h:928
+msgid "Warn when skipping an incompatible library"
+msgstr "Varoita, kun ohitetaan yhteensopimaton kirjasto"
+
+#: options.h:929
+msgid "Don't warn when skipping an incompatible library"
+msgstr "Älä varoita, kun ohitetaan yhteensopimaton kirjasto"
+
+#: options.h:932
+msgid "Include all archive contents"
+msgstr "Sisällytä kaikki arkistosisällöt"
+
+#: options.h:933
+msgid "Include only needed archive contents"
+msgstr "Sisällytä vain tarvitut arkistosisällöt"
+
+#: options.h:936
+msgid "Use wrapper functions for SYMBOL"
+msgstr "Käytä käärinfunktioita symbolille SYMBOLI"
+
+#: options.h:939
+msgid "Trace references to symbol"
+msgstr "Jäljitä viitteet symboliin"
+
+#: options.h:942
+msgid "Default search path for Solaris compatibility"
+msgstr "Oletushakupolku Solaris-yhteensopivuutta varten"
+
+#: options.h:943
+msgid "PATH"
+msgstr "POLKU"
+
+#: options.h:946
+msgid "Start a library search group"
+msgstr "Aloita kirjastonetsimisryhmä"
+
+#: options.h:948
+msgid "End a library search group"
+msgstr "Lopeta kirjastonetsimisryhmä"
+
+#: options.h:953
+msgid "Sort dynamic relocs"
+msgstr "Lajittele dynaamiset relocs-tietueet"
+
+#: options.h:954
+msgid "Do not sort dynamic relocs"
+msgstr "Älä lajittele dynaamisia relocs-tietueita"
+
+#: options.h:956
+msgid "Set common page size to SIZE"
+msgstr "Aseta yhteissivun kooksi KOKO"
+
+#: options.h:961
+msgid "Mark output as requiring executable stack"
+msgstr "Merkitse tuloste vaadittuna suoritettavassa pinossa"
+
+# DSO on ilmeisesti Dynamic shared object
+#: options.h:963
+msgid "Mark DSO to be initialized first at runtime"
+msgstr "Merkitse dynaamisesti jaetut objektit alustettavaksi ensimmäiseksi ajoaikana"
+
+#: options.h:966
+msgid "Mark object to interpose all DSOs but executable"
+msgstr "Merkitse objekti kaikkien dynaamisesti jaettujen objektien väliin paitsi suoritettavien"
+
+#: options.h:969
+msgid "Mark object for lazy runtime binding (default)"
+msgstr "Merkitse objekti lazy-ajoaikaista sidontaa varten (oletus)"
+
+#: options.h:972
+msgid "Mark object requiring immediate process"
+msgstr "Merkitse, että objekti vaatii välitöntä käsittelyä"
+
+#: options.h:975
+msgid "Set maximum page size to SIZE"
+msgstr "Aseta suurimmaksi sivukooksi KOKO"
+
+#: options.h:978
+msgid "Do not create copy relocs"
+msgstr "Älä luo kopio-relocs-tietueita"
+
+#: options.h:980
+msgid "Mark object not to use default search paths"
+msgstr "Merkitse, että objekti ei käytä oletushakupolkuja"
+
+#: options.h:983
+msgid "Mark DSO non-deletable at runtime"
+msgstr "Merkitse dynaamisesti jaettu objekti ei-poistettavaksi ajoaikana"
+
+#: options.h:986
+msgid "Mark DSO not available to dlopen"
+msgstr "Merkitse, että dynaamisesti jaettu objekti ei ole saatavilla funktiolle dlopen"
+
+#: options.h:989
+msgid "Mark DSO not available to dldump"
+msgstr "Merkitse, että dynaamisesti jaettu objekti ei saatavilla funktiolle dldump"
+
+#: options.h:992
+msgid "Mark output as not requiring executable stack"
+msgstr "Merkitse, että tuloste ei vaadi suoritettavaa pinoa"
+
+#: options.h:994
+msgid "Mark object for immediate function binding"
+msgstr "Merkitse, että objekti vaatii välitöntä funktion sidontaa"
+
+#: options.h:997
+msgid "Mark DSO to indicate that needs immediate $ORIGIN processing at runtime"
+msgstr "Merkitse DSO osoittamaan, että se tarvitsee välittömän $ORIGIN-käsittelyn ajoaikaisesti"
+
+#: options.h:1000
+msgid "Where possible mark variables read-only after relocation"
+msgstr "Missä mahdollista, merkitse muuttuja kirjoitussuojatuiksi sijoituksen jälkeen"
+
+#: options.h:1001
+msgid "Don't mark variables read-only after relocation"
+msgstr "Älä merkitse muuttujia kirjoitussuojatuiksi siirroksen jälkeen"
+
+#: output.cc:1132
+msgid "section group retained but group element discarded"
+msgstr "lohkoryhmä palautettu, mutta ryhmän elementti hylätty"
+
+#: output.cc:1860
+#, c-format
+msgid "invalid alignment %lu for section \"%s\""
+msgstr "virheellinen tasaus %lu lohkolle ”%s”"
+
+#: output.cc:3573
+#, c-format
+msgid "dot moves backward in linker script from 0x%llx to 0x%llx"
+msgstr "piste siirtyy taaksepäin linkkeriskriptissä osoitteesta 0x%llx osoitteeseen 0x%llx"
+
+#: output.cc:3576
+#, c-format
+msgid "address of section '%s' moves backward from 0x%llx to 0x%llx"
+msgstr "lohkon ’%s’ osoite siirtyy taaksepäin osoitteesta 0x%llx osoitteeseen 0x%llx"
+
+#: output.cc:3755
+#, c-format
+msgid "nobits section %s may not precede progbits section %s in same segment"
+msgstr "nobits-lohko %s ei voi edeltää progbits-lohkoa %s samassa segmentissä"
+
+#: output.cc:3907 output.cc:3975
+#, c-format
+msgid "%s: open: %s"
+msgstr "%s: avaa tiedosto: %s"
+
+#: output.cc:3996
+#, c-format
+msgid "%s: mremap: %s"
+msgstr "%s: mremap epäonnistui: %s"
+
+#: output.cc:4005
+#, c-format
+msgid "%s: mmap: %s"
+msgstr "%s: mmap epäonnistui: %s"
+
+#: output.cc:4085
+#, c-format
+msgid "%s: mmap: failed to allocate %lu bytes for output file: %s"
+msgstr "%s: mmap: epäonnistuttiin varaamaan %lu tavua tulostetiedostolle: %s"
+
+#: output.cc:4096
+#, c-format
+msgid "%s: munmap: %s"
+msgstr "%s: munmap epäonnistui: %s"
+
+#: output.cc:4115
+#, c-format
+msgid "%s: write: unexpected 0 return-value"
+msgstr "%s: write: odottamaton 0-paluuarvo"
+
+#: output.cc:4117
+#, c-format
+msgid "%s: write: %s"
+msgstr "%s: write epäonnistui: %s"
+
+#: output.cc:4132
+#, c-format
+msgid "%s: close: %s"
+msgstr "%s: close epäonnistui: %s"
+
+#: output.h:520
+msgid "** section headers"
+msgstr "** lohko-otsakkeet"
+
+#: output.h:565
+msgid "** segment headers"
+msgstr "** segmenttiotsakkeet"
+
+#: output.h:613
+msgid "** file header"
+msgstr "** tiedosto-otsake"
+
+#: output.h:833
+msgid "** fill"
+msgstr "** täyte"
+
+#: output.h:987
+msgid "** string table"
+msgstr "** merkkijonotaulu"
+
+#: output.h:1300
+msgid "** dynamic relocs"
+msgstr "** dynaamiset sijoitukset"
+
+#: output.h:1301 output.h:1637
+msgid "** relocs"
+msgstr "** sijoitukset"
+
+#: output.h:1662
+msgid "** group"
+msgstr "** ryhmä"
+
+#: output.h:1774
+msgid "** GOT"
+msgstr "** GOT"
+
+#: output.h:1916
+msgid "** dynamic"
+msgstr "** dynaaminen"
+
+#: output.h:2039
+msgid "** symtab xindex"
+msgstr "** symtab xindex"
+
+#: parameters.cc:172
+#, c-format
+msgid "unrecognized output format %s"
+msgstr "tunnistamaton tulostemuoto %s"
+
+#: plugin.cc:106
+#, c-format
+msgid "%s: could not load plugin library"
+msgstr "%s: ei voitu ladata lisäosakirjastoa"
+
+#: plugin.cc:116
+#, c-format
+msgid "%s: could not find onload entry point"
+msgstr "%s: ei kyetty löytämään sulkemistulokohtaa"
+
+#: plugin.cc:426
+msgid "Input files added by plug-ins in --incremental mode not supported yet.\n"
+msgstr "Lisäosien lisäämiä syötetiedostoja ei tueta vielä --incremental -tilassa.\n"
+
+#: powerpc.cc:1502 sparc.cc:2307 x86_64.cc:1632
+#, c-format
+msgid "%s: unsupported REL reloc section"
+msgstr "%s: tukematon REL-sijoituslohko"
+
+#: readsyms.cc:191
+#, c-format
+msgid "%s: file is empty"
+msgstr "%s: tiedosto on tyhjä"
+
+#. Here we have to handle any other input file types we need.
+#: readsyms.cc:575
+#, c-format
+msgid "%s: not an object or archive"
+msgstr "%s: ei ole objekti tai arkisto"
+
+#: reduced_debug_output.cc:236
+msgid "Debug abbreviations extend beyond .debug_abbrev section; failed to reduce debug abbreviations"
+msgstr "Vianjäljityslyhennykset laajenevat .debug_abbrev-lohkon ylitse; vianjäljityslyhenteiden vähentäminen epäonnistui"
+
+#: reduced_debug_output.cc:322
+msgid "Extremely large compile unit in debug info; failed to reduce debug info"
+msgstr "Äärimmäisen laaja käännösyksikkö vianjäljitystiedoissa; vianjäljitystietojen vähentäminen epäonnistui"
+
+#: reduced_debug_output.cc:330
+msgid "Debug info extends beyond .debug_info section;failed to reduce debug info"
+msgstr "Vianjäljitystiedot laajentuvat .debug_info-lohkon ylitse; vianjäljitystietojen vähentäminen epäonnistui"
+
+#: reduced_debug_output.cc:350 reduced_debug_output.cc:392
+msgid "Invalid DIE in debug info; failed to reduce debug info"
+msgstr "Virheellinen DIE vianjäljitystiedoissa; vianjäljitystietojen vähentäminen epäonnistui"
+
+#: reduced_debug_output.cc:373
+msgid "Debug info extends beyond .debug_info section; failed to reduce debug info"
+msgstr "Vianjäljitystiedot laajenevat .debug_info-lohkon ylitse; vianjäljitystietojen vähentäminen epäonnistui"
+
+#: reloc.cc:297 reloc.cc:858
+#, c-format
+msgid "relocation section %u uses unexpected symbol table %u"
+msgstr "sijoituslohko %u käyttää odottomatonta symbolitaulua %u"
+
+#: reloc.cc:312 reloc.cc:875
+#, c-format
+msgid "unexpected entsize for reloc section %u: %lu != %u"
+msgstr "odottamaton entsize reloc-lohkolle %u: %lu != %u"
+
+#: reloc.cc:321 reloc.cc:884
+#, c-format
+msgid "reloc section %u size %lu uneven"
+msgstr "reloc-lohko %u koko %lu pariton"
+
+#: reloc.cc:1203
+#, c-format
+msgid "could not convert call to '%s' to '%s'"
+msgstr "ei voitu muuntaa kutsua kohteeseen ’%s’ kutsuksi kohteeseen ’%s’"
+
+#: reloc.cc:1343
+#, c-format
+msgid "reloc section size %zu is not a multiple of reloc size %d\n"
+msgstr "reloc-lohkokoko %zu ei ole reloc-koon %d monikerta\n"
+
+#. We should only see externally visible symbols in the symbol
+#. table.
+#: resolve.cc:191
+msgid "invalid STB_LOCAL symbol in external symbols"
+msgstr "virheellinen STB_LOCAL-symboli ulkoisissa symboleissa"
+
+#. Any target which wants to handle STB_LOOS, etc., needs to
+#. define a resolve method.
+#: resolve.cc:197
+msgid "unsupported symbol binding"
+msgstr "tukematon symbolisidos"
+
+#. A dynamic object cannot reference a hidden or internal symbol
+#. defined in another object.
+#: resolve.cc:266
+#, c-format
+msgid "%s symbol '%s' in %s is referenced by DSO %s"
+msgstr "%s symboli ’%s’ kohteessa %s on DSO %s:n viittaama"
+
+#: resolve.cc:326
+#, c-format
+msgid "common of '%s' overriding smaller common"
+msgstr "’%s’-yhteissymboli korvaa pienemmän yhteissymbolin"
+
+#: resolve.cc:331
+#, c-format
+msgid "common of '%s' overidden by larger common"
+msgstr "’%s’-yhteissymboli korvattu laajemmalla yhteissymbolilla"
+
+#: resolve.cc:336
+#, c-format
+msgid "multiple common of '%s'"
+msgstr "useita ’%s’-yhteissymboleja."
+
+#: resolve.cc:442
+#, c-format
+msgid "multiple definition of '%s'"
+msgstr "useita ’%s’-määrittelyjä"
+
+#: resolve.cc:481
+#, c-format
+msgid "definition of '%s' overriding common"
+msgstr "’%s’-määrittely korvaa yhteissymbolin"
+
+#: resolve.cc:516
+#, c-format
+msgid "definition of '%s' overriding dynamic common definition"
+msgstr "’%s’-määrittely korvaa dynaamisen yhteismäärittelyn"
+
+#: resolve.cc:636
+#, c-format
+msgid "common '%s' overridden by previous definition"
+msgstr "yhteinen ’%s’ korvattu edellisellä määrittelyllä"
+
+#: resolve.cc:766 resolve.cc:778
+msgid "command line"
+msgstr "komentorivi"
+
+#: script-sections.cc:690
+msgid "dot may not move backward"
+msgstr "piste ei voi siirtyä taaksepäin"
+
+#: script-sections.cc:757
+msgid "** expression"
+msgstr "** lauseke"
+
+#: script-sections.cc:941
+msgid "fill value is not absolute"
+msgstr "täytearvo ei ole absoluuttinen"
+
+#: script-sections.cc:1913
+#, c-format
+msgid "alignment of section %s is not absolute"
+msgstr "lohkon %s tasaus ei ole absoluuttinen"
+
+#: script-sections.cc:1957
+#, c-format
+msgid "subalign of section %s is not absolute"
+msgstr "lohkon %s alitasaus ei ole absoluuttinen"
+
+#: script-sections.cc:1972
+#, c-format
+msgid "fill of section %s is not absolute"
+msgstr "lohkon %s täyte ei ole absoluuttinen"
+
+#: script-sections.cc:2048
+msgid "SPECIAL constraints are not implemented"
+msgstr "SPECIAL-rajoitteita ei ole toteutettu"
+
+#: script-sections.cc:2090
+msgid "mismatched definition for constrained sections"
+msgstr "täsmäämätön määrittely rajoitetuille lohkoille"
+
+# DATA_SEGMENT_ALIGN on sisäänrakennettu funktio linkittäjän skriptikielessä.
+#: script-sections.cc:2634
+msgid "DATA_SEGMENT_ALIGN may only appear once in a linker script"
+msgstr "DATA_SEGMENT_ALIGN-funktio voi esiintyä vain kerran linkkeriskriptissä"
+
+#: script-sections.cc:2649
+msgid "DATA_SEGMENT_RELRO_END may only appear once in a linker script"
+msgstr "DATA_SEGMENT_RELRO_END-funktio voi esiintyä vain kerran linkkeriskriptissä"
+
+#: script-sections.cc:2654
+msgid "DATA_SEGMENT_RELRO_END must follow DATA_SEGMENT_ALIGN"
+msgstr "DATA_SEGMENT_RELRO_END-funktion on seurattava DATA_SEGMENT_ALIGN-funktiota"
+
+#: script-sections.cc:2826
+msgid "no matching section constraint"
+msgstr "ei täsmäävää lohkorajoitusta"
+
+#: script-sections.cc:3151
+msgid "TLS sections are not adjacent"
+msgstr "TLS-lohkot eivät ole vierekkäisiä"
+
+#: script-sections.cc:3280
+msgid "allocated section not in any segment"
+msgstr "varattu lohko ei ole missään segmentissä"
+
+#: script-sections.cc:3309
+#, c-format
+msgid "no segment %s"
+msgstr "ei segmenttiä %s"
+
+#: script-sections.cc:3323
+msgid "section in two PT_LOAD segments"
+msgstr "lohko kahdessa PT_LOAD-segmentissä"
+
+#: script-sections.cc:3330
+msgid "allocated section not in any PT_LOAD segment"
+msgstr "varattu lohko ei ole missään PT_LOAD-segmentissä"
+
+#: script-sections.cc:3358
+msgid "may only specify load address for PT_LOAD segment"
+msgstr "voi vain antaa latausosoitteen PT_LOAD-segmentille"
+
+#: script-sections.cc:3382
+#, c-format
+msgid "PHDRS load address overrides section %s load address"
+msgstr "PHDRS-komennon latausosoite korvaa lohkon %s latausosoitteen"
+
+#. We could support this if we wanted to.
+#: script-sections.cc:3393
+msgid "using only one of FILEHDR and PHDRS is not currently supported"
+msgstr "vain yhden avainsanoista FILEHDR ja PHDRS käyttämistä ei nykyisin tueta"
+
+#: script-sections.cc:3408
+msgid "sections loaded on first page without room for file and program headers are not supported"
+msgstr "ei tueta ensimmäisellä sivulla ladattuja lohkoja ilman tilaa tiedostolle ja ohjelmaotsakkeille"
+
+#: script-sections.cc:3414
+msgid "using FILEHDR and PHDRS on more than one PT_LOAD segment is not currently supported"
+msgstr "avainsanojen FILEHDR ja PHDRS käyttämistä useammassa kuin yhdessä PT_LOAD-segmentissä ei nykyisin tueta"
+
+#: script.cc:1072
+msgid "invalid use of PROVIDE for dot symbol"
+msgstr "virheellinen PROVIDE-käyttö dot-symbolille"
+
+#: script.cc:2132
+#, c-format
+msgid "%s:%d:%d: %s"
+msgstr "%s:%d:%d: %s"
+
+#. There are some options that we could handle here--e.g.,
+#. -lLIBRARY. Should we bother?
+#: script.cc:2297
+#, c-format
+msgid "%s:%d:%d: ignoring command OPTION; OPTION is only valid for scripts specified via -T/--script"
+msgstr "%s:%d:%d: ohitetaan komento OPTION; OPTION on kelvollinen vain skripteillä, jotka määritellään valitsimilla -T/--script"
+
+#: script.cc:2362
+#, c-format
+msgid "%s:%d:%d: ignoring SEARCH_DIR; SEARCH_DIR is only valid for scripts specified via -T/--script"
+msgstr "%s:%d:%d: ohitetaan SEARCH_DIR; SEARCH_DIR on kelvollinen vain skripteille, jotka on määritelty valitsimien -T/--script kautta"
+
+#: script.cc:2606 script.cc:2620
+#, c-format
+msgid "%s:%d:%d: DATA_SEGMENT_ALIGN not in SECTIONS clause"
+msgstr "%s:%d:%d: DATA_SEGMENT_ALIGN-funktio ei ole SECTIONS-lauseessa"
+
+#: script.cc:2739
+msgid "unknown PHDR type (try integer)"
+msgstr "tuntematon PHDR-tyyppi (yritä kokonaislukua)"
+
+# Esimerkiksi puhelinluettelossa A-kirjaimella alkavat nimet muodostavat yhden bucketin, B-kirjaimella alkavat toisen jne. A ja B ovat hash key -avaimia.
+#: stringpool.cc:528
+#, c-format
+msgid "%s: %s entries: %zu; buckets: %zu\n"
+msgstr "%s: %s alkiota: %zu; lohkot: %zu\n"
+
+#: stringpool.cc:532
+#, c-format
+msgid "%s: %s entries: %zu\n"
+msgstr "%s: %s alkiota: %zu\n"
+
+#: stringpool.cc:535
+#, c-format
+msgid "%s: %s Stringdata structures: %zu\n"
+msgstr "%s: %s Stringdata-rakenteet: %zu\n"
+
+# ensimmäinen argumentti on objektinimi, toinen nimi
+#: symtab.cc:857
+#, c-format
+msgid "%s: reference to %s"
+msgstr "%s: viite nimeen %s"
+
+# ensimmäinen argumentti on objektinimi, toinen nimi
+#: symtab.cc:859
+#, c-format
+msgid "%s: definition of %s"
+msgstr "%s: %s-määrittely"
+
+#: symtab.cc:1052
+#, c-format
+msgid "bad global symbol name offset %u at %zu"
+msgstr "väärä yleissymbolinimisiirros %u osoitteessa %zu"
+
+#: symtab.cc:1278
+msgid "--just-symbols does not make sense with a shared object"
+msgstr "--just-symbols ei tunnu järkevältä jaetuille objekteille"
+
+#: symtab.cc:1284
+msgid "too few symbol versions"
+msgstr "liian harvoja symboliversioita"
+
+#: symtab.cc:1333
+#, c-format
+msgid "bad symbol name offset %u at %zu"
+msgstr "väärä symbolinimisiirros %u osoitteessa %zu"
+
+#: symtab.cc:1396
+#, c-format
+msgid "versym for symbol %zu out of range: %u"
+msgstr "versym symbolille %zu lukualueen ulkopuolella: %u"
+
+#: symtab.cc:1404
+#, c-format
+msgid "versym for symbol %zu has no name: %u"
+msgstr "versym symbolille %zu ei ole nimeä: %u"
+
+#: symtab.cc:2549 symtab.cc:2681
+#, c-format
+msgid "%s: unsupported symbol section 0x%x"
+msgstr "%s: tukematon symbolilohko 0x%x"
+
+#: symtab.cc:2933
+#, c-format
+msgid "%s: symbol table entries: %zu; buckets: %zu\n"
+msgstr "%s: symbolitaulualkiot: %zu; lohkot: %zu\n"
+
+#: symtab.cc:2936
+#, c-format
+msgid "%s: symbol table entries: %zu\n"
+msgstr "%s: symbolitaulutuloja: %zu\n"
+
+#: symtab.cc:3007
+#, c-format
+msgid "while linking %s: symbol '%s' defined in multiple places (possible ODR violation):"
+msgstr "kun linkitetään %s: symboli ’%s’ määritellään useissa paikoissa (mahdollinen ODR-ristiriita):"
+
+#: target-reloc.h:259
+msgid "relocation refers to discarded comdat section"
+msgstr "sijoitus viittaa hylättyyn comdat-lohkoon"
+
+#: target-reloc.h:298
+#, c-format
+msgid "reloc has bad offset %zu"
+msgstr "reloc-tietueella on väärä siirros %zu"
+
+#: target.cc:90
+#, c-format
+msgid "%s: unsupported ELF file type %d"
+msgstr "%s: tukematon ELF-tiedostotyyppi %d"
+
+#: target.cc:157
+#, c-format
+msgid "linker does not include stack split support required by %s"
+msgstr "linkkeri ei sisällä kohteen %s vaatiman pinojakamisen tukea"
+
+#: tls.h:59
+msgid "TLS relocation out of range"
+msgstr "TLS-sijoitus lukualueen ulkopuolella"
+
+#: tls.h:73
+msgid "TLS relocation against invalid instruction"
+msgstr "TLS-sijoitus virheellistä käskyä vastaan"
+
+#. This output is intended to follow the GNU standards.
+#: version.cc:65
+#, c-format
+msgid "Copyright 2008 Free Software Foundation, Inc.\n"
+msgstr "Copyright 2008 Free Software Foundation, Inc.\n"
+
+#: version.cc:66
+#, c-format
+msgid ""
+"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) a later version.\n"
+"This program has absolutely no warranty.\n"
+msgstr ""
+"Tämä ohjelma on vapaa ohjelmisto; saat jakaa sitä GNU General Public lisenssi\n"
+"version 3 tai (valintasi mukaan) myöhäisemman version ehtojen mukaisesti.\n"
+"Tällä ohjelmalla ei ehdottomasti ole mitään takuuta.\n"
+
+#: workqueue-threads.cc:106
+#, c-format
+msgid "%s failed: %s"
+msgstr "%s epäonnistui: %s"
+
+#: x86_64.cc:2184
+#, c-format
+msgid "unsupported reloc type %u"
+msgstr "tukematon reloc-tietuetyyppi %u"
+
+#: x86_64.cc:2524
+#, c-format
+msgid "unsupported reloc %u against local symbol"
+msgstr "tukematon reloc %u -tietue paikallista symbolia vastaan"
+
+#~ msgid " applied to section relative value"
+#~ msgstr " sovellettu lohkosuhteelliseen arvoon"
+
+#~ msgid "cannot find -l%s"
+#~ msgstr "ei voi löytää -l%s"
+
+#~ msgid "%s: ELF file too short"
+#~ msgstr "%s: ELF-tiedosto on liian lyhyt"
+
+#~ msgid "%s: invalid ELF version 0"
+#~ msgstr "%s: virheellinen ELF-versio 0"
+
+#~ msgid "%s: unsupported ELF version %d"
+#~ msgstr "%s: tukematon ELF-versio %d"
+
+#~ msgid "%s: invalid ELF class 0"
+#~ msgstr "%s: virheellinen ELF-luokka 0"
+
+#~ msgid "%s: unsupported ELF class %d"
+#~ msgstr "%s: tukematon ELF-luokka %d"
+
+#~ msgid "%s: invalid ELF data encoding"
+#~ msgstr "%s: virheellinen ELF-datakoodaus"
+
+#~ msgid "%s: unsupported ELF data encoding %d"
+#~ msgstr "%s: tukematon ELF-datakoodaus %d"
diff --git a/binutils-2.25/gold/po/gold.pot b/binutils-2.25/gold/po/gold.pot
new file mode 100644
index 00000000..d58054a5
--- /dev/null
+++ b/binutils-2.25/gold/po/gold.pot
@@ -0,0 +1,2263 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: bug-binutils@gnu.org\n"
+"POT-Creation-Date: 2010-03-03 15:08+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: archive.cc:119
+#, c-format
+msgid "%s: no archive symbol table (run ranlib)"
+msgstr ""
+
+#: archive.cc:204
+#, c-format
+msgid "%s: bad archive symbol table names"
+msgstr ""
+
+#: archive.cc:236
+#, c-format
+msgid "%s: malformed archive header at %zu"
+msgstr ""
+
+#: archive.cc:256
+#, c-format
+msgid "%s: malformed archive header size at %zu"
+msgstr ""
+
+#: archive.cc:267
+#, c-format
+msgid "%s: malformed archive header name at %zu"
+msgstr ""
+
+#: archive.cc:297
+#, c-format
+msgid "%s: bad extended name index at %zu"
+msgstr ""
+
+#: archive.cc:307
+#, c-format
+msgid "%s: bad extended name entry at header %zu"
+msgstr ""
+
+#: archive.cc:404
+#, c-format
+msgid "%s: short archive header at %zu"
+msgstr ""
+
+#: archive.cc:560
+#, c-format
+msgid "%s: member at %zu is not an ELF object"
+msgstr ""
+
+#: archive.cc:879
+#, c-format
+msgid "%s: archive libraries: %u\n"
+msgstr ""
+
+#: archive.cc:881
+#, c-format
+msgid "%s: total archive members: %u\n"
+msgstr ""
+
+#: archive.cc:883
+#, c-format
+msgid "%s: loaded archive members: %u\n"
+msgstr ""
+
+#: arm.cc:1149 i386.cc:536 sparc.cc:1087 x86_64.cc:565
+msgid "** PLT"
+msgstr ""
+
+#: arm.cc:1364 i386.cc:880 powerpc.cc:1014 sparc.cc:1502 x86_64.cc:955
+#: x86_64.cc:1265
+#, c-format
+msgid "%s: unsupported reloc %u against local symbol"
+msgstr ""
+
+#: arm.cc:1404 powerpc.cc:1105 sparc.cc:1592 x86_64.cc:992
+msgid "requires unsupported dynamic reloc; recompile with -fPIC"
+msgstr ""
+
+#. These are relocations which should only be seen by the
+#. dynamic linker, and should never be seen here.
+#: arm.cc:1519 arm.cc:1739 arm.cc:2354 i386.cc:1002 i386.cc:1334
+#: powerpc.cc:1223 powerpc.cc:1432 sparc.cc:1877 sparc.cc:2238 x86_64.cc:1145
+#: x86_64.cc:1453
+#, c-format
+msgid "%s: unexpected reloc %u in object file"
+msgstr ""
+
+#: arm.cc:1538 i386.cc:1171 powerpc.cc:1242 sparc.cc:1896 x86_64.cc:1279
+#: x86_64.cc:1571
+#, c-format
+msgid "%s: unsupported reloc %u against global symbol %s"
+msgstr ""
+
+#: arm.cc:1804 i386.cc:1542
+#, c-format
+msgid "%s: unsupported RELA reloc section"
+msgstr ""
+
+#: arm.cc:2047
+msgid ""
+"relocation R_ARM_MOVW_ABS_NC cannot be used when makinga shared object; "
+"recompile with -fPIC"
+msgstr ""
+
+#: arm.cc:2056
+msgid ""
+"relocation R_ARM_MOVT_ABS cannot be used when makinga shared object; "
+"recompile with -fPIC"
+msgstr ""
+
+#: arm.cc:2067
+msgid ""
+"relocation R_ARM_THM_MOVW_ABS_NC cannot be used whenmaking a shared object; "
+"recompile with -fPIC"
+msgstr ""
+
+#: arm.cc:2077
+msgid ""
+"relocation R_ARM_THM_MOVT_ABS cannot be used whenmaking a shared object; "
+"recompile with -fPIC"
+msgstr ""
+
+#: arm.cc:2141
+msgid "cannot find origin of R_ARM_BASE_PREL"
+msgstr ""
+
+#: arm.cc:2169
+msgid "cannot find origin of R_ARM_BASE_ABS"
+msgstr ""
+
+#: arm.cc:2230 i386.cc:1820 i386.cc:2521 powerpc.cc:1798 sparc.cc:2711
+#: x86_64.cc:1935 x86_64.cc:2518
+#, c-format
+msgid "unexpected reloc %u in object file"
+msgstr ""
+
+#: arm.cc:2236 i386.cc:1852 i386.cc:1931 i386.cc:1983 i386.cc:2014
+#: i386.cc:2076 powerpc.cc:1804 sparc.cc:2717 sparc.cc:2900 sparc.cc:2961
+#: sparc.cc:3068 x86_64.cc:1956 x86_64.cc:2039 x86_64.cc:2094 x86_64.cc:2119
+#, c-format
+msgid "unsupported reloc %u"
+msgstr ""
+
+#: arm.cc:2248
+#, c-format
+msgid "relocation overflow in relocation %u"
+msgstr ""
+
+#: arm.cc:2256
+#, c-format
+msgid "unexpected opcode while processing relocation %u"
+msgstr ""
+
+#: arm.cc:2359 i386.cc:2535
+#, c-format
+msgid "unsupported reloc %u in object file"
+msgstr ""
+
+#: binary.cc:129
+#, c-format
+msgid "cannot open %s: %s:"
+msgstr ""
+
+#: compressed_output.cc:128
+msgid "not compressing section data: zlib error"
+msgstr ""
+
+#: cref.cc:244
+#, c-format
+msgid "cannot open symbol count file %s: %s"
+msgstr ""
+
+#: descriptors.cc:116
+#, c-format
+msgid "file %s was removed during the link"
+msgstr ""
+
+#: descriptors.cc:169
+msgid "out of file descriptors and couldn't close any"
+msgstr ""
+
+#: descriptors.cc:190 descriptors.cc:226
+#, c-format
+msgid "while closing %s: %s"
+msgstr ""
+
+#: dirsearch.cc:71
+#, c-format
+msgid "%s: can not read directory: %s"
+msgstr ""
+
+#: dwarf_reader.cc:53 dwarf_reader.cc:84
+msgid "Unusually large LEB128 decoded, debug information may be corrupted"
+msgstr ""
+
+#: dynobj.cc:164
+#, c-format
+msgid "unexpected duplicate type %u section: %u, %u"
+msgstr ""
+
+#: dynobj.cc:200
+#, c-format
+msgid "unexpected link in section %u header: %u != %u"
+msgstr ""
+
+#: dynobj.cc:236
+#, c-format
+msgid "DYNAMIC section %u link out of range: %u"
+msgstr ""
+
+#: dynobj.cc:244
+#, c-format
+msgid "DYNAMIC section %u link %u is not a strtab"
+msgstr ""
+
+#: dynobj.cc:273
+#, c-format
+msgid "DT_SONAME value out of range: %lld >= %lld"
+msgstr ""
+
+#: dynobj.cc:285
+#, c-format
+msgid "DT_NEEDED value out of range: %lld >= %lld"
+msgstr ""
+
+#: dynobj.cc:298
+msgid "missing DT_NULL in dynamic segment"
+msgstr ""
+
+#: dynobj.cc:344
+#, c-format
+msgid "invalid dynamic symbol table name index: %u"
+msgstr ""
+
+#: dynobj.cc:351
+#, c-format
+msgid "dynamic symbol table name section has wrong type: %u"
+msgstr ""
+
+#: dynobj.cc:438 object.cc:463 object.cc:1106
+#, c-format
+msgid "bad section name offset for section %u: %lu"
+msgstr ""
+
+#: dynobj.cc:468
+#, c-format
+msgid "duplicate definition for version %u"
+msgstr ""
+
+#: dynobj.cc:497
+#, c-format
+msgid "unexpected verdef version %u"
+msgstr ""
+
+#: dynobj.cc:513
+#, c-format
+msgid "verdef vd_cnt field too small: %u"
+msgstr ""
+
+#: dynobj.cc:521
+#, c-format
+msgid "verdef vd_aux field out of range: %u"
+msgstr ""
+
+#: dynobj.cc:532
+#, c-format
+msgid "verdaux vda_name field out of range: %u"
+msgstr ""
+
+#: dynobj.cc:542
+#, c-format
+msgid "verdef vd_next field out of range: %u"
+msgstr ""
+
+#: dynobj.cc:576
+#, c-format
+msgid "unexpected verneed version %u"
+msgstr ""
+
+#: dynobj.cc:585
+#, c-format
+msgid "verneed vn_aux field out of range: %u"
+msgstr ""
+
+#: dynobj.cc:599
+#, c-format
+msgid "vernaux vna_name field out of range: %u"
+msgstr ""
+
+#: dynobj.cc:610
+#, c-format
+msgid "verneed vna_next field out of range: %u"
+msgstr ""
+
+#: dynobj.cc:621
+#, c-format
+msgid "verneed vn_next field out of range: %u"
+msgstr ""
+
+#: dynobj.cc:670
+msgid "size of dynamic symbols is not multiple of symbol size"
+msgstr ""
+
+#: dynobj.cc:1435
+#, c-format
+msgid "symbol %s has undefined version %s"
+msgstr ""
+
+#: ehframe.h:82
+msgid "** eh_frame_hdr"
+msgstr ""
+
+#: ehframe.h:353
+msgid "** eh_frame"
+msgstr ""
+
+#: errors.cc:81
+#, c-format
+msgid "%s: fatal error: "
+msgstr ""
+
+#: errors.cc:92
+#, c-format
+msgid "%s: error: "
+msgstr ""
+
+#: errors.cc:104
+#, c-format
+msgid "%s: warning: "
+msgstr ""
+
+#: errors.cc:128
+#, c-format
+msgid "%s: %s: error: "
+msgstr ""
+
+#: errors.cc:144
+#, c-format
+msgid "%s: %s: warning: "
+msgstr ""
+
+#: errors.cc:167
+#, c-format
+msgid "%s: %s: error: undefined reference to '%s'\n"
+msgstr ""
+
+#: errors.cc:172
+#, c-format
+msgid "%s: %s: error: undefined reference to '%s', version '%s'\n"
+msgstr ""
+
+#: errors.cc:182
+#, c-format
+msgid "%s: "
+msgstr ""
+
+#: expression.cc:172
+#, c-format
+msgid "undefined symbol '%s' referenced in expression"
+msgstr ""
+
+#: expression.cc:209
+msgid "invalid reference to dot symbol outside of SECTIONS clause"
+msgstr ""
+
+#. Handle unary operators. We use a preprocessor macro as a hack to
+#. capture the C operator.
+#: expression.cc:278
+msgid "unary "
+msgstr ""
+
+#. 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.
+#: expression.cc:400
+msgid "binary "
+msgstr ""
+
+#: expression.cc:404
+msgid " by zero"
+msgstr ""
+
+#: expression.cc:575
+msgid "max applied to section relative value"
+msgstr ""
+
+#: expression.cc:610
+msgid "min applied to section relative value"
+msgstr ""
+
+#: expression.cc:740
+msgid "aligning to section relative value"
+msgstr ""
+
+#: expression.cc:895
+#, c-format
+msgid "unknown constant %s"
+msgstr ""
+
+#: expression.cc:1126
+msgid "SEGMENT_START not implemented"
+msgstr ""
+
+#: expression.cc:1135
+msgid "ORIGIN not implemented"
+msgstr ""
+
+#: expression.cc:1141
+msgid "LENGTH not implemented"
+msgstr ""
+
+#: fileread.cc:65
+#, c-format
+msgid "munmap failed: %s"
+msgstr ""
+
+#: fileread.cc:129
+#, c-format
+msgid "%s: fstat failed: %s"
+msgstr ""
+
+#: fileread.cc:169
+#, c-format
+msgid "could not reopen file %s"
+msgstr ""
+
+#: fileread.cc:302
+#, c-format
+msgid "%s: pread failed: %s"
+msgstr ""
+
+#: fileread.cc:308
+#, c-format
+msgid "%s: file too short: read only %lld of %lld bytes at %lld"
+msgstr ""
+
+#: fileread.cc:372
+#, c-format
+msgid ""
+"%s: attempt to map %lld bytes at offset %lld exceeds size of file; the file "
+"may be corrupt"
+msgstr ""
+
+#: fileread.cc:402
+#, c-format
+msgid "%s: mmap offset %lld size %lld failed: %s"
+msgstr ""
+
+#: fileread.cc:548
+#, c-format
+msgid "%s: lseek failed: %s"
+msgstr ""
+
+#: fileread.cc:554
+#, c-format
+msgid "%s: readv failed: %s"
+msgstr ""
+
+#: fileread.cc:557
+#, c-format
+msgid "%s: file too short: read only %zd of %zd bytes at %lld"
+msgstr ""
+
+#: fileread.cc:706
+#, c-format
+msgid "%s: total bytes mapped for read: %llu\n"
+msgstr ""
+
+#: fileread.cc:708
+#, c-format
+msgid "%s: maximum bytes mapped for read at one time: %llu\n"
+msgstr ""
+
+#: fileread.cc:791
+#, c-format
+msgid "%s: stat failed: %s"
+msgstr ""
+
+#: fileread.cc:849
+#, c-format
+msgid "cannot find %s%s"
+msgstr ""
+
+#: fileread.cc:880
+#, c-format
+msgid "cannot find %s"
+msgstr ""
+
+#: fileread.cc:904
+#, c-format
+msgid "cannot open %s: %s"
+msgstr ""
+
+#: gold-threads.cc:103
+#, c-format
+msgid "pthead_mutextattr_init failed: %s"
+msgstr ""
+
+#: gold-threads.cc:107
+#, c-format
+msgid "pthread_mutextattr_settype failed: %s"
+msgstr ""
+
+#: gold-threads.cc:112
+#, c-format
+msgid "pthread_mutex_init failed: %s"
+msgstr ""
+
+#: gold-threads.cc:116
+#, c-format
+msgid "pthread_mutexattr_destroy failed: %s"
+msgstr ""
+
+#: gold-threads.cc:123
+#, c-format
+msgid "pthread_mutex_destroy failed: %s"
+msgstr ""
+
+#: gold-threads.cc:131 gold-threads.cc:382
+#, c-format
+msgid "pthread_mutex_lock failed: %s"
+msgstr ""
+
+#: gold-threads.cc:139 gold-threads.cc:394
+#, c-format
+msgid "pthread_mutex_unlock failed: %s"
+msgstr ""
+
+#: gold-threads.cc:220
+#, c-format
+msgid "pthread_cond_init failed: %s"
+msgstr ""
+
+#: gold-threads.cc:227
+#, c-format
+msgid "pthread_cond_destroy failed: %s"
+msgstr ""
+
+#: gold-threads.cc:236
+#, c-format
+msgid "pthread_cond_wait failed: %s"
+msgstr ""
+
+#: gold-threads.cc:244
+#, c-format
+msgid "pthread_cond_signal failed: %s"
+msgstr ""
+
+#: gold-threads.cc:252
+#, c-format
+msgid "pthread_cond_broadcast failed: %s"
+msgstr ""
+
+#: gold-threads.cc:388
+#, c-format
+msgid "pthread_once failed: %s"
+msgstr ""
+
+#: gold.cc:91
+#, c-format
+msgid "%s: internal error in %s, at %s:%d\n"
+msgstr ""
+
+#: gold.cc:173
+msgid "no input files"
+msgstr ""
+
+#: gold.cc:226
+msgid "cannot mix -r with --gc-sections or --icf"
+msgstr ""
+
+#: gold.cc:407
+#, c-format
+msgid "cannot mix -static with dynamic object %s"
+msgstr ""
+
+#: gold.cc:411
+#, c-format
+msgid "cannot mix -r with dynamic object %s"
+msgstr ""
+
+#: gold.cc:415
+#, c-format
+msgid "cannot use non-ELF output format with dynamic object %s"
+msgstr ""
+
+#: gold.cc:427
+#, c-format
+msgid "cannot mix split-stack '%s' and non-split-stack '%s' when using -r"
+msgstr ""
+
+#. FIXME: This needs to specify the location somehow.
+#: i386.cc:232 i386.cc:1669 sparc.cc:234 sparc.cc:2395 x86_64.cc:237
+#: x86_64.cc:1732
+msgid "missing expected TLS relocation"
+msgstr ""
+
+#: i386.cc:944 x86_64.cc:1068
+#, c-format
+msgid "section symbol %u has bad shndx %u"
+msgstr ""
+
+#: i386.cc:1036 i386.cc:1060 sparc.cc:1777 x86_64.cc:1176 x86_64.cc:1204
+#, c-format
+msgid "local symbol %u has bad shndx %u"
+msgstr ""
+
+#: i386.cc:1991
+msgid "both SUN and GNU model TLS relocations"
+msgstr ""
+
+#: i386.cc:2730 x86_64.cc:2719
+#, c-format
+msgid "failed to match split-stack sequence at section %u offset %0zx"
+msgstr ""
+
+#: icf.cc:616
+#, c-format
+msgid "%s: ICF Converged after %u iteration(s)"
+msgstr ""
+
+#: icf.cc:619
+#, c-format
+msgid "%s: ICF stopped after %u iteration(s)"
+msgstr ""
+
+#: icf.cc:633
+#, c-format
+msgid "Could not find symbol %s to unfold\n"
+msgstr ""
+
+#: incremental.cc:242
+#, c-format
+msgid "the link might take longer: cannot perform incremental link: %s"
+msgstr ""
+
+#: incremental.cc:302
+msgid "no incremental data from previous build"
+msgstr ""
+
+#: incremental.cc:309 incremental.cc:332
+msgid "invalid incremental build data"
+msgstr ""
+
+#: incremental.cc:321
+msgid "different version of incremental build data"
+msgstr ""
+
+#: incremental.cc:338
+msgid "command line changed"
+msgstr ""
+
+#: incremental.cc:362
+#, c-format
+msgid "unsupported ELF machine number %d"
+msgstr ""
+
+#: incremental.cc:387
+msgid "output is not an ELF file."
+msgstr ""
+
+#: incremental.cc:410
+msgid "unsupported file: 32-bit, big-endian"
+msgstr ""
+
+#: incremental.cc:419
+msgid "unsupported file: 32-bit, little-endian"
+msgstr ""
+
+#: incremental.cc:431
+msgid "unsupported file: 64-bit, big-endian"
+msgstr ""
+
+#: incremental.cc:440
+msgid "unsupported file: 64-bit, little-endian"
+msgstr ""
+
+#: layout.cc:1887
+#, c-format
+msgid "--build-id=uuid failed: could not open /dev/urandom: %s"
+msgstr ""
+
+#: layout.cc:1894
+#, c-format
+msgid "/dev/urandom: read failed: %s"
+msgstr ""
+
+#: layout.cc:1896
+#, c-format
+msgid "/dev/urandom: expected %zu bytes, got %zd bytes"
+msgstr ""
+
+#: layout.cc:1918
+#, c-format
+msgid "--build-id argument '%s' not a valid hex number"
+msgstr ""
+
+#: layout.cc:1924
+#, c-format
+msgid "unrecognized --build-id argument '%s'"
+msgstr ""
+
+#: layout.cc:2337
+#, c-format
+msgid "load segment overlap [0x%llx -> 0x%llx] and [0x%llx -> 0x%llx]"
+msgstr ""
+
+#: mapfile.cc:70
+#, c-format
+msgid "cannot open map file %s: %s"
+msgstr ""
+
+#: mapfile.cc:84
+#, c-format
+msgid "cannot close map file: %s"
+msgstr ""
+
+#: mapfile.cc:116
+#, c-format
+msgid ""
+"Archive member included because of file (symbol)\n"
+"\n"
+msgstr ""
+
+#: mapfile.cc:159
+#, c-format
+msgid ""
+"\n"
+"Allocating common symbols\n"
+msgstr ""
+
+#: mapfile.cc:161
+#, c-format
+msgid ""
+"Common symbol size file\n"
+"\n"
+msgstr ""
+
+#: mapfile.cc:195
+#, c-format
+msgid ""
+"\n"
+"Memory map\n"
+"\n"
+msgstr ""
+
+#: mapfile.cc:361
+#, c-format
+msgid ""
+"\n"
+"Discarded input sections\n"
+"\n"
+msgstr ""
+
+#: merge.cc:455
+#, c-format
+msgid "%s: %s merged constants size: %lu; input: %zu; output: %zu\n"
+msgstr ""
+
+#: merge.cc:478
+msgid "mergeable string section length not multiple of character size"
+msgstr ""
+
+#: merge.cc:494
+#, c-format
+msgid "%s: last entry in mergeable string section '%s' not null terminated"
+msgstr ""
+
+#: merge.cc:613
+#, c-format
+msgid "%s: %s input: %zu\n"
+msgstr ""
+
+#: merge.h:300
+msgid "** merge constants"
+msgstr ""
+
+#: merge.h:422
+msgid "** merge strings"
+msgstr ""
+
+#: object.cc:75
+msgid "missing SHT_SYMTAB_SHNDX section"
+msgstr ""
+
+#: object.cc:119
+#, c-format
+msgid "symbol %u out of range for SHT_SYMTAB_SHNDX section"
+msgstr ""
+
+#: object.cc:126
+#, c-format
+msgid "extended index for symbol %u out of range: %u"
+msgstr ""
+
+#: object.cc:148 object.cc:2331 output.cc:4052
+#, c-format
+msgid "%s: %s"
+msgstr ""
+
+#: object.cc:190
+#, c-format
+msgid "section name section has wrong type: %u"
+msgstr ""
+
+#: object.cc:546
+#, c-format
+msgid "invalid symbol table name index: %u"
+msgstr ""
+
+#: object.cc:552
+#, c-format
+msgid "symbol table name section has wrong type: %u"
+msgstr ""
+
+#: object.cc:641
+#, c-format
+msgid "section group %u info %u out of range"
+msgstr ""
+
+#: object.cc:660
+#, c-format
+msgid "symbol %u name offset %u out of range"
+msgstr ""
+
+#: object.cc:678
+#, c-format
+msgid "symbol %u invalid section index %u"
+msgstr ""
+
+#: object.cc:723
+#, c-format
+msgid "section %u in section group %u out of range"
+msgstr ""
+
+#: object.cc:731
+#, c-format
+msgid "invalid section group %u refers to earlier section %u"
+msgstr ""
+
+#: object.cc:1037 reloc.cc:271 reloc.cc:838
+#, c-format
+msgid "relocation section %u has bad info %u"
+msgstr ""
+
+#: object.cc:1231
+#, c-format
+msgid "%s: removing unused section from '%s' in file '%s'"
+msgstr ""
+
+#: object.cc:1257
+#, c-format
+msgid "%s: ICF folding section '%s' in file '%s'into '%s' in file '%s'"
+msgstr ""
+
+#: object.cc:1454
+msgid "size of symbols is not multiple of symbol size"
+msgstr ""
+
+#: object.cc:1563
+#, c-format
+msgid "local symbol %u section name out of range: %u >= %u"
+msgstr ""
+
+#: object.cc:1652
+#, c-format
+msgid "unknown section index %u for local symbol %u"
+msgstr ""
+
+#: object.cc:1661
+#, c-format
+msgid "local symbol %u section index %u out of range"
+msgstr ""
+
+#: object.cc:2169
+#, c-format
+msgid "%s is not supported but is required for %s in %s"
+msgstr ""
+
+#: object.cc:2273
+#, c-format
+msgid "%s: unsupported ELF machine number %d"
+msgstr ""
+
+#: object.cc:2283
+#, c-format
+msgid "%s: incompatible target"
+msgstr ""
+
+#: object.cc:2347 plugin.cc:1019
+#, c-format
+msgid "%s: not configured to support 32-bit big-endian object"
+msgstr ""
+
+#: object.cc:2363 plugin.cc:1028
+#, c-format
+msgid "%s: not configured to support 32-bit little-endian object"
+msgstr ""
+
+#: object.cc:2382 plugin.cc:1040
+#, c-format
+msgid "%s: not configured to support 64-bit big-endian object"
+msgstr ""
+
+#: object.cc:2398 plugin.cc:1049
+#, c-format
+msgid "%s: not configured to support 64-bit little-endian object"
+msgstr ""
+
+#: options.cc:156
+#, c-format
+msgid ""
+"Usage: %s [options] file...\n"
+"Options:\n"
+msgstr ""
+
+#. config.guess and libtool.m4 look in ld --help output for the
+#. string "supported targets".
+#: options.cc:164
+#, c-format
+msgid "%s: supported targets:"
+msgstr ""
+
+#: options.cc:176
+#, c-format
+msgid "Report bugs to %s\n"
+msgstr ""
+
+#: options.cc:193 options.cc:203 options.cc:213
+#, c-format
+msgid "%s: invalid option value (expected an integer): %s"
+msgstr ""
+
+#: options.cc:223
+#, c-format
+msgid "%s: invalid option value (expected a floating point number): %s"
+msgstr ""
+
+#: options.cc:232
+#, c-format
+msgid "%s: must take a non-empty argument"
+msgstr ""
+
+#: options.cc:273
+#, c-format
+msgid "%s: must take one of the following arguments: %s"
+msgstr ""
+
+#: options.cc:300
+#, c-format
+msgid " Supported targets:\n"
+msgstr ""
+
+#: options.cc:409
+#, c-format
+msgid "unable to parse script file %s"
+msgstr ""
+
+#: options.cc:417
+#, c-format
+msgid "unable to parse version script file %s"
+msgstr ""
+
+#: options.cc:425
+#, c-format
+msgid "unable to parse dynamic-list script file %s"
+msgstr ""
+
+#: options.cc:522
+#, c-format
+msgid ""
+"format '%s' not supported; treating as elf (supported formats: elf, binary)"
+msgstr ""
+
+#: options.cc:538
+#, c-format
+msgid "%s: use the --help option for usage information\n"
+msgstr ""
+
+#: options.cc:547
+#, c-format
+msgid "%s: %s: %s\n"
+msgstr ""
+
+#: options.cc:651
+msgid "unexpected argument"
+msgstr ""
+
+#: options.cc:664 options.cc:725
+msgid "missing argument"
+msgstr ""
+
+#: options.cc:736
+msgid "unknown -z option"
+msgstr ""
+
+#: options.cc:935
+#, c-format
+msgid "ignoring --threads: %s was compiled without thread support"
+msgstr ""
+
+#: options.cc:942
+#, c-format
+msgid "ignoring --thread-count: %s was compiled without thread support"
+msgstr ""
+
+#: options.cc:981
+#, c-format
+msgid "unable to open -retain-symbols-file file %s: %s"
+msgstr ""
+
+#: options.cc:1003
+msgid "-shared and -static are incompatible"
+msgstr ""
+
+#: options.cc:1005
+msgid "-shared and -pie are incompatible"
+msgstr ""
+
+#: options.cc:1008
+msgid "-shared and -r are incompatible"
+msgstr ""
+
+#: options.cc:1010
+msgid "-pie and -r are incompatible"
+msgstr ""
+
+#: options.cc:1014
+msgid "-retain-symbols-file does not yet work with -r"
+msgstr ""
+
+#: options.cc:1020
+msgid "binary output format not compatible with -shared or -pie or -r"
+msgstr ""
+
+#: options.cc:1026
+#, c-format
+msgid "--hash-bucket-empty-fraction value %g out of range [0.0, 1.0)"
+msgstr ""
+
+#: options.cc:1031
+msgid ""
+"Options --incremental-changed, --incremental-unchanged, --incremental-"
+"unknown require the use of --incremental"
+msgstr ""
+
+#: options.cc:1097
+msgid "May not nest groups"
+msgstr ""
+
+#: options.cc:1109
+msgid "Group end without group start"
+msgstr ""
+
+#. I guess it's neither a long option nor a short option.
+#: options.cc:1174
+msgid "unknown option"
+msgstr ""
+
+#: options.cc:1201
+#, c-format
+msgid "%s: missing group end\n"
+msgstr ""
+
+#: options.h:571
+msgid "Report usage information"
+msgstr ""
+
+#: options.h:573
+msgid "Report version information"
+msgstr ""
+
+#: options.h:575
+msgid "Report version and target information"
+msgstr ""
+
+#: options.h:584 options.h:635
+msgid "Not supported"
+msgstr ""
+
+#: options.h:585 options.h:636
+msgid "Do not copy DT_NEEDED tags from shared libraries"
+msgstr ""
+
+#: options.h:588
+msgid "Allow unresolved references in shared libraries"
+msgstr ""
+
+#: options.h:589
+msgid "Do not allow unresolved references in shared libraries"
+msgstr ""
+
+#: options.h:592
+msgid "Only set DT_NEEDED for shared libraries if used"
+msgstr ""
+
+#: options.h:593
+msgid "Always DT_NEEDED for shared libraries"
+msgstr ""
+
+#: options.h:600
+msgid "Set input format"
+msgstr ""
+
+#: options.h:603
+msgid "-l searches for shared libraries"
+msgstr ""
+
+#: options.h:605
+msgid "-l does not search for shared libraries"
+msgstr ""
+
+#: options.h:609
+msgid "Bind defined symbols locally"
+msgstr ""
+
+#: options.h:612
+msgid "Bind defined function symbols locally"
+msgstr ""
+
+#: options.h:615
+msgid "Generate build ID note"
+msgstr ""
+
+#: options.h:616 options.h:655
+msgid "[=STYLE]"
+msgstr ""
+
+#: options.h:619
+msgid "Check segment addresses for overlaps (default)"
+msgstr ""
+
+#: options.h:620
+msgid "Do not check segment addresses for overlaps"
+msgstr ""
+
+#: options.h:624 options.h:629
+msgid "Compress .debug_* sections in the output file"
+msgstr ""
+
+#: options.h:630
+msgid "[none]"
+msgstr ""
+
+#: options.h:639
+msgid "Define common symbols"
+msgstr ""
+
+#: options.h:640
+msgid "Do not define common symbols"
+msgstr ""
+
+#: options.h:642 options.h:644
+msgid "Alias for -d"
+msgstr ""
+
+#: options.h:647
+msgid "Turn on debugging"
+msgstr ""
+
+#: options.h:648
+msgid "[all,files,script,task][,...]"
+msgstr ""
+
+#: options.h:651
+msgid "Define a symbol"
+msgstr ""
+
+#: options.h:651
+msgid "SYMBOL=EXPRESSION"
+msgstr ""
+
+#: options.h:654
+msgid "Demangle C++ symbols in log messages"
+msgstr ""
+
+#: options.h:658
+msgid "Do not demangle C++ symbols in log messages"
+msgstr ""
+
+#: options.h:662
+msgid "Try to detect violations of the One Definition Rule"
+msgstr ""
+
+#: options.h:666
+msgid "Delete all temporary local symbols"
+msgstr ""
+
+#: options.h:669
+msgid "Add data symbols to dynamic symbols"
+msgstr ""
+
+#: options.h:672
+msgid "Add C++ operator new/delete to dynamic symbols"
+msgstr ""
+
+#: options.h:675
+msgid "Add C++ typeinfo to dynamic symbols"
+msgstr ""
+
+#: options.h:678
+msgid "Read a list of dynamic symbols"
+msgstr ""
+
+#: options.h:678 options.h:732 options.h:766 options.h:893 options.h:921
+msgid "FILE"
+msgstr ""
+
+#: options.h:681
+msgid "Set program start address"
+msgstr ""
+
+#: options.h:681 options.h:908 options.h:910 options.h:912
+msgid "ADDRESS"
+msgstr ""
+
+#: options.h:684
+msgid "Exclude libraries from automatic export"
+msgstr ""
+
+#: options.h:688
+msgid "Export all dynamic symbols"
+msgstr ""
+
+#: options.h:689
+msgid "Do not export all dynamic symbols (default)"
+msgstr ""
+
+#: options.h:692
+msgid "Create exception frame header"
+msgstr ""
+
+#: options.h:695
+msgid "Treat warnings as errors"
+msgstr ""
+
+#: options.h:696
+msgid "Do not treat warnings as errors"
+msgstr ""
+
+#: options.h:699
+msgid "Call SYMBOL at unload-time"
+msgstr ""
+
+#: options.h:699 options.h:729 options.h:873 options.h:915 options.h:936
+#: options.h:939
+msgid "SYMBOL"
+msgstr ""
+
+#: options.h:702
+msgid "Set shared library name"
+msgstr ""
+
+#: options.h:702 options.h:792
+msgid "FILENAME"
+msgstr ""
+
+#: options.h:705
+msgid "Min fraction of empty buckets in dynamic hash"
+msgstr ""
+
+#: options.h:706
+msgid "FRACTION"
+msgstr ""
+
+#: options.h:709
+msgid "Dynamic hash style"
+msgstr ""
+
+#: options.h:709
+msgid "[sysv,gnu,both]"
+msgstr ""
+
+#: options.h:713
+msgid "Set dynamic linker path"
+msgstr ""
+
+#: options.h:713
+msgid "PROGRAM"
+msgstr ""
+
+#: options.h:716
+msgid "Work in progress; do not use"
+msgstr ""
+
+#: options.h:717
+msgid "Do a full build"
+msgstr ""
+
+#: options.h:720
+msgid "Assume files changed"
+msgstr ""
+
+#: options.h:723
+msgid "Assume files didn't change"
+msgstr ""
+
+#: options.h:726
+msgid "Use timestamps to check files (default)"
+msgstr ""
+
+#: options.h:729
+msgid "Call SYMBOL at load-time"
+msgstr ""
+
+#: options.h:732
+msgid "Read only symbol values from FILE"
+msgstr ""
+
+#: options.h:735
+msgid "Search for library LIBNAME"
+msgstr ""
+
+#: options.h:735
+msgid "LIBNAME"
+msgstr ""
+
+#: options.h:738
+msgid "Add directory to search path"
+msgstr ""
+
+#: options.h:738 options.h:813 options.h:816 options.h:820 options.h:887
+msgid "DIR"
+msgstr ""
+
+#: options.h:741
+msgid "Ignored for compatibility"
+msgstr ""
+
+#: options.h:741
+msgid "EMULATION"
+msgstr ""
+
+#: options.h:744
+msgid "Write map file on standard output"
+msgstr ""
+
+#: options.h:745
+msgid "Write map file"
+msgstr ""
+
+#: options.h:746
+msgid "MAPFILENAME"
+msgstr ""
+
+#: options.h:749
+msgid "Do not page align data"
+msgstr ""
+
+#: options.h:751
+msgid "Do not page align data, do not make text readonly"
+msgstr ""
+
+#: options.h:752
+msgid "Page align data, make text readonly"
+msgstr ""
+
+#: options.h:755
+msgid "Enable use of DT_RUNPATH and DT_FLAGS"
+msgstr ""
+
+#: options.h:756
+msgid "Disable use of DT_RUNPATH and DT_FLAGS"
+msgstr ""
+
+#: options.h:759
+msgid "Create an output file even if errors occur"
+msgstr ""
+
+#: options.h:762 options.h:958
+msgid "Report undefined symbols (even with --shared)"
+msgstr ""
+
+#: options.h:766
+msgid "Set output file name"
+msgstr ""
+
+#: options.h:769
+msgid "Optimize output file size"
+msgstr ""
+
+#: options.h:769
+msgid "LEVEL"
+msgstr ""
+
+#: options.h:772
+msgid "Set output format"
+msgstr ""
+
+#: options.h:772
+msgid "[binary]"
+msgstr ""
+
+#: options.h:775 options.h:777
+msgid "Create a position independent executable"
+msgstr ""
+
+#: options.h:782
+msgid "Load a plugin library"
+msgstr ""
+
+#: options.h:782
+msgid "PLUGIN"
+msgstr ""
+
+#: options.h:784
+msgid "Pass an option to the plugin"
+msgstr ""
+
+#: options.h:784
+msgid "OPTION"
+msgstr ""
+
+#: options.h:788
+msgid "Preread archive symbols when multi-threaded"
+msgstr ""
+
+#: options.h:791
+msgid "Print symbols defined and used for each input"
+msgstr ""
+
+#: options.h:795
+msgid "Ignored for SVR4 compatibility"
+msgstr ""
+
+#: options.h:798
+msgid "Generate relocations in output"
+msgstr ""
+
+#: options.h:801
+msgid "Generate relocatable output"
+msgstr ""
+
+#: options.h:804
+msgid "Relax branches on certain targets"
+msgstr ""
+
+#: options.h:807
+msgid "keep only symbols listed in this file"
+msgstr ""
+
+#: options.h:807
+msgid "[file]"
+msgstr ""
+
+#: options.h:813 options.h:816
+msgid "Add DIR to runtime search path"
+msgstr ""
+
+#: options.h:819
+msgid "Add DIR to link time shared library search path"
+msgstr ""
+
+#: options.h:823
+msgid "Strip all symbols"
+msgstr ""
+
+#: options.h:825
+msgid "Strip debugging information"
+msgstr ""
+
+#: options.h:827
+msgid "Emit only debug line number information"
+msgstr ""
+
+#: options.h:829
+msgid "Strip debug symbols that are unused by gdb (at least versions <= 6.7)"
+msgstr ""
+
+#: options.h:832
+msgid "Strip LTO intermediate code sections"
+msgstr ""
+
+#: options.h:835
+msgid ""
+"(ARM only) The maximum distance from instructions in a group of sections to "
+"their stubs. Negative values mean stubs are always after the group. 1 means "
+"using default size.\n"
+msgstr ""
+
+#: options.h:838 options.h:852 options.h:956 options.h:975
+msgid "SIZE"
+msgstr ""
+
+#: options.h:841
+msgid ""
+"Use less memory and more disk I/O (included only for compatibility with GNU "
+"ld)"
+msgstr ""
+
+#: options.h:845 options.h:848
+msgid "Generate shared library"
+msgstr ""
+
+#: options.h:851
+msgid "Stack size when -fsplit-stack function calls non-split"
+msgstr ""
+
+#: options.h:857
+msgid "Do not link against shared libraries"
+msgstr ""
+
+#: options.h:860
+msgid "Identical Code Folding. '--icf=safe' folds only ctors and dtors."
+msgstr ""
+
+#: options.h:866
+msgid "Number of iterations of ICF (default 2)"
+msgstr ""
+
+#: options.h:866 options.h:899 options.h:901 options.h:903 options.h:905
+msgid "COUNT"
+msgstr ""
+
+#: options.h:869
+msgid "List folded identical sections on stderr"
+msgstr ""
+
+#: options.h:870
+msgid "Do not list folded identical sections"
+msgstr ""
+
+#: options.h:873
+msgid "Do not fold this symbol during ICF"
+msgstr ""
+
+#: options.h:876
+msgid "Remove unused sections"
+msgstr ""
+
+#: options.h:877
+msgid "Don't remove unused sections (default)"
+msgstr ""
+
+#: options.h:880
+msgid "List removed unused sections on stderr"
+msgstr ""
+
+#: options.h:881
+msgid "Do not list removed unused sections"
+msgstr ""
+
+#: options.h:884
+msgid "Print resource usage statistics"
+msgstr ""
+
+#: options.h:887
+msgid "Set target system root directory"
+msgstr ""
+
+#: options.h:890
+msgid "Print the name of each input file"
+msgstr ""
+
+#: options.h:893
+msgid "Read linker script"
+msgstr ""
+
+#: options.h:896
+msgid "Run the linker multi-threaded"
+msgstr ""
+
+#: options.h:897
+msgid "Do not run the linker multi-threaded"
+msgstr ""
+
+#: options.h:899
+msgid "Number of threads to use"
+msgstr ""
+
+#: options.h:901
+msgid "Number of threads to use in initial pass"
+msgstr ""
+
+#: options.h:903
+msgid "Number of threads to use in middle pass"
+msgstr ""
+
+#: options.h:905
+msgid "Number of threads to use in final pass"
+msgstr ""
+
+#: options.h:908
+msgid "Set the address of the bss segment"
+msgstr ""
+
+#: options.h:910
+msgid "Set the address of the data segment"
+msgstr ""
+
+#: options.h:912
+msgid "Set the address of the text segment"
+msgstr ""
+
+#: options.h:915
+msgid "Create undefined reference to SYMBOL"
+msgstr ""
+
+#: options.h:918
+msgid "Synonym for --debug=files"
+msgstr ""
+
+#: options.h:921
+msgid "Read version script"
+msgstr ""
+
+#: options.h:924
+msgid "Warn about duplicate common symbols"
+msgstr ""
+
+#: options.h:925
+msgid "Do not warn about duplicate common symbols (default)"
+msgstr ""
+
+#: options.h:928
+msgid "Warn when skipping an incompatible library"
+msgstr ""
+
+#: options.h:929
+msgid "Don't warn when skipping an incompatible library"
+msgstr ""
+
+#: options.h:932
+msgid "Include all archive contents"
+msgstr ""
+
+#: options.h:933
+msgid "Include only needed archive contents"
+msgstr ""
+
+#: options.h:936
+msgid "Use wrapper functions for SYMBOL"
+msgstr ""
+
+#: options.h:939
+msgid "Trace references to symbol"
+msgstr ""
+
+#: options.h:942
+msgid "Default search path for Solaris compatibility"
+msgstr ""
+
+#: options.h:943
+msgid "PATH"
+msgstr ""
+
+#: options.h:946
+msgid "Start a library search group"
+msgstr ""
+
+#: options.h:948
+msgid "End a library search group"
+msgstr ""
+
+#: options.h:953
+msgid "Sort dynamic relocs"
+msgstr ""
+
+#: options.h:954
+msgid "Do not sort dynamic relocs"
+msgstr ""
+
+#: options.h:956
+msgid "Set common page size to SIZE"
+msgstr ""
+
+#: options.h:961
+msgid "Mark output as requiring executable stack"
+msgstr ""
+
+#: options.h:963
+msgid "Mark DSO to be initialized first at runtime"
+msgstr ""
+
+#: options.h:966
+msgid "Mark object to interpose all DSOs but executable"
+msgstr ""
+
+#: options.h:969
+msgid "Mark object for lazy runtime binding (default)"
+msgstr ""
+
+#: options.h:972
+msgid "Mark object requiring immediate process"
+msgstr ""
+
+#: options.h:975
+msgid "Set maximum page size to SIZE"
+msgstr ""
+
+#: options.h:978
+msgid "Do not create copy relocs"
+msgstr ""
+
+#: options.h:980
+msgid "Mark object not to use default search paths"
+msgstr ""
+
+#: options.h:983
+msgid "Mark DSO non-deletable at runtime"
+msgstr ""
+
+#: options.h:986
+msgid "Mark DSO not available to dlopen"
+msgstr ""
+
+#: options.h:989
+msgid "Mark DSO not available to dldump"
+msgstr ""
+
+#: options.h:992
+msgid "Mark output as not requiring executable stack"
+msgstr ""
+
+#: options.h:994
+msgid "Mark object for immediate function binding"
+msgstr ""
+
+#: options.h:997
+msgid "Mark DSO to indicate that needs immediate $ORIGIN processing at runtime"
+msgstr ""
+
+#: options.h:1000
+msgid "Where possible mark variables read-only after relocation"
+msgstr ""
+
+#: options.h:1001
+msgid "Don't mark variables read-only after relocation"
+msgstr ""
+
+#: output.cc:1132
+msgid "section group retained but group element discarded"
+msgstr ""
+
+#: output.cc:1860
+#, c-format
+msgid "invalid alignment %lu for section \"%s\""
+msgstr ""
+
+#: output.cc:3573
+#, c-format
+msgid "dot moves backward in linker script from 0x%llx to 0x%llx"
+msgstr ""
+
+#: output.cc:3576
+#, c-format
+msgid "address of section '%s' moves backward from 0x%llx to 0x%llx"
+msgstr ""
+
+#: output.cc:3755
+#, c-format
+msgid "nobits section %s may not precede progbits section %s in same segment"
+msgstr ""
+
+#: output.cc:3907 output.cc:3975
+#, c-format
+msgid "%s: open: %s"
+msgstr ""
+
+#: output.cc:3996
+#, c-format
+msgid "%s: mremap: %s"
+msgstr ""
+
+#: output.cc:4005
+#, c-format
+msgid "%s: mmap: %s"
+msgstr ""
+
+#: output.cc:4085
+#, c-format
+msgid "%s: mmap: failed to allocate %lu bytes for output file: %s"
+msgstr ""
+
+#: output.cc:4096
+#, c-format
+msgid "%s: munmap: %s"
+msgstr ""
+
+#: output.cc:4115
+#, c-format
+msgid "%s: write: unexpected 0 return-value"
+msgstr ""
+
+#: output.cc:4117
+#, c-format
+msgid "%s: write: %s"
+msgstr ""
+
+#: output.cc:4132
+#, c-format
+msgid "%s: close: %s"
+msgstr ""
+
+#: output.h:520
+msgid "** section headers"
+msgstr ""
+
+#: output.h:565
+msgid "** segment headers"
+msgstr ""
+
+#: output.h:613
+msgid "** file header"
+msgstr ""
+
+#: output.h:833
+msgid "** fill"
+msgstr ""
+
+#: output.h:987
+msgid "** string table"
+msgstr ""
+
+#: output.h:1300
+msgid "** dynamic relocs"
+msgstr ""
+
+#: output.h:1301 output.h:1637
+msgid "** relocs"
+msgstr ""
+
+#: output.h:1662
+msgid "** group"
+msgstr ""
+
+#: output.h:1774
+msgid "** GOT"
+msgstr ""
+
+#: output.h:1916
+msgid "** dynamic"
+msgstr ""
+
+#: output.h:2039
+msgid "** symtab xindex"
+msgstr ""
+
+#: parameters.cc:172
+#, c-format
+msgid "unrecognized output format %s"
+msgstr ""
+
+#: plugin.cc:106
+#, c-format
+msgid "%s: could not load plugin library"
+msgstr ""
+
+#: plugin.cc:116
+#, c-format
+msgid "%s: could not find onload entry point"
+msgstr ""
+
+#: plugin.cc:426
+msgid ""
+"Input files added by plug-ins in --incremental mode not supported yet.\n"
+msgstr ""
+
+#: powerpc.cc:1502 sparc.cc:2307 x86_64.cc:1632
+#, c-format
+msgid "%s: unsupported REL reloc section"
+msgstr ""
+
+#: readsyms.cc:191
+#, c-format
+msgid "%s: file is empty"
+msgstr ""
+
+#. Here we have to handle any other input file types we need.
+#: readsyms.cc:575
+#, c-format
+msgid "%s: not an object or archive"
+msgstr ""
+
+#: reduced_debug_output.cc:236
+msgid ""
+"Debug abbreviations extend beyond .debug_abbrev section; failed to reduce "
+"debug abbreviations"
+msgstr ""
+
+#: reduced_debug_output.cc:322
+msgid "Extremely large compile unit in debug info; failed to reduce debug info"
+msgstr ""
+
+#: reduced_debug_output.cc:330
+msgid ""
+"Debug info extends beyond .debug_info section;failed to reduce debug info"
+msgstr ""
+
+#: reduced_debug_output.cc:350 reduced_debug_output.cc:392
+msgid "Invalid DIE in debug info; failed to reduce debug info"
+msgstr ""
+
+#: reduced_debug_output.cc:373
+msgid ""
+"Debug info extends beyond .debug_info section; failed to reduce debug info"
+msgstr ""
+
+#: reloc.cc:297 reloc.cc:858
+#, c-format
+msgid "relocation section %u uses unexpected symbol table %u"
+msgstr ""
+
+#: reloc.cc:312 reloc.cc:875
+#, c-format
+msgid "unexpected entsize for reloc section %u: %lu != %u"
+msgstr ""
+
+#: reloc.cc:321 reloc.cc:884
+#, c-format
+msgid "reloc section %u size %lu uneven"
+msgstr ""
+
+#: reloc.cc:1203
+#, c-format
+msgid "could not convert call to '%s' to '%s'"
+msgstr ""
+
+#: reloc.cc:1343
+#, c-format
+msgid "reloc section size %zu is not a multiple of reloc size %d\n"
+msgstr ""
+
+#. We should only see externally visible symbols in the symbol
+#. table.
+#: resolve.cc:191
+msgid "invalid STB_LOCAL symbol in external symbols"
+msgstr ""
+
+#. Any target which wants to handle STB_LOOS, etc., needs to
+#. define a resolve method.
+#: resolve.cc:197
+msgid "unsupported symbol binding"
+msgstr ""
+
+#. A dynamic object cannot reference a hidden or internal symbol
+#. defined in another object.
+#: resolve.cc:266
+#, c-format
+msgid "%s symbol '%s' in %s is referenced by DSO %s"
+msgstr ""
+
+#: resolve.cc:326
+#, c-format
+msgid "common of '%s' overriding smaller common"
+msgstr ""
+
+#: resolve.cc:331
+#, c-format
+msgid "common of '%s' overidden by larger common"
+msgstr ""
+
+#: resolve.cc:336
+#, c-format
+msgid "multiple common of '%s'"
+msgstr ""
+
+#: resolve.cc:442
+#, c-format
+msgid "multiple definition of '%s'"
+msgstr ""
+
+#: resolve.cc:481
+#, c-format
+msgid "definition of '%s' overriding common"
+msgstr ""
+
+#: resolve.cc:516
+#, c-format
+msgid "definition of '%s' overriding dynamic common definition"
+msgstr ""
+
+#: resolve.cc:636
+#, c-format
+msgid "common '%s' overridden by previous definition"
+msgstr ""
+
+#: resolve.cc:766 resolve.cc:778
+msgid "command line"
+msgstr ""
+
+#: script-sections.cc:690
+msgid "dot may not move backward"
+msgstr ""
+
+#: script-sections.cc:757
+msgid "** expression"
+msgstr ""
+
+#: script-sections.cc:941
+msgid "fill value is not absolute"
+msgstr ""
+
+#: script-sections.cc:1913
+#, c-format
+msgid "alignment of section %s is not absolute"
+msgstr ""
+
+#: script-sections.cc:1957
+#, c-format
+msgid "subalign of section %s is not absolute"
+msgstr ""
+
+#: script-sections.cc:1972
+#, c-format
+msgid "fill of section %s is not absolute"
+msgstr ""
+
+#: script-sections.cc:2048
+msgid "SPECIAL constraints are not implemented"
+msgstr ""
+
+#: script-sections.cc:2090
+msgid "mismatched definition for constrained sections"
+msgstr ""
+
+#: script-sections.cc:2634
+msgid "DATA_SEGMENT_ALIGN may only appear once in a linker script"
+msgstr ""
+
+#: script-sections.cc:2649
+msgid "DATA_SEGMENT_RELRO_END may only appear once in a linker script"
+msgstr ""
+
+#: script-sections.cc:2654
+msgid "DATA_SEGMENT_RELRO_END must follow DATA_SEGMENT_ALIGN"
+msgstr ""
+
+#: script-sections.cc:2826
+msgid "no matching section constraint"
+msgstr ""
+
+#: script-sections.cc:3151
+msgid "TLS sections are not adjacent"
+msgstr ""
+
+#: script-sections.cc:3280
+msgid "allocated section not in any segment"
+msgstr ""
+
+#: script-sections.cc:3309
+#, c-format
+msgid "no segment %s"
+msgstr ""
+
+#: script-sections.cc:3323
+msgid "section in two PT_LOAD segments"
+msgstr ""
+
+#: script-sections.cc:3330
+msgid "allocated section not in any PT_LOAD segment"
+msgstr ""
+
+#: script-sections.cc:3358
+msgid "may only specify load address for PT_LOAD segment"
+msgstr ""
+
+#: script-sections.cc:3382
+#, c-format
+msgid "PHDRS load address overrides section %s load address"
+msgstr ""
+
+#. We could support this if we wanted to.
+#: script-sections.cc:3393
+msgid "using only one of FILEHDR and PHDRS is not currently supported"
+msgstr ""
+
+#: script-sections.cc:3408
+msgid ""
+"sections loaded on first page without room for file and program headers are "
+"not supported"
+msgstr ""
+
+#: script-sections.cc:3414
+msgid ""
+"using FILEHDR and PHDRS on more than one PT_LOAD segment is not currently "
+"supported"
+msgstr ""
+
+#: script.cc:1072
+msgid "invalid use of PROVIDE for dot symbol"
+msgstr ""
+
+#: script.cc:2132
+#, c-format
+msgid "%s:%d:%d: %s"
+msgstr ""
+
+#. There are some options that we could handle here--e.g.,
+#. -lLIBRARY. Should we bother?
+#: script.cc:2297
+#, c-format
+msgid ""
+"%s:%d:%d: ignoring command OPTION; OPTION is only valid for scripts "
+"specified via -T/--script"
+msgstr ""
+
+#: script.cc:2362
+#, c-format
+msgid ""
+"%s:%d:%d: ignoring SEARCH_DIR; SEARCH_DIR is only valid for scripts "
+"specified via -T/--script"
+msgstr ""
+
+#: script.cc:2606 script.cc:2620
+#, c-format
+msgid "%s:%d:%d: DATA_SEGMENT_ALIGN not in SECTIONS clause"
+msgstr ""
+
+#: script.cc:2739
+msgid "unknown PHDR type (try integer)"
+msgstr ""
+
+#: stringpool.cc:528
+#, c-format
+msgid "%s: %s entries: %zu; buckets: %zu\n"
+msgstr ""
+
+#: stringpool.cc:532
+#, c-format
+msgid "%s: %s entries: %zu\n"
+msgstr ""
+
+#: stringpool.cc:535
+#, c-format
+msgid "%s: %s Stringdata structures: %zu\n"
+msgstr ""
+
+#: symtab.cc:857
+#, c-format
+msgid "%s: reference to %s"
+msgstr ""
+
+#: symtab.cc:859
+#, c-format
+msgid "%s: definition of %s"
+msgstr ""
+
+#: symtab.cc:1052
+#, c-format
+msgid "bad global symbol name offset %u at %zu"
+msgstr ""
+
+#: symtab.cc:1278
+msgid "--just-symbols does not make sense with a shared object"
+msgstr ""
+
+#: symtab.cc:1284
+msgid "too few symbol versions"
+msgstr ""
+
+#: symtab.cc:1333
+#, c-format
+msgid "bad symbol name offset %u at %zu"
+msgstr ""
+
+#: symtab.cc:1396
+#, c-format
+msgid "versym for symbol %zu out of range: %u"
+msgstr ""
+
+#: symtab.cc:1404
+#, c-format
+msgid "versym for symbol %zu has no name: %u"
+msgstr ""
+
+#: symtab.cc:2549 symtab.cc:2681
+#, c-format
+msgid "%s: unsupported symbol section 0x%x"
+msgstr ""
+
+#: symtab.cc:2933
+#, c-format
+msgid "%s: symbol table entries: %zu; buckets: %zu\n"
+msgstr ""
+
+#: symtab.cc:2936
+#, c-format
+msgid "%s: symbol table entries: %zu\n"
+msgstr ""
+
+#: symtab.cc:3007
+#, c-format
+msgid ""
+"while linking %s: symbol '%s' defined in multiple places (possible ODR "
+"violation):"
+msgstr ""
+
+#: target-reloc.h:259
+msgid "relocation refers to discarded comdat section"
+msgstr ""
+
+#: target-reloc.h:298
+#, c-format
+msgid "reloc has bad offset %zu"
+msgstr ""
+
+#: target.cc:90
+#, c-format
+msgid "%s: unsupported ELF file type %d"
+msgstr ""
+
+#: target.cc:157
+#, c-format
+msgid "linker does not include stack split support required by %s"
+msgstr ""
+
+#: tls.h:59
+msgid "TLS relocation out of range"
+msgstr ""
+
+#: tls.h:73
+msgid "TLS relocation against invalid instruction"
+msgstr ""
+
+#. This output is intended to follow the GNU standards.
+#: version.cc:65
+#, c-format
+msgid "Copyright 2008 Free Software Foundation, Inc.\n"
+msgstr ""
+
+#: version.cc:66
+#, c-format
+msgid ""
+"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) a later "
+"version.\n"
+"This program has absolutely no warranty.\n"
+msgstr ""
+
+#: workqueue-threads.cc:106
+#, c-format
+msgid "%s failed: %s"
+msgstr ""
+
+#: x86_64.cc:2184
+#, c-format
+msgid "unsupported reloc type %u"
+msgstr ""
+
+#: x86_64.cc:2524
+#, c-format
+msgid "unsupported reloc %u against local symbol"
+msgstr ""
diff --git a/binutils-2.25/gold/po/id.po b/binutils-2.25/gold/po/id.po
new file mode 100644
index 00000000..1c3b45f5
--- /dev/null
+++ b/binutils-2.25/gold/po/id.po
@@ -0,0 +1,1867 @@
+# Pesan bahasa indonesia untuk gold.
+# Copyright (C) 2009 Free Software Foundation, Inc.
+# This file is distributed under the same license as the binutils package.
+# Arif E. Nugroho <arif_endro@yahoo.com>, 2009.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gold 2.19.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-09 17:16+0930\n"
+"PO-Revision-Date: 2009-05-26 08:00+0700\n"
+"Last-Translator: Arif E. Nugroho <arif_endro@yahoo.com>\n"
+"Language-Team: Indonesian <translation-team-id@lists.sourceforge.net>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: archive.cc:107
+#, c-format
+msgid "%s: no archive symbol table (run ranlib)"
+msgstr "%s: tidak ada kumpulan tabel simbol (jalankan ranlib)"
+
+#: archive.cc:189
+#, c-format
+msgid "%s: bad archive symbol table names"
+msgstr "%s: nama kumpulan tabel simbol buruk"
+
+#: archive.cc:221
+#, c-format
+msgid "%s: malformed archive header at %zu"
+msgstr "%s: kumpulan kepala salah bentuk di %zu"
+
+#: archive.cc:241
+#, c-format
+msgid "%s: malformed archive header size at %zu"
+msgstr "%s: ukuran kepala kumpulan salah bentuk di %zu"
+
+#: archive.cc:252
+#, c-format
+msgid "%s: malformed archive header name at %zu"
+msgstr "%s: salah bentuk nama kepala kumpulan di %zu"
+
+#: archive.cc:282
+#, c-format
+msgid "%s: bad extended name index at %zu"
+msgstr "%s: nama indeks extensi buruk di %zu"
+
+#: archive.cc:292
+#, c-format
+msgid "%s: bad extended name entry at header %zu"
+msgstr "%s: nama masukan ekstensi buruk di kepala %zu"
+
+#: archive.cc:389
+#, c-format
+msgid "%s: short archive header at %zu"
+msgstr "%s: kumpulan kepala pendek di %zu"
+
+#: archive.cc:530 archive.cc:545
+#, c-format
+msgid "%s: member at %zu is not an ELF object"
+msgstr "%s: anggota di %zu bukan sebuah objek ELF"
+
+#: archive.cc:775
+#, c-format
+msgid "%s: archive libraries: %u\n"
+msgstr "%s: kumpulan perpustakaan: %u\n"
+
+#: archive.cc:777
+#, c-format
+msgid "%s: total archive members: %u\n"
+msgstr "%s: jumlah total kumpulan: %u\n"
+
+#: archive.cc:779
+#, c-format
+msgid "%s: loaded archive members: %u\n"
+msgstr "%s: dimuat anggota kumpulan: %u\n"
+
+#: binary.cc:129
+#, c-format
+msgid "cannot open %s: %s:"
+msgstr "tidak dapat membuka %s: %s:"
+
+#: compressed_output.cc:128
+msgid "not compressing section data: zlib error"
+msgstr "tidak mengkompress bagian data: zlib error"
+
+#: cref.cc:244
+#, c-format
+msgid "cannot open symbol count file %s: %s"
+msgstr "tidak dapat membuka jumlah berkas simbol %s: %s"
+
+#: descriptors.cc:94
+#, c-format
+msgid "file %s was removed during the link"
+msgstr "berkas %s telah dihapus ketika penyambungan"
+
+#: descriptors.cc:133
+msgid "out of file descriptors and couldn't close any"
+msgstr "diluar dari berkas deskripsi dan tidak dapat menutup apapun"
+
+#: descriptors.cc:154 descriptors.cc:189
+#, c-format
+msgid "while closing %s: %s"
+msgstr "ketika menutup %s: %s"
+
+#: dirsearch.cc:71
+#, c-format
+msgid "%s: can not read directory: %s"
+msgstr "%s: tidak dapat membaca direktori: %s"
+
+#: dwarf_reader.cc:53 dwarf_reader.cc:84
+msgid "Unusually large LEB128 decoded, debug information may be corrupted"
+msgstr "Besar LEB128 terurai tidak biasa, informasi penelusuran mungkin telah terkorupsi"
+
+#: dynobj.cc:169
+#, c-format
+msgid "unexpected duplicate type %u section: %u, %u"
+msgstr "tidak terduga duplikasi daerah tipe %u: %u, %u"
+
+#: dynobj.cc:205
+#, c-format
+msgid "unexpected link in section %u header: %u != %u"
+msgstr "tidak terduga sambungan dalam daerah %u kepala: %u != %u"
+
+#: dynobj.cc:241
+#, c-format
+msgid "DYNAMIC section %u link out of range: %u"
+msgstr "daerah DINAMIS %u sambungan diluar dari jangkauan: %u"
+
+#: dynobj.cc:249
+#, c-format
+msgid "DYNAMIC section %u link %u is not a strtab"
+msgstr "daerah DINAMIS %u sambungan %u bukan sebuah a strtab"
+
+#: dynobj.cc:278
+#, c-format
+msgid "DT_SONAME value out of range: %lld >= %lld"
+msgstr "DT_SONAME nilai diluar dari jangkauan: %lld >= %lld"
+
+#: dynobj.cc:290
+#, c-format
+msgid "DT_NEEDED value out of range: %lld >= %lld"
+msgstr "DT_NEEDED nilai diluar dari jangkauan: %lld >= %lld"
+
+#: dynobj.cc:303
+msgid "missing DT_NULL in dynamic segment"
+msgstr "hilang DT_NULL dalam bagian dinamis"
+
+#: dynobj.cc:349
+#, c-format
+msgid "invalid dynamic symbol table name index: %u"
+msgstr "nama indeks table simbol dinamis tidak valid: %u"
+
+#: dynobj.cc:356
+#, c-format
+msgid "dynamic symbol table name section has wrong type: %u"
+msgstr "nama daerah tabel simbol dinamis memiliki tipe salah: %u"
+
+#: dynobj.cc:443 object.cc:376 object.cc:884
+#, c-format
+msgid "bad section name offset for section %u: %lu"
+msgstr "nama daerah ofset buruk untuk daerah %u: %lu"
+
+#: dynobj.cc:472
+#, c-format
+msgid "duplicate definition for version %u"
+msgstr "duplikasi definisi untuk versi %u"
+
+#: dynobj.cc:501
+#, c-format
+msgid "unexpected verdef version %u"
+msgstr "tidak terduga verdef versi %u"
+
+#: dynobj.cc:517
+#, c-format
+msgid "verdef vd_cnt field too small: %u"
+msgstr "verdef vd_cnt daerah terlalu kecil: %u"
+
+#: dynobj.cc:525
+#, c-format
+msgid "verdef vd_aux field out of range: %u"
+msgstr "daerah verdef vd_aux diluar dari jangkauan: %u"
+
+#: dynobj.cc:536
+#, c-format
+msgid "verdaux vda_name field out of range: %u"
+msgstr "daerah verdaux vda_name diluar dari jangkauan: %u"
+
+#: dynobj.cc:546
+#, c-format
+msgid "verdef vd_next field out of range: %u"
+msgstr "daerah verdef vd_next diluar dari jangkauan: %u"
+
+#: dynobj.cc:580
+#, c-format
+msgid "unexpected verneed version %u"
+msgstr "tidak terduga versi verneed %u"
+
+#: dynobj.cc:589
+#, c-format
+msgid "verneed vn_aux field out of range: %u"
+msgstr "daerah verneed vn_aux diluar dari jangkauan: %u"
+
+#: dynobj.cc:603
+#, c-format
+msgid "vernaux vna_name field out of range: %u"
+msgstr "daerah vernaux vna_name diluar dari jangkauan: %u"
+
+#: dynobj.cc:614
+#, c-format
+msgid "verneed vna_next field out of range: %u"
+msgstr "daerah verneed vna_next diluar dari jangkauan: %u"
+
+#: dynobj.cc:625
+#, c-format
+msgid "verneed vn_next field out of range: %u"
+msgstr "daerah verneed vn_next diluar dari jangkauan: %u"
+
+#: dynobj.cc:673
+msgid "size of dynamic symbols is not multiple of symbol size"
+msgstr "ukuran dari simbol dinamis bukan kelipatan dari ukuran simbol"
+
+#: dynobj.cc:1425
+#, c-format
+msgid "symbol %s has undefined version %s"
+msgstr "simbol %s memiliki versi %s tidak terdefinisi"
+
+#: ehframe.h:82
+msgid "** eh_frame_hdr"
+msgstr "** eh_frame_hdr"
+
+#: ehframe.h:353
+msgid "** eh_frame"
+msgstr "** eh_frame"
+
+#: errors.cc:106
+#, c-format
+msgid "%s: warning: "
+msgstr "%s: peringatan: "
+
+#: errors.cc:146
+#, c-format
+msgid "%s: %s: warning: "
+msgstr "%s: %s: peringatan: "
+
+#: errors.cc:172
+#, c-format
+msgid "%s: %s: undefined reference to '%s'\n"
+msgstr "%s: %s: referensi tidak terdefinisi ke '%s'\n"
+
+#: errors.cc:176
+#, c-format
+msgid "%s: %s: undefined reference to '%s', version '%s'\n"
+msgstr "%s: %s: referensi ke '%s' tidak terdefinisi, versi '%s'\n"
+
+#: errors.cc:186
+#, c-format
+msgid "%s: "
+msgstr "%s: "
+
+#: expression.cc:172
+#, c-format
+msgid "undefined symbol '%s' referenced in expression"
+msgstr "simbol '%s' tidak terdefinisi direferensikan dalam ekspresi"
+
+#: expression.cc:209
+msgid "invalid reference to dot symbol outside of SECTIONS clause"
+msgstr "referensi tidak valid ke dot symbol diluar dari SECTIONS clause"
+
+#. Handle unary operators. We use a preprocessor macro as a hack to
+#. capture the C operator.
+#: expression.cc:278
+msgid "unary "
+msgstr "unary "
+
+#: expression.cc:278 expression.cc:400
+msgid " applied to section relative value"
+msgstr " diaplikasikan ke daerah nilai relatif"
+
+#. 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.
+#: expression.cc:400
+msgid "binary "
+msgstr "binari "
+
+#: expression.cc:404
+msgid " by zero"
+msgstr " dengan nol"
+
+#: expression.cc:575
+msgid "max applied to section relative value"
+msgstr "maks diaplikasikan ke daerah nilai relatif"
+
+#: expression.cc:610
+msgid "min applied to section relative value"
+msgstr "min diaplikasikan ke daerah nilai relatif"
+
+#: expression.cc:740
+msgid "aligning to section relative value"
+msgstr "menyesuaikan ke daerah nilai relatif"
+
+#: expression.cc:895
+#, c-format
+msgid "unknown constant %s"
+msgstr "konstanta %s tidak diketahui"
+
+#: expression.cc:1126
+msgid "SEGMENT_START not implemented"
+msgstr "SEGMENT_START tidak diimplementasikan"
+
+#: expression.cc:1135
+msgid "ORIGIN not implemented"
+msgstr "ORIGIN tidak diimplementasikan"
+
+#: expression.cc:1141
+msgid "LENGTH not implemented"
+msgstr "LENGTH tidak diimplementasikan"
+
+#: fileread.cc:55
+#, c-format
+msgid "munmap failed: %s"
+msgstr "munmap gagal: %s"
+
+#: fileread.cc:119
+#, c-format
+msgid "%s: fstat failed: %s"
+msgstr "%s: fstat gagal: %s"
+
+#: fileread.cc:159
+#, c-format
+msgid "could not reopen file %s"
+msgstr "tidak dapat membuka kembali berkas %s"
+
+#: fileread.cc:292
+#, c-format
+msgid "%s: pread failed: %s"
+msgstr "%s: pread gagal: %s"
+
+#: fileread.cc:298
+#, c-format
+msgid "%s: file too short: read only %lld of %lld bytes at %lld"
+msgstr "%s: berkas terlalu pendek: hanya membaca %lld dari %lld byte di %lld"
+
+#: fileread.cc:382
+#, c-format
+msgid "%s: mmap offset %lld size %lld failed: %s"
+msgstr "%s: mmap ofset %lld ukuran %lld gagal: %s"
+
+#: fileread.cc:528
+#, c-format
+msgid "%s: lseek failed: %s"
+msgstr "%s: lseek gagal: %s"
+
+#: fileread.cc:534
+#, c-format
+msgid "%s: readv failed: %s"
+msgstr "%s: readv gagal: %s"
+
+#: fileread.cc:537
+#, c-format
+msgid "%s: file too short: read only %zd of %zd bytes at %lld"
+msgstr "%s: berkas terlalu pendek: hanya membaca %zd dari %zd byte di %lld"
+
+#: fileread.cc:686
+#, c-format
+msgid "%s: total bytes mapped for read: %llu\n"
+msgstr "%s: total byte dipetakan untuk pembacaan: %llu\n"
+
+#: fileread.cc:688
+#, c-format
+msgid "%s: maximum bytes mapped for read at one time: %llu\n"
+msgstr "%s: jumlah maksimal byte dipetakan untuk pembacaan di setiap waktu: %llu\n"
+
+#: fileread.cc:783
+#, c-format
+msgid "cannot find -l%s"
+msgstr "tidak dapat menemukan -l%s"
+
+#: fileread.cc:810
+#, c-format
+msgid "cannot find %s"
+msgstr "tidak dapat menemukan %s"
+
+#: fileread.cc:833
+#, c-format
+msgid "cannot open %s: %s"
+msgstr "tidak dapat membuka %s: %s"
+
+#: gold-threads.cc:103
+#, c-format
+msgid "pthead_mutextattr_init failed: %s"
+msgstr "pthead_mutextattr_init gagal: %s"
+
+#: gold-threads.cc:107
+#, c-format
+msgid "pthread_mutextattr_settype failed: %s"
+msgstr "pthread_mutextattr_settype gagal: %s"
+
+#: gold-threads.cc:112
+#, c-format
+msgid "pthread_mutex_init failed: %s"
+msgstr "pthread_mutex_init gagal: %s"
+
+#: gold-threads.cc:116
+#, c-format
+msgid "pthread_mutexattr_destroy failed: %s"
+msgstr "pthread_mutexattr_destroy gagal: %s"
+
+#: gold-threads.cc:123
+#, c-format
+msgid "pthread_mutex_destroy failed: %s"
+msgstr "pthread_mutex_destroy gagal: %s"
+
+#: gold-threads.cc:131
+#, c-format
+msgid "pthread_mutex_lock failed: %s"
+msgstr "pthread_mutex_lock gagal: %s"
+
+#: gold-threads.cc:139
+#, c-format
+msgid "pthread_mutex_unlock failed: %s"
+msgstr "pthread_mutex_unlock gagal: %s"
+
+#: gold-threads.cc:220
+#, c-format
+msgid "pthread_cond_init failed: %s"
+msgstr "pthread_cond_init gagal: %s"
+
+#: gold-threads.cc:227
+#, c-format
+msgid "pthread_cond_destroy failed: %s"
+msgstr "pthread_cond_destroy gagal: %s"
+
+#: gold-threads.cc:236
+#, c-format
+msgid "pthread_cond_wait failed: %s"
+msgstr "pthread_cond_wait gagal: %s"
+
+#: gold-threads.cc:244
+#, c-format
+msgid "pthread_cond_signal failed: %s"
+msgstr "pthread_cond_signal gagal: %s"
+
+#: gold-threads.cc:252
+#, c-format
+msgid "pthread_cond_broadcast failed: %s"
+msgstr "pthread_cond_broadcast gagal: %s"
+
+#: gold.cc:83
+#, c-format
+msgid "%s: internal error in %s, at %s:%d\n"
+msgstr "%s: kerusakan internal dalam %s, di %s:%d\n"
+
+#: gold.cc:130
+msgid "no input files"
+msgstr "tidak ada berkas masukan"
+
+#. We print out just the first .so we see; there may be others.
+#: gold.cc:195
+#, c-format
+msgid "cannot mix -static with dynamic object %s"
+msgstr "tidak dapat mencampurkan -static dengan objek dinamis %s"
+
+#: gold.cc:199
+#, c-format
+msgid "cannot mix -r with dynamic object %s"
+msgstr "tidak dapat mencampurkan -r dengan objek dinamis %s"
+
+#: gold.cc:203
+#, c-format
+msgid "cannot use non-ELF output format with dynamic object %s"
+msgstr "tidak dapat menggunakan format keluaran bukan ELF dengan objek dinamis %s"
+
+#. FIXME: This needs to specify the location somehow.
+#: i386.cc:193 i386.cc:1588 sparc.cc:211 sparc.cc:2322 x86_64.cc:208
+#: x86_64.cc:1656
+msgid "missing expected TLS relocation"
+msgstr "hilang relokasi TLS yang diduga"
+
+#: i386.cc:503 sparc.cc:1066 x86_64.cc:533
+msgid "** PLT"
+msgstr "** PLT"
+
+#: i386.cc:843 powerpc.cc:996 sparc.cc:1480 x86_64.cc:921 x86_64.cc:1230
+#, c-format
+msgid "%s: unsupported reloc %u against local symbol"
+msgstr "%s: tidak didukung relokasi %u terhadap simbol lokal"
+
+#: i386.cc:907 x86_64.cc:1033
+#, c-format
+msgid "section symbol %u has bad shndx %u"
+msgstr "daerah simbol %u memiliki shndx buruk %u"
+
+#: i386.cc:965 i386.cc:1297 powerpc.cc:1204 powerpc.cc:1413 sparc.cc:1852
+#: sparc.cc:2204 x86_64.cc:1110 x86_64.cc:1418
+#, c-format
+msgid "%s: unexpected reloc %u in object file"
+msgstr "%s: tidak terduga relokasi %u dalam berkas objek"
+
+#: i386.cc:999 i386.cc:1023 sparc.cc:1753 x86_64.cc:1141 x86_64.cc:1169
+#, c-format
+msgid "local symbol %u has bad shndx %u"
+msgstr "lokal simbol %u memiliki shndx buruk %u"
+
+#: i386.cc:1134 powerpc.cc:1223 sparc.cc:1871 x86_64.cc:1244 x86_64.cc:1536
+#, c-format
+msgid "%s: unsupported reloc %u against global symbol %s"
+msgstr "%s: tidak didukung relokasi %u terhadap simbol global %s"
+
+#: i386.cc:1473
+#, c-format
+msgid "%s: unsupported RELA reloc section"
+msgstr "%s: tidak didukung daerah relokasi RELA"
+
+#: i386.cc:1735 i386.cc:2429 powerpc.cc:1740 sparc.cc:2637 x86_64.cc:1859
+#: x86_64.cc:2435
+#, c-format
+msgid "unexpected reloc %u in object file"
+msgstr "tidak diduga relokasi %u dalam berkas objek"
+
+#: i386.cc:1767 i386.cc:1846 i386.cc:1898 i386.cc:1929 i386.cc:1986
+#: powerpc.cc:1746 sparc.cc:2643 sparc.cc:2826 sparc.cc:2887 sparc.cc:2994
+#: x86_64.cc:1880 x86_64.cc:1963 x86_64.cc:2018 x86_64.cc:2043
+#, c-format
+msgid "unsupported reloc %u"
+msgstr "tidak diduga relokasi %u"
+
+#: i386.cc:1906
+msgid "both SUN and GNU model TLS relocations"
+msgstr "baik model relokasi TLS SUN dan GNU"
+
+#: i386.cc:2443
+#, c-format
+msgid "unsupported reloc %u in object file"
+msgstr "tidak diduga relokasi %u dalam berkas objek"
+
+#: layout.cc:1511
+#, c-format
+msgid "--build-id=uuid failed: could not open /dev/urandom: %s"
+msgstr "--build-id=uuid gagal: tidak dapat membuka /dev/urandom: %s"
+
+#: layout.cc:1518
+#, c-format
+msgid "/dev/urandom: read failed: %s"
+msgstr "/dev/urandom: pembacaan gagal: %s"
+
+#: layout.cc:1520
+#, c-format
+msgid "/dev/urandom: expected %zu bytes, got %zd bytes"
+msgstr "/dev/urandom: tidak terduga %zu byte, diperoleh %zd byte"
+
+#: layout.cc:1542
+#, c-format
+msgid "--build-id argument '%s' not a valid hex number"
+msgstr "--build-id argumen '%s' bukan sebuah nomor heksa yang valid"
+
+#: layout.cc:1548
+#, c-format
+msgid "unrecognized --build-id argument '%s'"
+msgstr "tidak dikenal argumen --build-id '%s'"
+
+#: layout.cc:1866
+#, c-format
+msgid "load segment overlap [0x%llx -> 0x%llx] and [0x%llx -> 0x%llx]"
+msgstr "daerah pemuatan saling tumpang tindih [0x%llx -> 0x%llx] dan [0x%llx -> 0x%llx]"
+
+#: mapfile.cc:70
+#, c-format
+msgid "cannot open map file %s: %s"
+msgstr "tidak dapat membuka berkas peta %s: %s"
+
+#: mapfile.cc:84
+#, c-format
+msgid "cannot close map file: %s"
+msgstr "tidak dapat menutup berkas peta: %s"
+
+#: mapfile.cc:116
+#, c-format
+msgid ""
+"Archive member included because of file (symbol)\n"
+"\n"
+msgstr ""
+"Kumpulan anggota dimasukan karena berkas (simbol)\n"
+"\n"
+
+#: mapfile.cc:159
+#, c-format
+msgid ""
+"\n"
+"Allocating common symbols\n"
+msgstr ""
+"\n"
+"Mengalokasikan simbol umum\n"
+
+#: mapfile.cc:161
+#, c-format
+msgid ""
+"Common symbol size file\n"
+"\n"
+msgstr ""
+"Simbol umum ukuran berkas\n"
+"\n"
+
+#: mapfile.cc:195
+#, c-format
+msgid ""
+"\n"
+"Memory map\n"
+"\n"
+msgstr ""
+"\n"
+"Peta memori\n"
+"\n"
+
+#: mapfile.cc:361
+#, c-format
+msgid ""
+"\n"
+"Discarded input sections\n"
+"\n"
+msgstr ""
+"\n"
+"Mengabaikan daerah masukan\n"
+"\n"
+
+#: merge.cc:449
+#, c-format
+msgid "%s: %s merged constants size: %lu; input: %zu; output: %zu\n"
+msgstr "%s: %s gabungan ukuran konstanta: %lu; masukan: %zu; keluaran: %zu\n"
+
+#: merge.cc:472
+msgid "mergeable string section length not multiple of character size"
+msgstr "panjang daerah string dapat digabungkan bukan kelipatan dari besar karakter"
+
+#: merge.cc:488
+msgid "entry in mergeable string section not null terminated"
+msgstr "masukan dalam daerah string yang dapat digabungkan bukan diakhiri kosong"
+
+#: merge.cc:605
+#, c-format
+msgid "%s: %s input: %zu\n"
+msgstr "%s: %s masukan: %zu\n"
+
+#: merge.h:289
+msgid "** merge constants"
+msgstr "** gabungan konstanta"
+
+#: merge.h:411
+msgid "** merge strings"
+msgstr "** gabungan strings"
+
+#: object.cc:73
+msgid "missing SHT_SYMTAB_SHNDX section"
+msgstr "hilang daerah SHT_SYMTAB_SHNDX"
+
+#: object.cc:117
+#, c-format
+msgid "symbol %u out of range for SHT_SYMTAB_SHNDX section"
+msgstr "simbol %u diluar dari jangkauan untuk daerah SHT_SYMTAB_SHNDX"
+
+#: object.cc:124
+#, c-format
+msgid "extended index for symbol %u out of range: %u"
+msgstr "indeks ekstensi untuk simbol %u diluar dari jangkauan: %u"
+
+#: object.cc:141
+#, c-format
+msgid "%s: unsupported ELF machine number %d"
+msgstr "%s: tidak didukung nomor mesin ELF %d"
+
+#: object.cc:159
+#, c-format
+msgid "%s: %s"
+msgstr "%s: %s"
+
+#: object.cc:196
+#, c-format
+msgid "section name section has wrong type: %u"
+msgstr "nama daerah nama memiliki tipe salah: %u"
+
+#: object.cc:459
+#, c-format
+msgid "invalid symbol table name index: %u"
+msgstr "nama indeks tabel simbol tidak valid: %u"
+
+#: object.cc:465
+#, c-format
+msgid "symbol table name section has wrong type: %u"
+msgstr "nama daerah tabel simbol memiliki tipe salah: %u"
+
+#: object.cc:554
+#, c-format
+msgid "section group %u info %u out of range"
+msgstr "nama grup %u info %u diluar dari jangkauan"
+
+#: object.cc:573
+#, c-format
+msgid "symbol %u name offset %u out of range"
+msgstr "simbol %u nama ofset %u diluar dari jangkauan"
+
+#: object.cc:591
+#, c-format
+msgid "symbol %u invalid section index %u"
+msgstr "simbol %u tidak valid daerah indeks %u"
+
+#: object.cc:644
+#, c-format
+msgid "section %u in section group %u out of range"
+msgstr "daerah %u dalam daerah grup %u diluar dari jangkauan"
+
+#: object.cc:652
+#, c-format
+msgid "invalid section group %u refers to earlier section %u"
+msgstr "tidak valid daerah grup %u mereferensikan ke daerah sebelumnya %u"
+
+#: object.cc:827 reloc.cc:215 reloc.cc:723
+#, c-format
+msgid "relocation section %u has bad info %u"
+msgstr "relokasi daerah %u memiliki info %u buruk"
+
+#: object.cc:1080
+msgid "size of symbols is not multiple of symbol size"
+msgstr "ukuran dari simbol bukan kelipatan dari ukuran simbol"
+
+#: object.cc:1187
+#, c-format
+msgid "local symbol %u section name out of range: %u >= %u"
+msgstr "simbol lokal %u nama daerah diluar dari jangkauan: %u >= %u"
+
+#: object.cc:1245
+#, c-format
+msgid "unknown section index %u for local symbol %u"
+msgstr "daerah indeks %u tidak diketahui untuk simbol lokal %u"
+
+#: object.cc:1254
+#, c-format
+msgid "local symbol %u section index %u out of range"
+msgstr "lokal simbol %u daerah indeks %u diluar dari daerah"
+
+#: object.cc:1619
+msgid "incompatible target"
+msgstr "target tidak kompatibel"
+
+#: object.cc:1816
+#, c-format
+msgid "%s: unsupported ELF file type %d"
+msgstr "%s: tipe berkas ELF %d tidak didukung"
+
+#: object.cc:1835 object.cc:1881 object.cc:1915
+#, c-format
+msgid "%s: ELF file too short"
+msgstr "%s: berkas ELF terlalu pendek"
+
+#: object.cc:1843
+#, c-format
+msgid "%s: invalid ELF version 0"
+msgstr "%s: versi ELF 0 tidak valid"
+
+#: object.cc:1845
+#, c-format
+msgid "%s: unsupported ELF version %d"
+msgstr "%s: versi %d ELF tidak didukung"
+
+#: object.cc:1852
+#, c-format
+msgid "%s: invalid ELF class 0"
+msgstr "%s: ELF kelas 0 tidak valid"
+
+#: object.cc:1858
+#, c-format
+msgid "%s: unsupported ELF class %d"
+msgstr "%s: ELF kelas %d tidak didukung"
+
+#: object.cc:1865
+#, c-format
+msgid "%s: invalid ELF data encoding"
+msgstr "%s: pengkodean data ELF tidak valid"
+
+#: object.cc:1871
+#, c-format
+msgid "%s: unsupported ELF data encoding %d"
+msgstr "%s: pengkodean data ELF %d tidak didukung"
+
+#: object.cc:1891
+#, c-format
+msgid "%s: not configured to support 32-bit big-endian object"
+msgstr "%s: tidak dikonfigurasikan untuk mendukung objek 32-bit big-endian"
+
+#: object.cc:1904
+#, c-format
+msgid "%s: not configured to support 32-bit little-endian object"
+msgstr "%s: tidak dikonfigurasikan untuk mendukung objek 32-bit little-endian"
+
+#: object.cc:1925
+#, c-format
+msgid "%s: not configured to support 64-bit big-endian object"
+msgstr "%s: tidak dikonfigurasikan untuk mendukung objek 64-bit big-endian"
+
+#: object.cc:1938
+#, c-format
+msgid "%s: not configured to support 64-bit little-endian object"
+msgstr "%s: tidak dikonfigurasikan untuk mendukung objek 64-bit little-endian"
+
+#: options.cc:142
+#, c-format
+msgid ""
+"Usage: %s [options] file...\n"
+"Options:\n"
+msgstr ""
+"Penggunaan: %s [pilihan] berkas...\n"
+"Pilihan:\n"
+
+#. config.guess and libtool.m4 look in ld --help output for the
+#. string "supported targets".
+#: options.cc:150
+#, c-format
+msgid "%s: supported targets:"
+msgstr "%s: target yang didukung:"
+
+#: options.cc:162
+#, c-format
+msgid "Report bugs to %s\n"
+msgstr "Laporkan bugs ke %s\n"
+
+#: options.cc:179 options.cc:189
+#, c-format
+msgid "%s: invalid option value (expected an integer): %s"
+msgstr "%s: nilai pilihan tidak valid (diduga sebuah bilangan bulat): %s"
+
+#: options.cc:199
+#, c-format
+msgid "%s: invalid option value (expected a floating point number): %s"
+msgstr "%s: nilai pilihan tidak valid (diduga sebuah bilangan pecahan): %s"
+
+#: options.cc:208
+#, c-format
+msgid "%s: must take a non-empty argument"
+msgstr "%s: harus mengambil sebuah argumen tidak kosong"
+
+#: options.cc:249
+#, c-format
+msgid "%s: must take one of the following arguments: %s"
+msgstr "%s: harus mengambil salah satu dari argumen berikut: %s"
+
+#: options.cc:275
+#, c-format
+msgid " Supported targets:\n"
+msgstr " Target yang didukung:\n"
+
+#: options.cc:329
+#, c-format
+msgid "unable to parse script file %s"
+msgstr "tidak dapat mengambil berkas script %s"
+
+#: options.cc:337
+#, c-format
+msgid "unable to parse version script file %s"
+msgstr "tidak dapat mengambil berkas script versi %s"
+
+#: options.cc:363
+#, c-format
+msgid "%s: use the --help option for usage information\n"
+msgstr "%s: gunakan pilihan --help untuk informasi penggunaan\n"
+
+#: options.cc:372
+#, c-format
+msgid "%s: %s: %s\n"
+msgstr "%s: %s: %s\n"
+
+#: options.cc:393
+#, c-format
+msgid "format '%s' not supported; treating as elf (supported formats: elf, binary)"
+msgstr "format '%s' tidak didukung; memperlakukan sebagai elf (format yang didukung: elf, binari)"
+
+#: options.cc:499
+msgid "unexpected argument"
+msgstr "argumen tidak diduga"
+
+#: options.cc:512 options.cc:573
+msgid "missing argument"
+msgstr "hilang argumen"
+
+#: options.cc:584
+msgid "unknown -z option"
+msgstr "pilihan -z tidak diketahui"
+
+#: options.cc:727
+#, c-format
+msgid "ignoring --threads: %s was compiled without thread support"
+msgstr "mengabaikan --threads: %s telah dikompilasi tanpa dukungan thread"
+
+#: options.cc:734
+#, c-format
+msgid "ignoring --thread-count: %s was compiled without thread support"
+msgstr "mengabaikan --thread-count: %s telah dikompilasi tanpa bantuah thread"
+
+#: options.cc:776
+msgid "-shared and -r are incompatible"
+msgstr "-shared dan -r tidak kompatibel"
+
+#: options.cc:780
+msgid "binary output format not compatible with -shared or -r"
+msgstr "format keluaran binari tidak kompatibel dengan -shared atau -r"
+
+#: options.cc:785
+#, c-format
+msgid "--hash-bucket-empty-fraction value %g out of range [0.0, 1.0)"
+msgstr "nilai --hash-bucket-empty-fraction %g diluar dari jangkauan [0.0, 1.0]"
+
+#: options.cc:852
+msgid "May not nest groups"
+msgstr "Mungkin bukan grups nest"
+
+#: options.cc:864
+msgid "Group end without group start"
+msgstr "Grup berakhir tanpa awal grup"
+
+#. I guess it's neither a long option nor a short option.
+#: options.cc:922
+msgid "unknown option"
+msgstr "pilihan tidak diketahui"
+
+#: options.cc:948
+#, c-format
+msgid "%s: missing group end\n"
+msgstr "%s: hilang grup akhir\n"
+
+#: options.h:536
+msgid "Report usage information"
+msgstr "Laporan informasi penggunaan"
+
+#: options.h:538
+msgid "Report version information"
+msgstr "Laporan informasi versi"
+
+#: options.h:540
+msgid "Report version and target information"
+msgstr "Laporan versi dan informasi target"
+
+#: options.h:549
+msgid "Allow unresolved references in shared libraries"
+msgstr "Ijinkan referensi tidak terselesaikan dalam perpustakaan terbagi"
+
+#: options.h:550
+msgid "Do not allow unresolved references in shared libraries"
+msgstr "Jangan ijinkan referensi tidak terselesaikan dalam perpustakaan terbagi"
+
+#: options.h:553
+msgid "Only set DT_NEEDED for dynamic libs if used"
+msgstr "Hanya set DT_NEEDED untuk libs dinamis jika digunakan"
+
+#: options.h:554
+msgid "Always DT_NEEDED for dynamic libs"
+msgstr "Selalu DT_NEEDED untuk libs dinamis"
+
+#: options.h:561
+msgid "Set input format"
+msgstr "Set format masukan"
+
+#: options.h:564
+msgid "-l searches for shared libraries"
+msgstr "-l mencari untuk perpustakaan terbagi"
+
+#: options.h:566
+msgid "-l does not search for shared libraries"
+msgstr "-l tidak mencari untuk perpustakaan terbagi"
+
+#: options.h:570
+msgid "Bind defined symbols locally"
+msgstr "Ikat simbol terdefinisi secara lokal"
+
+#: options.h:573
+msgid "Bind defined function symbols locally"
+msgstr "Ikan simbol fungsi terdefinisi secara lokal"
+
+#: options.h:576
+msgid "Generate build ID note"
+msgstr "Buat catatan identitas pembuatan"
+
+#: options.h:577 options.h:612
+msgid "[=STYLE]"
+msgstr "[=GAYA]"
+
+#: options.h:580
+msgid "Check segment addresses for overlaps (default)"
+msgstr "Periksa daerah alamat untuk tumpang tindih (baku)"
+
+#: options.h:581
+msgid "Do not check segment addresses for overlaps"
+msgstr "Jangan periksa daerah alamat untuk tumpang tindih"
+
+#: options.h:585 options.h:590
+msgid "Compress .debug_* sections in the output file"
+msgstr "Kompress .debug_* daerah dalam berkas keluaran"
+
+#: options.h:591
+msgid "[none]"
+msgstr "[kosong]"
+
+#: options.h:596
+msgid "Define common symbols"
+msgstr "Definisikan simbol umum"
+
+#: options.h:597
+msgid "Do not define common symbols"
+msgstr "Jangan definisikan simbol umum"
+
+#: options.h:599 options.h:601
+msgid "Alias for -d"
+msgstr "Alias untuk -d"
+
+#: options.h:604
+msgid "Turn on debugging"
+msgstr "Aktifkan penelusuran"
+
+#: options.h:605
+msgid "[all,files,script,task][,...]"
+msgstr "[semua,berkas,skript,tugas][,...]"
+
+#: options.h:608
+msgid "Define a symbol"
+msgstr "Definisikan sebuah simbol"
+
+#: options.h:608
+msgid "SYMBOL=EXPRESSION"
+msgstr "SIMBOL=EKSPRESI"
+
+#: options.h:611
+msgid "Demangle C++ symbols in log messages"
+msgstr "Demangle simbol C++ dalam pesan pencatatan"
+
+#: options.h:615
+msgid "Do not demangle C++ symbols in log messages"
+msgstr "Jangan demangle simbol C++ dalam pesan pencatatan"
+
+#: options.h:619
+msgid "Try to detect violations of the One Definition Rule"
+msgstr "Coba detekasi pelanggaran dalam Definisi Satu Aturan"
+
+#: options.h:623
+msgid "Set program start address"
+msgstr "Set alamat awal aplikasi"
+
+#: options.h:623 options.h:766 options.h:768 options.h:770
+msgid "ADDRESS"
+msgstr "ALAMAT"
+
+#: options.h:626
+msgid "Export all dynamic symbols"
+msgstr "Ekpor seluruh simbol dinamis"
+
+#: options.h:629
+msgid "Create exception frame header"
+msgstr "Buat pengecualian lembar kepala"
+
+#: options.h:632
+msgid "Treat warnings as errors"
+msgstr "Perlakukan peringatan sebagai kesalahan"
+
+#: options.h:633
+msgid "Do not treat warnings as errors"
+msgstr "Jangan perlakukan peringatan sebagai kesalahan"
+
+#: options.h:636
+msgid "Set shared library name"
+msgstr "Set nama perpustakaan terbagi"
+
+#: options.h:636 options.h:696
+msgid "FILENAME"
+msgstr "NAMA BERKAS"
+
+#: options.h:639
+msgid "Min fraction of empty buckets in dynamic hash"
+msgstr "Bagian minimal dari tempat kosong dalam hash dinamis"
+
+#: options.h:640
+msgid "FRACTION"
+msgstr "BAGIAN"
+
+#: options.h:643
+msgid "Dynamic hash style"
+msgstr "Gaya hash dinamis"
+
+#: options.h:643
+msgid "[sysv,gnu,both]"
+msgstr "[sysv,gnu,keduanya]"
+
+#: options.h:647
+msgid "Set dynamic linker path"
+msgstr "Set jalur penghubung dinamis"
+
+#: options.h:647
+msgid "PROGRAM"
+msgstr "APLIKASI"
+
+#: options.h:650
+msgid "Read only symbol values from FILE"
+msgstr "Hanya baca nilai simbol dari BERKAS"
+
+#: options.h:650 options.h:684 options.h:751 options.h:779
+msgid "FILE"
+msgstr "BERKAS"
+
+#: options.h:653
+msgid "Search for library LIBNAME"
+msgstr "Cari untuk perpustakaan LIBNAME"
+
+#: options.h:653
+msgid "LIBNAME"
+msgstr "LIBNAME"
+
+#: options.h:656
+msgid "Add directory to search path"
+msgstr "Tambahkan direktori ke jalur pencarian"
+
+#: options.h:656 options.h:714 options.h:717 options.h:721 options.h:745
+msgid "DIR"
+msgstr "DIR"
+
+#: options.h:659
+msgid "Ignored for compatibility"
+msgstr "Abaikan untuk kompabilitas"
+
+#: options.h:659
+msgid "EMULATION"
+msgstr "EMULASI"
+
+#: options.h:662
+msgid "Write map file on standard output"
+msgstr "Tulis berkas peta di standar keluaran"
+
+#: options.h:663
+msgid "Write map file"
+msgstr "Tulis berkas peta"
+
+#: options.h:664
+msgid "MAPFILENAME"
+msgstr "NAMABERKASPETA"
+
+#: options.h:667
+msgid "Do not page align data"
+msgstr "Jangan sesuaikan data page"
+
+#: options.h:669
+msgid "Do not page align data, do not make text readonly"
+msgstr "Jangan sesuaikan data page, jangan buat teks baca-saja"
+
+#: options.h:670
+msgid "Page align data, make text readonly"
+msgstr "Sesuaikan data halaman, buat teks baca saja"
+
+#: options.h:673
+msgid "Enable use of DT_RUNPATH and DT_FLAGS"
+msgstr "Aktifkan penggunaan DT_RUNPATH dan DT_FLAGS"
+
+#: options.h:674
+msgid "Disable use of DT_RUNPATH and DT_FLAGS"
+msgstr "Nonaktifkan penggunaan DT_RUNPATH dan DT_FLAGS"
+
+#: options.h:677
+msgid "Create an output file even if errors occur"
+msgstr "Buat sebuah berkas keluaran walaupun terjadi kesalahan"
+
+#: options.h:680 options.h:808
+msgid "Report undefined symbols (even with --shared)"
+msgstr "Laporkan simbol tidak terdefinisi (walaupun dengan --shared)"
+
+#: options.h:684
+msgid "Set output file name"
+msgstr "Set nama berkas keluaran"
+
+#: options.h:687
+msgid "Optimize output file size"
+msgstr "Optimasi besar berkas keluaran"
+
+#: options.h:687
+msgid "LEVEL"
+msgstr "TINGKAT"
+
+#: options.h:690
+msgid "Set output format"
+msgstr "Set format keluaran"
+
+#: options.h:690
+msgid "[binary]"
+msgstr "[binari]"
+
+#: options.h:693
+msgid "Preread archive symbols when multi-threaded"
+msgstr "Baca terlebih dahulu kumpulan simbol ketika multi-threaded"
+
+#: options.h:695
+msgid "Print symbols defined and used for each input"
+msgstr "Tampilkan simbol didefinisikan dan digunakan untuk setiap masukan"
+
+#: options.h:699
+msgid "Ignored for SVR4 compatibility"
+msgstr "Abaikan untuk kompabilitas SVR4"
+
+#: options.h:702
+msgid "Generate relocations in output"
+msgstr "Buat relokasi dalam keluaran"
+
+#: options.h:705
+msgid "Generate relocatable output"
+msgstr "Buat relokasi keluaran"
+
+#: options.h:708
+msgid "Relax branches on certain targets"
+msgstr "Percabangan relaks dalam beberapa target"
+
+#: options.h:714 options.h:717
+msgid "Add DIR to runtime search path"
+msgstr "Tambahkan DIR ke jalur pencarian waktu jalan"
+
+#: options.h:720
+msgid "Add DIR to link time shared library search path"
+msgstr "Tambahkan DIR ke jalur pencarian waktu penyambungan perpustakaan terbagi"
+
+#: options.h:724
+msgid "Strip all symbols"
+msgstr "Hapus seluruh simbol"
+
+#: options.h:726
+msgid "Strip debugging information"
+msgstr "Hapus informasi penelusuran"
+
+#: options.h:728
+msgid "Emit only debug line number information"
+msgstr "Hanya keluarkan informasi nomor baris penelusuran"
+
+#: options.h:730
+msgid "Strip debug symbols that are unused by gdb (at least versions <= 6.7)"
+msgstr "Hapus simbol penelusuran yang tidak digunakan oleh gdb (paling tidak versi < 6.7)"
+
+#: options.h:734
+msgid "Generate shared library"
+msgstr "Buat perpustakaan terbagi"
+
+#: options.h:739
+msgid "Do not link against shared libraries"
+msgstr "Jangan sambungkan terhadap perpustakaan terbagi"
+
+#: options.h:742
+msgid "Print resource usage statistics"
+msgstr "Tampilkan statistik penggunaan sumber daya"
+
+#: options.h:745
+msgid "Set target system root directory"
+msgstr "Set target direktori root sistem"
+
+#: options.h:748
+msgid "Print the name of each input file"
+msgstr "Tampilkan nama dari setiap berkas masukan"
+
+#: options.h:751
+msgid "Read linker script"
+msgstr "Baca script penyambung"
+
+#: options.h:754
+msgid "Run the linker multi-threaded"
+msgstr "Jalankan penyambung multi-threaded"
+
+#: options.h:755
+msgid "Do not run the linker multi-threaded"
+msgstr "Jangan jalankan penyambung multi-threaded"
+
+#: options.h:757
+msgid "Number of threads to use"
+msgstr "Jumlah dari thread yang digunakan"
+
+#: options.h:757 options.h:759 options.h:761 options.h:763
+msgid "COUNT"
+msgstr "JUMLAH"
+
+#: options.h:759
+msgid "Number of threads to use in initial pass"
+msgstr "Jumlah dari thread yang digunakan dalam tahap awal"
+
+#: options.h:761
+msgid "Number of threads to use in middle pass"
+msgstr "Jumlah thread yang digunakan dalam tahap perantara"
+
+#: options.h:763
+msgid "Number of threads to use in final pass"
+msgstr "Jumlah dari thread yang digunakan dalam tahap akhir"
+
+#: options.h:766
+msgid "Set the address of the bss segment"
+msgstr "Set alamat dari bagian bss"
+
+#: options.h:768
+msgid "Set the address of the data segment"
+msgstr "Set alamat dari bagian data"
+
+#: options.h:770
+msgid "Set the address of the text segment"
+msgstr "Set alamat dari bagian teks"
+
+#: options.h:773
+msgid "Create undefined reference to SYMBOL"
+msgstr "Buat referensi tidak terdefinisi ke SIMBOL"
+
+#: options.h:773 options.h:786 options.h:789
+msgid "SYMBOL"
+msgstr "SIMBOL"
+
+#: options.h:776
+msgid "Synonym for --debug=files"
+msgstr "Sinonim untuk --debug=berkas"
+
+#: options.h:779
+msgid "Read version script"
+msgstr "Baca versi script"
+
+#: options.h:782
+msgid "Include all archive contents"
+msgstr "Masukan seluruh isi kumpulan"
+
+#: options.h:783
+msgid "Include only needed archive contents"
+msgstr "Masukan hanya isi kumpulan yang dibutuhkan"
+
+#: options.h:786
+msgid "Use wrapper functions for SYMBOL"
+msgstr "Gunakan wrapper fungsi untuk SIMBOL"
+
+#: options.h:789
+msgid "Trace references to symbol"
+msgstr "Telusuri referensi ke simbol"
+
+#: options.h:792
+msgid "Default search path for Solaris compatibility"
+msgstr "Jalur pencarian baku untuk kompabilitas solaris"
+
+#: options.h:793
+msgid "PATH"
+msgstr "JALUR"
+
+#: options.h:796
+msgid "Start a library search group"
+msgstr "Awal sebuah perpustakaan grup pencarian"
+
+#: options.h:798
+msgid "End a library search group"
+msgstr "Akhir sebuah perpustakaan grup pencarian"
+
+#: options.h:803
+msgid "Sort dynamic relocs"
+msgstr "Urutkan relokasi dinamis"
+
+#: options.h:804
+msgid "Do not sort dynamic relocs"
+msgstr "Jangan urutkan relokasi dinamis"
+
+#: options.h:806
+msgid "Set common page size to SIZE"
+msgstr "Set ukuran halaman umum ke BESAR"
+
+#: options.h:806 options.h:813
+msgid "SIZE"
+msgstr "BESAR"
+
+#: options.h:811
+msgid "Mark output as requiring executable stack"
+msgstr "Tandai keluaran sebagai stack eksekusi yang dibutuhkan"
+
+#: options.h:813
+msgid "Set maximum page size to SIZE"
+msgstr "Set ukuran maksimal halaman ke UKURAN"
+
+#: options.h:815
+msgid "Mark output as not requiring executable stack"
+msgstr "Tandai keluaran sebagai tidak membutuhkan stack eksekusi"
+
+#: options.h:817
+msgid "Mark DSO to be initialized first at runtime"
+msgstr "Tandai DSO untuk diinisialisasi terlebih dahulu di waktu jalan"
+
+#: options.h:820
+msgid "Mark object to interpose all DSOs but executable"
+msgstr "Tandai objek untuk interpose seluruh DSO tetapi eksekusi"
+
+#: options.h:823
+msgid "Mark object requiring immediate process"
+msgstr "Tandai objek membutuhkan proses perantara"
+
+#: options.h:826
+msgid "Mark object not to use default search paths"
+msgstr "Tandai objek tidak menggunakan jalur pencarian baku"
+
+#: options.h:829
+msgid "Mark DSO non-deletable at runtime"
+msgstr "Tandai DSO tidak dapat dihapus di waktu jalan"
+
+#: options.h:832
+msgid "Mark DSO not available to dlopen"
+msgstr "Tandai DSO tidak tersedia di dlopen"
+
+#: options.h:835
+msgid "Mark DSO not available to dldump"
+msgstr "Tandai DSO tidak tersedia ke dldump"
+
+#: options.h:838
+msgid "Where possible mark variables read-only after relocation"
+msgstr "Dimana memungkinkan tanda variabel baca-saja setelah relokasi"
+
+#: options.h:839
+msgid "Don't mark variables read-only after relocation"
+msgstr "Jangan tandai variabel baca-saja setelah relokasi"
+
+#: output.cc:1098
+msgid "section group retained but group element discarded"
+msgstr "daerah grup dijaga tetapi elemen grup diabaikan"
+
+#: output.cc:1800
+#, c-format
+msgid "invalid alignment %lu for section \"%s\""
+msgstr "alignment %lu tidak valid untuk daerah \"%s\""
+
+#: output.cc:3159
+#, c-format
+msgid "nobits section %s may not precede progbits section %s in same segment"
+msgstr "daerah nobits %s tidak boleh mengawali daerah progbits %s dalam daerah yang sama"
+
+#: output.cc:3329
+#, c-format
+msgid "%s: open: %s"
+msgstr "%s: buka: %s"
+
+#: output.cc:3350
+#, c-format
+msgid "%s: mremap: %s"
+msgstr "%s: mremap: %s"
+
+#: output.cc:3387
+#, c-format
+msgid "%s: lseek: %s"
+msgstr "%s: lseek: %s"
+
+#: output.cc:3390 output.cc:3427
+#, c-format
+msgid "%s: write: %s"
+msgstr "%s: tulis: %s"
+
+#: output.cc:3398
+#, c-format
+msgid "%s: mmap: %s"
+msgstr "%s: mmap: %s"
+
+#: output.cc:3408
+#, c-format
+msgid "%s: munmap: %s"
+msgstr "%s: munmap: %s"
+
+#: output.cc:3425
+#, c-format
+msgid "%s: write: unexpected 0 return-value"
+msgstr "%s: tulis: tidak terduga 0 nilai-kembali"
+
+#: output.cc:3439
+#, c-format
+msgid "%s: close: %s"
+msgstr "%s: tutup: %s"
+
+#: output.h:415
+msgid "** section headers"
+msgstr "** daerah kepala"
+
+#: output.h:451
+msgid "** segment headers"
+msgstr "** bagian kepala"
+
+#: output.h:490
+msgid "** file header"
+msgstr "** berkas kepala"
+
+#: output.h:696
+msgid "** fill"
+msgstr "** isi"
+
+#: output.h:850
+msgid "** string table"
+msgstr "** tabel string"
+
+#: output.h:1161
+msgid "** dynamic relocs"
+msgstr "** relokasi dinamis"
+
+#: output.h:1162 output.h:1498
+msgid "** relocs"
+msgstr "** relokasi"
+
+#: output.h:1523
+msgid "** group"
+msgstr "** grup"
+
+#: output.h:1630
+msgid "** GOT"
+msgstr "** GOT"
+
+#: output.h:1772
+msgid "** dynamic"
+msgstr "** dinamis"
+
+#: output.h:1890
+msgid "** symtab xindex"
+msgstr "** symtab xindex"
+
+#: parameters.cc:87
+#, c-format
+msgid "unrecognized output format %s"
+msgstr "format keluaran tidak diketahui %s"
+
+#: powerpc.cc:1086 sparc.cc:1569 x86_64.cc:957
+msgid "requires unsupported dynamic reloc; recompile with -fPIC"
+msgstr "relokasi dinamis yang dibutuhkan tidak didukung; rekompilasi dengan -fPIC"
+
+#: powerpc.cc:1447 sparc.cc:2237 x86_64.cc:1561
+#, c-format
+msgid "%s: unsupported REL reloc section"
+msgstr "%s: daerah relokasi REL tidak didukung"
+
+#: readsyms.cc:150
+#, c-format
+msgid "%s: file is empty"
+msgstr "%s: berkas kosong"
+
+#. Here we have to handle any other input file types we need.
+#: readsyms.cc:471
+#, c-format
+msgid "%s: not an object or archive"
+msgstr "%s: bukan sebuah objek atau kumpulan"
+
+#: reduced_debug_output.cc:240
+msgid "Debug abbreviations extend beyond .debug_abbrev section; failed to reduce debug abbreviations"
+msgstr "Kependekan debug melewati daerah .debug_abbrev; gagai untuk mengurangi kependekan penelusuran"
+
+#: reduced_debug_output.cc:326
+msgid "Extremely large compile unit in debug info; failed to reduce debug info"
+msgstr "Ekstremely satuan kompilasi besar dalam informasi penelusuran; gagal untuk mengurangi informasi penelusuran"
+
+#: reduced_debug_output.cc:334
+msgid "Debug info extends beyond .debug_info section;failed to reduce debug info"
+msgstr "Informasi penelusuran melewati daerah .debug_info; gagal untuk mengurangi informasi penelusuran"
+
+#: reduced_debug_output.cc:354 reduced_debug_output.cc:396
+msgid "Invalid DIE in debug info; failed to reduce debug info"
+msgstr "Informasi debugu dalam DIE tidak valid; gagal untuk mengurangi informasi debug"
+
+#: reduced_debug_output.cc:377
+msgid "Debug info extends beyond .debug_info section; failed to reduce debug info"
+msgstr "Informasi debug melewati daerah .debug_info; gagal mengurangi informasi penelusuran"
+
+#: reloc.cc:239 reloc.cc:743
+#, c-format
+msgid "relocation section %u uses unexpected symbol table %u"
+msgstr "daerah relokasi %u menggunakan tabel simbol tidak terduga %u"
+
+#: reloc.cc:254 reloc.cc:761
+#, c-format
+msgid "unexpected entsize for reloc section %u: %lu != %u"
+msgstr "tidak terduga entsize untuk daerah relokasi %u: %lu != %u"
+
+#: reloc.cc:263 reloc.cc:770
+#, c-format
+msgid "reloc section %u size %lu uneven"
+msgstr "daerah relokasi %u besar %lu tidak genap"
+
+#: reloc.cc:992
+#, c-format
+msgid "reloc section size %zu is not a multiple of reloc size %d\n"
+msgstr "ukuran daerah relokasi %zu bukan kelipatan dari ukuran relokasi %d\n"
+
+#. We should only see externally visible symbols in the symbol
+#. table.
+#: resolve.cc:170
+msgid "invalid STB_LOCAL symbol in external symbols"
+msgstr "simbol STB_LOCAL tidak valid dalam simbol eksternal"
+
+#. Any target which wants to handle STB_LOOS, etc., needs to
+#. define a resolve method.
+#: resolve.cc:176
+msgid "unsupported symbol binding"
+msgstr "pengikatan simbol tidak diduga"
+
+#. FIXME: Do a better job of reporting locations.
+#: resolve.cc:367
+#, c-format
+msgid "%s: multiple definition of %s"
+msgstr "%s: definisi ganda dari %s"
+
+#: resolve.cc:368 resolve.cc:373
+msgid "command line"
+msgstr "baris perintah"
+
+#: resolve.cc:370
+#, c-format
+msgid "%s: previous definition here"
+msgstr "%s: definisi sebelumnya disini"
+
+#: script-sections.cc:432
+msgid "dot may not move backward"
+msgstr "dot tidak boleh bergerak kebelakang"
+
+#: script-sections.cc:498
+msgid "** expression"
+msgstr "** ekspresi"
+
+#: script-sections.cc:684
+msgid "fill value is not absolute"
+msgstr "nilai isi tidak absolut"
+
+#: script-sections.cc:1693
+#, c-format
+msgid "alignment of section %s is not absolute"
+msgstr "penyesuaian dari daerah %s tidak absolut"
+
+#: script-sections.cc:1737
+#, c-format
+msgid "subalign of section %s is not absolute"
+msgstr "subalign dari daerah %s tidak absolut"
+
+#: script-sections.cc:1752
+#, c-format
+msgid "fill of section %s is not absolute"
+msgstr "isi dari daerah %s tidak absolut"
+
+#: script-sections.cc:1828
+msgid "SPECIAL constraints are not implemented"
+msgstr "konstrain SPESIAL tidak terimplementasi"
+
+#: script-sections.cc:1870
+msgid "mismatched definition for constrained sections"
+msgstr "definisi tidak cocok untuk daerah konstrain"
+
+#: script-sections.cc:2395
+msgid "DATA_SEGMENT_ALIGN may only appear once in a linker script"
+msgstr "DATA_SEGMENT_ALIGN hanya mungkin muncul sekali dalam script linker"
+
+#: script-sections.cc:2406
+msgid "DATA_SEGMENT_RELRO_END may only appear once in a linker script"
+msgstr "DATA_SEGMENT_RELRO_END hanya mungkin muncul sekali dalam script linker"
+
+#: script-sections.cc:2411
+msgid "DATA_SEGMENT_RELRO_END must follow DATA_SEGMENT_ALIGN"
+msgstr "DATA_SEGMENT_RELRO_END harus mengikuti DATA_SEGMENT_ALIGN"
+
+#: script-sections.cc:2570
+msgid "no matching section constraint"
+msgstr "tidak ada kecocokan daerah konstrain"
+
+#: script-sections.cc:2890
+msgid "TLS sections are not adjacent"
+msgstr "daerah TLS tidak berurutan"
+
+#: script-sections.cc:3016
+msgid "allocated section not in any segment"
+msgstr "daerah yang dialokasikan tidka dalam bagian apapun"
+
+#: script-sections.cc:3048
+#, c-format
+msgid "no segment %s"
+msgstr "bukan bagian %s"
+
+#: script-sections.cc:3058
+msgid "section in two PT_LOAD segments"
+msgstr "daerah dalam dua bagian PT_LOAD"
+
+#: script-sections.cc:3065
+msgid "allocated section not in any PT_LOAD segment"
+msgstr "daerah dialokasikan tidak dalam bagian PT_LOAD apapun"
+
+#: script-sections.cc:3093
+msgid "may only specify load address for PT_LOAD segment"
+msgstr "mungkin hanya dispesifikasikan alamat pemuatan untuk bagian PT_LOAD"
+
+#: script-sections.cc:3117
+#, c-format
+msgid "PHDRS load address overrides section %s load address"
+msgstr "PHDRS alamat pemuatan memaksa daerah %s alamat pemuatan"
+
+#. We could support this if we wanted to.
+#: script-sections.cc:3128
+msgid "using only one of FILEHDR and PHDRS is not currently supported"
+msgstr "hanya menggunakan satu dari FILEHDR dan PHDRS belum didukung"
+
+#: script-sections.cc:3143
+msgid "sections loaded on first page without room for file and program headers are not supported"
+msgstr "daerah dimuat dalam halaman pertama tanpa ruang untuk berkas dan aplikasi kepala tidak didukung"
+
+#: script-sections.cc:3149
+msgid "using FILEHDR and PHDRS on more than one PT_LOAD segment is not currently supported"
+msgstr "menggunakan FILEHDR dan PHDRS di lebih dari sekali bagian PT_LOAD saat ini belum didukung"
+
+#: script.cc:1063
+msgid "invalid use of PROVIDE for dot symbol"
+msgstr "penggunaan tidak valid dari PROVIDE untuk simbol dot"
+
+#: script.cc:1065
+msgid "invalid assignment to dot outside of SECTIONS"
+msgstr "penempatan tidak valid untuk dot diluar dari DAERAH"
+
+#: script.cc:1995
+#, c-format
+msgid "%s:%d:%d: %s"
+msgstr "%s:%d:%d: %s"
+
+#. There are some options that we could handle here--e.g.,
+#. -lLIBRARY. Should we bother?
+#: script.cc:2143
+#, c-format
+msgid "%s:%d:%d: ignoring command OPTION; OPTION is only valid for scripts specified via -T/--script"
+msgstr "%s:%d:%d mengabaikan perintah OPTION; OPTION hanya valid untuk script dispesifikasikan melalui -T/--script"
+
+#: script.cc:2168
+#, c-format
+msgid "%s:%d:%d: ignoring SEARCH_DIR; SEARCH_DIR is only valid for scripts specified via -T/--script"
+msgstr "%s:%d:%d: mengabaikan SEARCH_DIR; SEARCH_DIR hanya valid untuk script dispesifikasikan melalui -T/--script"
+
+#: script.cc:2411 script.cc:2425
+#, c-format
+msgid "%s:%d:%d: DATA_SEGMENT_ALIGN not in SECTIONS clause"
+msgstr "%s:%d:%d: DATA_SEGMENT_ALIGN tidak dalam clause DAERAH"
+
+#: script.cc:2543
+msgid "unknown PHDR type (try integer)"
+msgstr "tipe PHDR tidak diketahui (coba bilangan bulat)"
+
+#: stringpool.cc:526
+#, c-format
+msgid "%s: %s entries: %zu; buckets: %zu\n"
+msgstr "%s: %s masukan: %zu; buckets: %zu\n"
+
+#: stringpool.cc:530
+#, c-format
+msgid "%s: %s entries: %zu\n"
+msgstr "%s: %s masukan: %zu\n"
+
+#: stringpool.cc:533
+#, c-format
+msgid "%s: %s Stringdata structures: %zu\n"
+msgstr "%s: %s struktur Stringdata: %zu\n"
+
+#: symtab.cc:623
+#, c-format
+msgid "%s: reference to %s"
+msgstr "%s: referensi ke %s"
+
+#: symtab.cc:625
+#, c-format
+msgid "%s: definition of %s"
+msgstr "%s: definisi dari %s"
+
+#: symtab.cc:860
+#, c-format
+msgid "bad global symbol name offset %u at %zu"
+msgstr "ofset nama simbol global buruk %u di %zu"
+
+#: symtab.cc:999
+msgid "--just-symbols does not make sense with a shared object"
+msgstr "--just-symbols tidak masuk akal dengan sebuah objek terbagi"
+
+#: symtab.cc:1005
+msgid "too few symbol versions"
+msgstr "terlalu sedikit versi simbol"
+
+#: symtab.cc:1054
+#, c-format
+msgid "bad symbol name offset %u at %zu"
+msgstr "ofset nama simbol buruk %u di %zu"
+
+#: symtab.cc:1117
+#, c-format
+msgid "versym for symbol %zu out of range: %u"
+msgstr "versym untuk simbol %zu diluar dari jangkauan: %u"
+
+#: symtab.cc:1125
+#, c-format
+msgid "versym for symbol %zu has no name: %u"
+msgstr "versym untuk symbol %zu tidak memiliki nama: %u"
+
+#: symtab.cc:2035 symtab.cc:2251
+#, c-format
+msgid "%s: unsupported symbol section 0x%x"
+msgstr "%s: daerah simbol tidak didukung 0x%x"
+
+#: symtab.cc:2409
+#, c-format
+msgid "%s: undefined reference to '%s', version '%s'"
+msgstr "%s: referensi ke '%s' tidak terdefinisi, versi '%s'"
+
+#: symtab.cc:2414
+#, c-format
+msgid "%s: undefined reference to '%s'"
+msgstr "%s: referensi ke '%s' tidak terdefinisi"
+
+#: symtab.cc:2498
+#, c-format
+msgid "%s: symbol table entries: %zu; buckets: %zu\n"
+msgstr "%s: masukan tabel simbol: %zu; buckets: %zu\n"
+
+#: symtab.cc:2501
+#, c-format
+msgid "%s: symbol table entries: %zu\n"
+msgstr "%s: masukan tabel simbol: %zu\n"
+
+#: symtab.cc:2572
+#, c-format
+msgid "while linking %s: symbol '%s' defined in multiple places (possible ODR violation):"
+msgstr "ketika menyambungkan %s: simbol '%s' didefinisikan dalam beberapa tempat (mungkin penyimpangan ODR):"
+
+#: target-reloc.h:247
+msgid "Relocation refers to discarded comdat section"
+msgstr "Relokasi mereferensikan ke daerah comdat yang diabaikan"
+
+#: target-reloc.h:278
+#, c-format
+msgid "reloc has bad offset %zu"
+msgstr "relokasi memliki ofset %zu buruk"
+
+#: tls.h:59
+msgid "TLS relocation out of range"
+msgstr "relokasi TLS diluar dari jangkauan"
+
+#: tls.h:73
+msgid "TLS relocation against invalid instruction"
+msgstr "relokasi TLS terhadap instruksi tidak valid"
+
+#. This output is intended to follow the GNU standards.
+#: version.cc:64
+#, c-format
+msgid "Copyright 2008 Free Software Foundation, Inc.\n"
+msgstr "Hak Cipta 2008 Free Software Foundation, Inc.\n"
+
+#: version.cc:65
+#, c-format
+msgid ""
+"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) a later version.\n"
+"This program has absolutely no warranty.\n"
+msgstr ""
+"Aplikasi ini adalah aplikasi bebas; anda boleh meredistribusikannya dibawah\n"
+"perjanjian dari GNU General Public License versi 3 atau (menurut pilihan anda)\n"
+" di versi selanjutnya.\n"
+"Aplikasi ini benar benar tidak bergaransi.\n"
+
+#: workqueue-threads.cc:106
+#, c-format
+msgid "%s failed: %s"
+msgstr "%s gagal: %s"
+
+#: x86_64.cc:2104
+#, c-format
+msgid "unsupported reloc type %u"
+msgstr "tipe relokasi %u tidak didukung"
+
+#: x86_64.cc:2441
+#, c-format
+msgid "unsupported reloc %u against local symbol"
+msgstr "relokasi %u terhadap simbol lokal tidak didukung"
diff --git a/binutils-2.25/gold/po/it.po b/binutils-2.25/gold/po/it.po
new file mode 100644
index 00000000..144a1e76
--- /dev/null
+++ b/binutils-2.25/gold/po/it.po
@@ -0,0 +1,2247 @@
+# Italian translation for gold.
+# Copyright (C) 2011 Free Software Foundation, Inc.
+# This file is distributed under the same license as the binutils package.
+# Sergio Zanchetta <primes2h@ubuntu.com>, 2011.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gold-2.21.53\n"
+"Report-Msgid-Bugs-To: bug-binutils@gnu.org\n"
+"POT-Creation-Date: 2010-03-03 15:08+0100\n"
+"PO-Revision-Date: 2011-11-14 18:30+0100\n"
+"Last-Translator: Sergio Zanchetta <primes2h@ubuntu.com>\n"
+"Language-Team: Italian <tp@lists.linux.it>\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural= (n != 1)\n"
+
+#: archive.cc:119
+#, c-format
+msgid "%s: no archive symbol table (run ranlib)"
+msgstr "%s: nessuna tabella dei simboli dell'archivio (eseguire ranlib)"
+
+#: archive.cc:204
+#, c-format
+msgid "%s: bad archive symbol table names"
+msgstr "%s: nomi delle tabelle dei simboli dell'archivio errati"
+
+#: archive.cc:236
+#, c-format
+msgid "%s: malformed archive header at %zu"
+msgstr "%s: intestazione malformata dell'archivio alla %zu"
+
+#: archive.cc:256
+#, c-format
+msgid "%s: malformed archive header size at %zu"
+msgstr "%s: dimensione malformata dell'intestazione dell'archivio alla %zu"
+
+#: archive.cc:267
+#, c-format
+msgid "%s: malformed archive header name at %zu"
+msgstr "%s: nome malformato dell'intestazione dell'archivio alla %zu"
+
+#: archive.cc:297
+#, c-format
+msgid "%s: bad extended name index at %zu"
+msgstr "%s: indice dei nomi estesi errato alla %zu"
+
+#: archive.cc:307
+#, c-format
+msgid "%s: bad extended name entry at header %zu"
+msgstr "%s: voce di nome esteso errata all'intestazione %zu"
+
+#: archive.cc:404
+#, c-format
+msgid "%s: short archive header at %zu"
+msgstr "%s: intestazione corta dell'archivio alla %zu"
+
+#: archive.cc:560
+#, c-format
+msgid "%s: member at %zu is not an ELF object"
+msgstr "%s: il membro alla %zu non è un oggetto ELF"
+
+#: archive.cc:879
+#, c-format
+msgid "%s: archive libraries: %u\n"
+msgstr "%s: librerie di archivio: %u\n"
+
+#: archive.cc:881
+#, c-format
+msgid "%s: total archive members: %u\n"
+msgstr "%s: membri totali dell'archivio: %u\n"
+
+#: archive.cc:883
+#, c-format
+msgid "%s: loaded archive members: %u\n"
+msgstr "%s: membri caricati dell'archivio: %u\n"
+
+#: arm.cc:1149 i386.cc:536 sparc.cc:1087 x86_64.cc:565
+msgid "** PLT"
+msgstr "** PLT"
+
+#: arm.cc:1364 i386.cc:880 powerpc.cc:1014 sparc.cc:1502 x86_64.cc:955
+#: x86_64.cc:1265
+#, c-format
+msgid "%s: unsupported reloc %u against local symbol"
+msgstr "%s: rilocazione %u non supportata contro un simbolo locale"
+
+#: arm.cc:1404 powerpc.cc:1105 sparc.cc:1592 x86_64.cc:992
+msgid "requires unsupported dynamic reloc; recompile with -fPIC"
+msgstr "richiede rilocazioni dinamiche non supportate; ricompilare con -fPIC"
+
+#. These are relocations which should only be seen by the
+#. dynamic linker, and should never be seen here.
+#: arm.cc:1519 arm.cc:1739 arm.cc:2354 i386.cc:1002 i386.cc:1334
+#: powerpc.cc:1223 powerpc.cc:1432 sparc.cc:1877 sparc.cc:2238 x86_64.cc:1145
+#: x86_64.cc:1453
+#, c-format
+msgid "%s: unexpected reloc %u in object file"
+msgstr "%s: rilocazione %u inattesa nel file oggetto"
+
+#: arm.cc:1538 i386.cc:1171 powerpc.cc:1242 sparc.cc:1896 x86_64.cc:1279
+#: x86_64.cc:1571
+#, c-format
+msgid "%s: unsupported reloc %u against global symbol %s"
+msgstr "%s: rilocazione %u non supportata contro il simbolo globale %s"
+
+#: arm.cc:1804 i386.cc:1542
+#, c-format
+msgid "%s: unsupported RELA reloc section"
+msgstr "%s: sezione di rilocazione RELA non supportata"
+
+#: arm.cc:2047
+msgid "relocation R_ARM_MOVW_ABS_NC cannot be used when makinga shared object; recompile with -fPIC"
+msgstr "impossibile usare la rilocazione R_ARM_MOVW_ABS_NC quando viene creato un oggetto condiviso; ricompilare con -fPIC"
+
+#: arm.cc:2056
+msgid "relocation R_ARM_MOVT_ABS cannot be used when makinga shared object; recompile with -fPIC"
+msgstr "impossibile usare la rilocazione R_ARM_MOVT_ABS quando viene creato un oggetto condiviso; ricompilare con -fPIC"
+
+#: arm.cc:2067
+msgid "relocation R_ARM_THM_MOVW_ABS_NC cannot be used whenmaking a shared object; recompile with -fPIC"
+msgstr "impossibile usare la rilocazione R_ARM_THM_MOVW_ABS_NC quando viene creato un oggetto condiviso; ricompilare con -fPIC"
+
+#: arm.cc:2077
+msgid "relocation R_ARM_THM_MOVT_ABS cannot be used whenmaking a shared object; recompile with -fPIC"
+msgstr "impossibile usare la rilocazione R_ARM_THM_MOVT_ABS quando viene creato un oggetto condiviso; ricompilare con -fPIC"
+
+#: arm.cc:2141
+msgid "cannot find origin of R_ARM_BASE_PREL"
+msgstr "impossibile trovare l'origine di R_ARM_BASE_PREL"
+
+#: arm.cc:2169
+msgid "cannot find origin of R_ARM_BASE_ABS"
+msgstr "impossibile trovare l'origine di R_ARM_BASE_ABS"
+
+#: arm.cc:2230 i386.cc:1820 i386.cc:2521 powerpc.cc:1798 sparc.cc:2711
+#: x86_64.cc:1935 x86_64.cc:2518
+#, c-format
+msgid "unexpected reloc %u in object file"
+msgstr "rilocazione %u inattesa nel file oggetto"
+
+#: arm.cc:2236 i386.cc:1852 i386.cc:1931 i386.cc:1983 i386.cc:2014
+#: i386.cc:2076 powerpc.cc:1804 sparc.cc:2717 sparc.cc:2900 sparc.cc:2961
+#: sparc.cc:3068 x86_64.cc:1956 x86_64.cc:2039 x86_64.cc:2094 x86_64.cc:2119
+#, c-format
+msgid "unsupported reloc %u"
+msgstr "rilocazione %u non supportata"
+
+#: arm.cc:2248
+#, c-format
+msgid "relocation overflow in relocation %u"
+msgstr "overflow nella rilocazione %u"
+
+#: arm.cc:2256
+#, c-format
+msgid "unexpected opcode while processing relocation %u"
+msgstr "opcode inatteso durante l'elaborazione della rilocazione %u"
+
+#: arm.cc:2359 i386.cc:2535
+#, c-format
+msgid "unsupported reloc %u in object file"
+msgstr "rilocazione %u non supportata nel file oggetto"
+
+#: binary.cc:129
+#, c-format
+msgid "cannot open %s: %s:"
+msgstr "impossibile aprire %s: %s:"
+
+#: compressed_output.cc:128
+msgid "not compressing section data: zlib error"
+msgstr "i dati di sezione non vengono compressi: errore di zlib"
+
+#: cref.cc:244
+#, c-format
+msgid "cannot open symbol count file %s: %s"
+msgstr "impossibile aprire il file %s di conteggio dei simboli: %s"
+
+#: descriptors.cc:116
+#, c-format
+msgid "file %s was removed during the link"
+msgstr "rimosso il file %s durante l'operazione di link"
+
+#: descriptors.cc:169
+msgid "out of file descriptors and couldn't close any"
+msgstr "descrittori di file terminati senza poterne chiudere alcuno"
+
+#: descriptors.cc:190 descriptors.cc:226
+#, c-format
+msgid "while closing %s: %s"
+msgstr "mentre viene chiuso %s: %s"
+
+#: dirsearch.cc:71
+#, c-format
+msgid "%s: can not read directory: %s"
+msgstr "%s: impossibile leggere la directory: %s"
+
+#: dwarf_reader.cc:53 dwarf_reader.cc:84
+msgid "Unusually large LEB128 decoded, debug information may be corrupted"
+msgstr "Decodificato un LEB128 insolitamente grande, le informazioni di debug potrebbero essere danneggiate"
+
+#: dynobj.cc:164
+#, c-format
+msgid "unexpected duplicate type %u section: %u, %u"
+msgstr "sezione duplicata di tipo %u inattesa: %u, %u"
+
+#: dynobj.cc:200
+#, c-format
+msgid "unexpected link in section %u header: %u != %u"
+msgstr "link inatteso nell'intestazione della sezione %u: %u != %u"
+
+#: dynobj.cc:236
+#, c-format
+msgid "DYNAMIC section %u link out of range: %u"
+msgstr "nella sezione DYNAMIC %u il link è fuori dall'intervallo: %u"
+
+#: dynobj.cc:244
+#, c-format
+msgid "DYNAMIC section %u link %u is not a strtab"
+msgstr "nella sezione DYNAMIC %u il link %u non è uno strtab"
+
+#: dynobj.cc:273
+#, c-format
+msgid "DT_SONAME value out of range: %lld >= %lld"
+msgstr "valore di DT_SONAME fuori dall'intervallo: %lld >= %lld"
+
+#: dynobj.cc:285
+#, c-format
+msgid "DT_NEEDED value out of range: %lld >= %lld"
+msgstr "valore di DT_NEEDED fuori dall'intervallo: %lld >= %lld"
+
+#: dynobj.cc:298
+msgid "missing DT_NULL in dynamic segment"
+msgstr "DT_NULL mancante nel segmento dinamico"
+
+#: dynobj.cc:344
+#, c-format
+msgid "invalid dynamic symbol table name index: %u"
+msgstr "indice dei nomi della tabella dei simboli dinamici non valido: %u"
+
+#: dynobj.cc:351
+#, c-format
+msgid "dynamic symbol table name section has wrong type: %u"
+msgstr "la sezione dei nomi della tabella dei simboli dinamici è di tipo errato: %u"
+
+#: dynobj.cc:438 object.cc:463 object.cc:1106
+#, c-format
+msgid "bad section name offset for section %u: %lu"
+msgstr "posizione del nome errata per la sezione %u: %lu"
+
+#: dynobj.cc:468
+#, c-format
+msgid "duplicate definition for version %u"
+msgstr "definizione duplicata per la versione %u"
+
+#: dynobj.cc:497
+#, c-format
+msgid "unexpected verdef version %u"
+msgstr "versione verdef %u inaspettata"
+
+#: dynobj.cc:513
+#, c-format
+msgid "verdef vd_cnt field too small: %u"
+msgstr "campo vd_cnt verdef troppo piccolo: %u"
+
+#: dynobj.cc:521
+#, c-format
+msgid "verdef vd_aux field out of range: %u"
+msgstr "campo vd_aux verdef fuori dall'intervallo: %u"
+
+#: dynobj.cc:532
+#, c-format
+msgid "verdaux vda_name field out of range: %u"
+msgstr "campo vda_name verdaux fuori dall'intervallo: %u"
+
+#: dynobj.cc:542
+#, c-format
+msgid "verdef vd_next field out of range: %u"
+msgstr "campo vd_next verdef fuori dall'intervallo: %u"
+
+#: dynobj.cc:576
+#, c-format
+msgid "unexpected verneed version %u"
+msgstr "versione verneed non attesa %u"
+
+#: dynobj.cc:585
+#, c-format
+msgid "verneed vn_aux field out of range: %u"
+msgstr "campo vn_aux verneed fuori dall'intervallo: %u"
+
+#: dynobj.cc:599
+#, c-format
+msgid "vernaux vna_name field out of range: %u"
+msgstr "campo vna_name vernaux fuori dall'intervallo: %u"
+
+#: dynobj.cc:610
+#, c-format
+msgid "verneed vna_next field out of range: %u"
+msgstr "campo vna_next verneed fuori dall'intervallo: %u"
+
+#: dynobj.cc:621
+#, c-format
+msgid "verneed vn_next field out of range: %u"
+msgstr "campo vn_next verneed fuori dall'intervallo: %u"
+
+#: dynobj.cc:670
+msgid "size of dynamic symbols is not multiple of symbol size"
+msgstr "la dimensione dei simboli dinamici non è un multiplo della dimensione del simbolo"
+
+#: dynobj.cc:1435
+#, c-format
+msgid "symbol %s has undefined version %s"
+msgstr "il simbolo %s non ha una versione %s definita"
+
+#: ehframe.h:82
+msgid "** eh_frame_hdr"
+msgstr "** eh_frame_hdr"
+
+#: ehframe.h:353
+msgid "** eh_frame"
+msgstr "** eh_frame"
+
+#: errors.cc:81
+#, c-format
+msgid "%s: fatal error: "
+msgstr "%s: errore fatale: "
+
+#: errors.cc:92
+#, c-format
+msgid "%s: error: "
+msgstr "%s: errore: "
+
+#: errors.cc:104
+#, c-format
+msgid "%s: warning: "
+msgstr "%s: attenzione: "
+
+#: errors.cc:128
+#, c-format
+msgid "%s: %s: error: "
+msgstr "%s: %s: errore: "
+
+#: errors.cc:144
+#, c-format
+msgid "%s: %s: warning: "
+msgstr "%s: %s: attenzione: "
+
+#: errors.cc:167
+#, c-format
+msgid "%s: %s: error: undefined reference to '%s'\n"
+msgstr "%s: %s: errore: riferimento non definito a \"%s\"\n"
+
+#: errors.cc:172
+#, c-format
+msgid "%s: %s: error: undefined reference to '%s', version '%s'\n"
+msgstr "%s: %s: errore: riferimento non definito a \"%s\", versione \"%s\"\n"
+
+#: errors.cc:182
+#, c-format
+msgid "%s: "
+msgstr "%s: "
+
+#: expression.cc:172
+#, c-format
+msgid "undefined symbol '%s' referenced in expression"
+msgstr "simbolo \"%s\" non definito referenziato nell'espressione"
+
+#: expression.cc:209
+msgid "invalid reference to dot symbol outside of SECTIONS clause"
+msgstr "riferimento non valido al simbolo dot fuori della direttiva SECTIONS"
+
+#. Handle unary operators. We use a preprocessor macro as a hack to
+#. capture the C operator.
+#: expression.cc:278
+msgid "unary "
+msgstr "unario "
+
+#. 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.
+#: expression.cc:400
+msgid "binary "
+msgstr "binario "
+
+#: expression.cc:404
+msgid " by zero"
+msgstr " per zero"
+
+#: expression.cc:575
+msgid "max applied to section relative value"
+msgstr "massimo calcolato su un valore relativo alla sezione"
+
+#: expression.cc:610
+msgid "min applied to section relative value"
+msgstr "minimo calcolato su un valore relativo alla sezione"
+
+#: expression.cc:740
+msgid "aligning to section relative value"
+msgstr "allineamento al valore relativo della sezione"
+
+#: expression.cc:895
+#, c-format
+msgid "unknown constant %s"
+msgstr "costante %s sconosciuta"
+
+#: expression.cc:1126
+msgid "SEGMENT_START not implemented"
+msgstr "SEGMENT_START non implementata"
+
+#: expression.cc:1135
+msgid "ORIGIN not implemented"
+msgstr "ORIGIN non implementata"
+
+#: expression.cc:1141
+msgid "LENGTH not implemented"
+msgstr "LENGTH non implementata"
+
+#: fileread.cc:65
+#, c-format
+msgid "munmap failed: %s"
+msgstr "munmap non riuscita: %s"
+
+#: fileread.cc:129
+#, c-format
+msgid "%s: fstat failed: %s"
+msgstr "%s: fstat non riuscita: %s"
+
+#: fileread.cc:169
+#, c-format
+msgid "could not reopen file %s"
+msgstr "impossibile riaprire il file %s"
+
+#: fileread.cc:302
+#, c-format
+msgid "%s: pread failed: %s"
+msgstr "%s: pread non riuscita: %s"
+
+#: fileread.cc:308
+#, c-format
+msgid "%s: file too short: read only %lld of %lld bytes at %lld"
+msgstr "%s: file troppo corto: letti solo %lld di %lld byte alla %lld"
+
+#: fileread.cc:372
+#, c-format
+msgid "%s: attempt to map %lld bytes at offset %lld exceeds size of file; the file may be corrupt"
+msgstr "%s: il tentativo di mappare %lld byte alla posizione %lld supera la dimensione del file, che potrebbe essere corrotto"
+
+#: fileread.cc:402
+#, c-format
+msgid "%s: mmap offset %lld size %lld failed: %s"
+msgstr "%s: mmap alla posizione %lld di dimensione %lld non riuscita: %s"
+
+#: fileread.cc:548
+#, c-format
+msgid "%s: lseek failed: %s"
+msgstr "%s: lseek non riuscita: %s"
+
+#: fileread.cc:554
+#, c-format
+msgid "%s: readv failed: %s"
+msgstr "%s: readv non riuscita: %s"
+
+#: fileread.cc:557
+#, c-format
+msgid "%s: file too short: read only %zd of %zd bytes at %lld"
+msgstr "%s: file troppo corto: letti solo %zd di %zd byte alla %lld"
+
+#: fileread.cc:706
+#, c-format
+msgid "%s: total bytes mapped for read: %llu\n"
+msgstr "%s: byte totali mappati per la lettura: %llu\n"
+
+#: fileread.cc:708
+#, c-format
+msgid "%s: maximum bytes mapped for read at one time: %llu\n"
+msgstr "%s: byte massimi mappati alla volta per la lettura: %llu\n"
+
+#: fileread.cc:791
+#, c-format
+msgid "%s: stat failed: %s"
+msgstr "%s: stat non riuscita: %s"
+
+#: fileread.cc:849
+#, c-format
+msgid "cannot find %s%s"
+msgstr "impossibile trovare %s%s"
+
+#: fileread.cc:880
+#, c-format
+msgid "cannot find %s"
+msgstr "impossibile trovare %s"
+
+#: fileread.cc:904
+#, c-format
+msgid "cannot open %s: %s"
+msgstr "impossibile aprire %s: %s"
+
+#: gold-threads.cc:103
+#, c-format
+msgid "pthead_mutextattr_init failed: %s"
+msgstr "pthead_mutextattr_init non riuscita: %s"
+
+#: gold-threads.cc:107
+#, c-format
+msgid "pthread_mutextattr_settype failed: %s"
+msgstr "pthread_mutextattr_settype non riuscita: %s"
+
+#: gold-threads.cc:112
+#, c-format
+msgid "pthread_mutex_init failed: %s"
+msgstr "pthread_mutex_init non riuscita: %s"
+
+#: gold-threads.cc:116
+#, c-format
+msgid "pthread_mutexattr_destroy failed: %s"
+msgstr "pthread_mutexattr_destroy non riuscita: %s"
+
+#: gold-threads.cc:123
+#, c-format
+msgid "pthread_mutex_destroy failed: %s"
+msgstr "pthread_mutex_destroy non riuscita: %s"
+
+#: gold-threads.cc:131 gold-threads.cc:382
+#, c-format
+msgid "pthread_mutex_lock failed: %s"
+msgstr "pthread_mutex_lock non riuscita: %s"
+
+#: gold-threads.cc:139 gold-threads.cc:394
+#, c-format
+msgid "pthread_mutex_unlock failed: %s"
+msgstr "pthread_mutex_unlock non riuscita: %s"
+
+#: gold-threads.cc:220
+#, c-format
+msgid "pthread_cond_init failed: %s"
+msgstr "pthread_cond_init non riuscita: %s"
+
+#: gold-threads.cc:227
+#, c-format
+msgid "pthread_cond_destroy failed: %s"
+msgstr "pthread_cond_destroy non riuscita: %s"
+
+#: gold-threads.cc:236
+#, c-format
+msgid "pthread_cond_wait failed: %s"
+msgstr "pthread_cond_wait non riuscita: %s"
+
+#: gold-threads.cc:244
+#, c-format
+msgid "pthread_cond_signal failed: %s"
+msgstr "pthread_cond_signal non riuscita: %s"
+
+#: gold-threads.cc:252
+#, c-format
+msgid "pthread_cond_broadcast failed: %s"
+msgstr "pthread_cond_broadcast non riuscita: %s"
+
+#: gold-threads.cc:388
+#, c-format
+msgid "pthread_once failed: %s"
+msgstr "pthread_once non riuscita: %s"
+
+#: gold.cc:91
+#, c-format
+msgid "%s: internal error in %s, at %s:%d\n"
+msgstr "%s: errore interno in %s, in %s:%d\n"
+
+#: gold.cc:173
+msgid "no input files"
+msgstr "nessun file di input"
+
+#: gold.cc:226
+msgid "cannot mix -r with --gc-sections or --icf"
+msgstr "impossibile usare -r con --gc-sections o --icf"
+
+#: gold.cc:407
+#, c-format
+msgid "cannot mix -static with dynamic object %s"
+msgstr "impossibile usare -static con l'oggetto dinamico %s"
+
+#: gold.cc:411
+#, c-format
+msgid "cannot mix -r with dynamic object %s"
+msgstr "impossibile usare -r con l'oggetto dinamico %s"
+
+#: gold.cc:415
+#, c-format
+msgid "cannot use non-ELF output format with dynamic object %s"
+msgstr "impossibile usare un formato di output non ELF con l'oggetto dinamico %s"
+
+#: gold.cc:427
+#, c-format
+msgid "cannot mix split-stack '%s' and non-split-stack '%s' when using -r"
+msgstr "impossibile usare insieme \"%s\" split-stack e \"%s\" non-split-stack con l'opzione -r"
+
+#. FIXME: This needs to specify the location somehow.
+#: i386.cc:232 i386.cc:1669 sparc.cc:234 sparc.cc:2395 x86_64.cc:237
+#: x86_64.cc:1732
+msgid "missing expected TLS relocation"
+msgstr "manca la rilocazione TLS attesa"
+
+#: i386.cc:944 x86_64.cc:1068
+#, c-format
+msgid "section symbol %u has bad shndx %u"
+msgstr "simbolo di sezione %u con shndx %u errato"
+
+#: i386.cc:1036 i386.cc:1060 sparc.cc:1777 x86_64.cc:1176 x86_64.cc:1204
+#, c-format
+msgid "local symbol %u has bad shndx %u"
+msgstr "simbolo locale %u con shndx %u errato"
+
+#: i386.cc:1991
+msgid "both SUN and GNU model TLS relocations"
+msgstr "rilocazioni TLS sia modello SUN che GNU"
+
+#: i386.cc:2730 x86_64.cc:2719
+#, c-format
+msgid "failed to match split-stack sequence at section %u offset %0zx"
+msgstr "impossibile far corrispondere la sequenza split-stack alla sezione %u con posizione %0zx"
+
+#: icf.cc:616
+#, c-format
+msgid "%s: ICF Converged after %u iteration(s)"
+msgstr "%s: convergenza di ICF dopo %u iterazione(i)"
+
+#: icf.cc:619
+#, c-format
+msgid "%s: ICF stopped after %u iteration(s)"
+msgstr "%s: arresto di ICF dopo %u iterazione(i)"
+
+#: icf.cc:633
+#, c-format
+msgid "Could not find symbol %s to unfold\n"
+msgstr "Impossibile trovare il simbolo %s da espandere\n"
+
+#: incremental.cc:242
+#, c-format
+msgid "the link might take longer: cannot perform incremental link: %s"
+msgstr "il link potrebbe durare più tempo: impossibile effettuare il link incrementale: %s"
+
+#: incremental.cc:302
+msgid "no incremental data from previous build"
+msgstr "nessun dato incrementale dalla creazione precedente"
+
+#: incremental.cc:309 incremental.cc:332
+msgid "invalid incremental build data"
+msgstr "dati di creazione incrementale non validi"
+
+#: incremental.cc:321
+msgid "different version of incremental build data"
+msgstr "versione diversa dei dati di creazione incrementale"
+
+#: incremental.cc:338
+msgid "command line changed"
+msgstr "la riga di comando è cambiata"
+
+#: incremental.cc:362
+#, c-format
+msgid "unsupported ELF machine number %d"
+msgstr "numero di macchina ELF %d non supportata"
+
+#: incremental.cc:387
+msgid "output is not an ELF file."
+msgstr "l'output non è un file ELF."
+
+#: incremental.cc:410
+msgid "unsupported file: 32-bit, big-endian"
+msgstr "file non supportato: 32 bit, big-endian"
+
+#: incremental.cc:419
+msgid "unsupported file: 32-bit, little-endian"
+msgstr "file non supportato: 32 bit, little-endian"
+
+#: incremental.cc:431
+msgid "unsupported file: 64-bit, big-endian"
+msgstr "file non supportato: 64 bit, big-endian"
+
+#: incremental.cc:440
+msgid "unsupported file: 64-bit, little-endian"
+msgstr "file non supportato: 64 bit, little-endian"
+
+#: layout.cc:1887
+#, c-format
+msgid "--build-id=uuid failed: could not open /dev/urandom: %s"
+msgstr "--build-id=uuid non riuscita: impossibile aprire /dev/urandom: %s"
+
+#: layout.cc:1894
+#, c-format
+msgid "/dev/urandom: read failed: %s"
+msgstr "/dev/urandom: lettura non riuscita: %s"
+
+#: layout.cc:1896
+#, c-format
+msgid "/dev/urandom: expected %zu bytes, got %zd bytes"
+msgstr "/dev/urandom: attesi %zu byte, ottenuti %zd byte"
+
+#: layout.cc:1918
+#, c-format
+msgid "--build-id argument '%s' not a valid hex number"
+msgstr "l'argomento \"%s\" di --build-id non è un numero esadecimale valido"
+
+#: layout.cc:1924
+#, c-format
+msgid "unrecognized --build-id argument '%s'"
+msgstr "argomento \"%s\" di --build-id non riconosciuto"
+
+#: layout.cc:2337
+#, c-format
+msgid "load segment overlap [0x%llx -> 0x%llx] and [0x%llx -> 0x%llx]"
+msgstr "sovrapposizione del segmento di caricamento [0x%llx -> 0x%llx] e [0x%llx -> 0x%llx]"
+
+#: mapfile.cc:70
+#, c-format
+msgid "cannot open map file %s: %s"
+msgstr "impossibile aprire il file di mappa %s: %s"
+
+#: mapfile.cc:84
+#, c-format
+msgid "cannot close map file: %s"
+msgstr "impossibile chiudere il file di mappa: %s"
+
+#: mapfile.cc:116
+#, c-format
+msgid ""
+"Archive member included because of file (symbol)\n"
+"\n"
+msgstr ""
+"Incluso membro dell'archivio a causa del file (simbolo)\n"
+"\n"
+
+#: mapfile.cc:159
+#, c-format
+msgid ""
+"\n"
+"Allocating common symbols\n"
+msgstr ""
+"\n"
+"Allocazione dei simboli comuni\n"
+
+#: mapfile.cc:161
+#, c-format
+msgid ""
+"Common symbol size file\n"
+"\n"
+msgstr ""
+"Simbolo comune dimensione file\n"
+"\n"
+
+#: mapfile.cc:195
+#, c-format
+msgid ""
+"\n"
+"Memory map\n"
+"\n"
+msgstr ""
+"\n"
+"Mappa della memoria\n"
+"\n"
+
+#: mapfile.cc:361
+#, c-format
+msgid ""
+"\n"
+"Discarded input sections\n"
+"\n"
+msgstr ""
+"\n"
+"Sezioni di input scartate\n"
+"\n"
+
+#: merge.cc:455
+#, c-format
+msgid "%s: %s merged constants size: %lu; input: %zu; output: %zu\n"
+msgstr "%s: %s costanti unite, dimensione: %lu; input: %zu; output: %zu\n"
+
+#: merge.cc:478
+msgid "mergeable string section length not multiple of character size"
+msgstr "la lunghezza della sezione delle stringhe unibili non è un multiplo della dimensione carattere"
+
+#: merge.cc:494
+#, c-format
+msgid "%s: last entry in mergeable string section '%s' not null terminated"
+msgstr "%s: l'ultima voce nella sezione \"%s\" delle stringhe unibili non termina con un null"
+
+#: merge.cc:613
+#, c-format
+msgid "%s: %s input: %zu\n"
+msgstr "%s: %s input: %zu\n"
+
+#: merge.h:300
+msgid "** merge constants"
+msgstr "** unione delle costanti"
+
+#: merge.h:422
+msgid "** merge strings"
+msgstr "** unione delle stringhe"
+
+#: object.cc:75
+msgid "missing SHT_SYMTAB_SHNDX section"
+msgstr "sezione SHT_SYMTAB_SHNDX mancante"
+
+#: object.cc:119
+#, c-format
+msgid "symbol %u out of range for SHT_SYMTAB_SHNDX section"
+msgstr "simbolo %u fuori dall'intervallo per la sezione SHT_SYMTAB_SHNDX"
+
+#: object.cc:126
+#, c-format
+msgid "extended index for symbol %u out of range: %u"
+msgstr "indice esteso per il simbolo %u fuori dall'intervallo: %u"
+
+#: object.cc:148 object.cc:2331 output.cc:4052
+#, c-format
+msgid "%s: %s"
+msgstr "%s: %s"
+
+#: object.cc:190
+#, c-format
+msgid "section name section has wrong type: %u"
+msgstr "la sezione dei nomi di sezione è di tipo errato: %u"
+
+#: object.cc:546
+#, c-format
+msgid "invalid symbol table name index: %u"
+msgstr "indice dei nomi della tabella dei simboli non valido: %u"
+
+#: object.cc:552
+#, c-format
+msgid "symbol table name section has wrong type: %u"
+msgstr "la sezione dei nomi delle tabelle dei simboli è di tipo errato: %u"
+
+#: object.cc:641
+#, c-format
+msgid "section group %u info %u out of range"
+msgstr "gruppo di sezione %u con informazioni %u fuori dall'intervallo"
+
+#: object.cc:660
+#, c-format
+msgid "symbol %u name offset %u out of range"
+msgstr "simbolo %u con posizione del nome %u fuori dall'intervallo"
+
+#: object.cc:678
+#, c-format
+msgid "symbol %u invalid section index %u"
+msgstr "simbolo %u con indice di sezione non valido %u"
+
+#: object.cc:723
+#, c-format
+msgid "section %u in section group %u out of range"
+msgstr "sezione %u nel gruppo di sezione %u fuori dell'intervallo"
+
+#: object.cc:731
+#, c-format
+msgid "invalid section group %u refers to earlier section %u"
+msgstr "il gruppo di sezione non valido %u fa riferimento alla sezione precedente %u"
+
+#: object.cc:1037 reloc.cc:271 reloc.cc:838
+#, c-format
+msgid "relocation section %u has bad info %u"
+msgstr "la sezione di rilocazione %u ha informazioni %u errate"
+
+#: object.cc:1231
+#, c-format
+msgid "%s: removing unused section from '%s' in file '%s'"
+msgstr "%s: rimozione da \"%s\" della sezione inutilizzata nel file \"%s\""
+
+#: object.cc:1257
+#, c-format
+msgid "%s: ICF folding section '%s' in file '%s'into '%s' in file '%s'"
+msgstr "%s: ripiegamento ICF della sezione \"%s\" nel file \"%s\" dentro a \"%s\" nel file \"%s\""
+
+#: object.cc:1454
+msgid "size of symbols is not multiple of symbol size"
+msgstr "la dimensione dei simboli non è un multiplo di quella del simbolo"
+
+#: object.cc:1563
+#, c-format
+msgid "local symbol %u section name out of range: %u >= %u"
+msgstr "il simbolo locale %u ha il nome di sezione fuori dall'intervallo: %u >= %u"
+
+#: object.cc:1652
+#, c-format
+msgid "unknown section index %u for local symbol %u"
+msgstr "indice della sezione %u sconosciuto per il simbolo locale %u"
+
+#: object.cc:1661
+#, c-format
+msgid "local symbol %u section index %u out of range"
+msgstr "il simbolo locale %u ha l'indice di sezione %u fuori dall'intervallo"
+
+#: object.cc:2169
+#, c-format
+msgid "%s is not supported but is required for %s in %s"
+msgstr "%s non è supportato ma è richiesto per %s in %s"
+
+#: object.cc:2273
+#, c-format
+msgid "%s: unsupported ELF machine number %d"
+msgstr "%s: numero di macchina ELF %d non supportato"
+
+#: object.cc:2283
+#, c-format
+msgid "%s: incompatible target"
+msgstr "%s: obiettivo incompatibile"
+
+#: object.cc:2347 plugin.cc:1019
+#, c-format
+msgid "%s: not configured to support 32-bit big-endian object"
+msgstr "%s: non configurato per supportare gli oggetti a 32 bit big-endian"
+
+#: object.cc:2363 plugin.cc:1028
+#, c-format
+msgid "%s: not configured to support 32-bit little-endian object"
+msgstr "%s: non configurato per supportare gli oggetti a 32 bit little-endian"
+
+#: object.cc:2382 plugin.cc:1040
+#, c-format
+msgid "%s: not configured to support 64-bit big-endian object"
+msgstr "%s: non configurato per supportare gli oggetti a 64 bit big-endian"
+
+#: object.cc:2398 plugin.cc:1049
+#, c-format
+msgid "%s: not configured to support 64-bit little-endian object"
+msgstr "%s: non configurato per supportare gli oggetti a 64 bit little-endian"
+
+#: options.cc:156
+#, c-format
+msgid ""
+"Usage: %s [options] file...\n"
+"Options:\n"
+msgstr ""
+"Uso: %s [opzioni] file...\n"
+"Opzioni:\n"
+
+#. config.guess and libtool.m4 look in ld --help output for the
+#. string "supported targets".
+#: options.cc:164
+#, c-format
+msgid "%s: supported targets:"
+msgstr "%s: obiettivi supportati:"
+
+#: options.cc:176
+#, c-format
+msgid "Report bugs to %s\n"
+msgstr "Segnalare i bug su %s\n"
+
+#: options.cc:193 options.cc:203 options.cc:213
+#, c-format
+msgid "%s: invalid option value (expected an integer): %s"
+msgstr "%s: valore dell'opzione non valido (atteso un intero): %s"
+
+#: options.cc:223
+#, c-format
+msgid "%s: invalid option value (expected a floating point number): %s"
+msgstr "%s: valore dell'opzione non valido (atteso un numero in virgola mobile): %s"
+
+#: options.cc:232
+#, c-format
+msgid "%s: must take a non-empty argument"
+msgstr "%s: necessita di un argomento non vuoto"
+
+#: options.cc:273
+#, c-format
+msgid "%s: must take one of the following arguments: %s"
+msgstr "%s: necessita di uno tra i seguenti argomenti: %s"
+
+#: options.cc:300
+#, c-format
+msgid " Supported targets:\n"
+msgstr " Obiettivi supportati:\n"
+
+#: options.cc:409
+#, c-format
+msgid "unable to parse script file %s"
+msgstr "impossibile analizzare lo script %s"
+
+#: options.cc:417
+#, c-format
+msgid "unable to parse version script file %s"
+msgstr "impossibile analizzare lo script di versione %s"
+
+#: options.cc:425
+#, c-format
+msgid "unable to parse dynamic-list script file %s"
+msgstr "impossibile analizzare lo script dell'elenco dinamico %s"
+
+#: options.cc:522
+#, c-format
+msgid "format '%s' not supported; treating as elf (supported formats: elf, binary)"
+msgstr "formato \"%s\" non supportato; viene trattato come elf (formati supportati: elf, binario)"
+
+#: options.cc:538
+#, c-format
+msgid "%s: use the --help option for usage information\n"
+msgstr "%s: usare l'opzione --help per le informazioni sull'uso\n"
+
+#: options.cc:547
+#, c-format
+msgid "%s: %s: %s\n"
+msgstr "%s: %s: %s\n"
+
+#: options.cc:651
+msgid "unexpected argument"
+msgstr "argomento inatteso"
+
+#: options.cc:664 options.cc:725
+msgid "missing argument"
+msgstr "argomento mancante"
+
+#: options.cc:736
+msgid "unknown -z option"
+msgstr "opzione -z sconosciuta"
+
+#: options.cc:935
+#, c-format
+msgid "ignoring --threads: %s was compiled without thread support"
+msgstr "ignorata l'opzione --threads: %s compilato senza supporto per il threading"
+
+#: options.cc:942
+#, c-format
+msgid "ignoring --thread-count: %s was compiled without thread support"
+msgstr "ignorata l'opzione --thread-count: %s compilato senza supporto per il threading"
+
+#: options.cc:981
+#, c-format
+msgid "unable to open -retain-symbols-file file %s: %s"
+msgstr "impossibile aprire il file -retain-symbols-file %s: %s"
+
+#: options.cc:1003
+msgid "-shared and -static are incompatible"
+msgstr "-shared e -static sono incompatibili"
+
+#: options.cc:1005
+msgid "-shared and -pie are incompatible"
+msgstr "-shared e -pie sono incompatibili"
+
+#: options.cc:1008
+msgid "-shared and -r are incompatible"
+msgstr "-shared e -r sono incompatibili"
+
+#: options.cc:1010
+msgid "-pie and -r are incompatible"
+msgstr "-pie e -r sono incompatibili"
+
+#: options.cc:1014
+msgid "-retain-symbols-file does not yet work with -r"
+msgstr "-retain-symbols-file non può ancora essere usato con -r"
+
+#: options.cc:1020
+msgid "binary output format not compatible with -shared or -pie or -r"
+msgstr "il formato di output binario non è compatibile con -shared, -pie o -r"
+
+#: options.cc:1026
+#, c-format
+msgid "--hash-bucket-empty-fraction value %g out of range [0.0, 1.0)"
+msgstr "valore %g di --hash-bucket-empty-fraction fuori dall'intervallo [0.0, 1.0)"
+
+#: options.cc:1031
+msgid "Options --incremental-changed, --incremental-unchanged, --incremental-unknown require the use of --incremental"
+msgstr "Le opzioni --incremental-changed, --incremental-unchanged, --incremental-unknown richiedono l'uso di --incremental"
+
+#: options.cc:1097
+msgid "May not nest groups"
+msgstr "Non può nidificare i gruppi"
+
+#: options.cc:1109
+msgid "Group end without group start"
+msgstr "Il gruppo termina senza essere iniziato"
+
+#. I guess it's neither a long option nor a short option.
+#: options.cc:1174
+msgid "unknown option"
+msgstr "opzione sconosciuta"
+
+#: options.cc:1201
+#, c-format
+msgid "%s: missing group end\n"
+msgstr "%s: manca la fine del gruppo\n"
+
+#: options.h:571
+msgid "Report usage information"
+msgstr "Mostra le informazioni sull'uso"
+
+#: options.h:573
+msgid "Report version information"
+msgstr "Mostra le informazioni sulla versione"
+
+#: options.h:575
+msgid "Report version and target information"
+msgstr "Mostra la versione e le informazioni sugli obiettivi"
+
+#: options.h:584 options.h:635
+msgid "Not supported"
+msgstr "Non supportata"
+
+#: options.h:585 options.h:636
+msgid "Do not copy DT_NEEDED tags from shared libraries"
+msgstr "Non copia i tag DT_NEEDED dalle librerie condivise"
+
+#: options.h:588
+msgid "Allow unresolved references in shared libraries"
+msgstr "Ammette riferimenti non risolti nelle librerie condivise"
+
+#: options.h:589
+msgid "Do not allow unresolved references in shared libraries"
+msgstr "Non ammette riferimenti non risolti nelle librerie condivise"
+
+#: options.h:592
+msgid "Only set DT_NEEDED for shared libraries if used"
+msgstr "Imposta DT_NEEDED per le librerie condivise solo se usate"
+
+#: options.h:593
+msgid "Always DT_NEEDED for shared libraries"
+msgstr "Imposta sempre DT_NEEDED per le librerie condivise"
+
+#: options.h:600
+msgid "Set input format"
+msgstr "Imposta il formato di input"
+
+#: options.h:603
+msgid "-l searches for shared libraries"
+msgstr "-l cerca le librerie condivise"
+
+#: options.h:605
+msgid "-l does not search for shared libraries"
+msgstr "-l non cerca le librerie condivise"
+
+#: options.h:609
+msgid "Bind defined symbols locally"
+msgstr "Associa localmente i simboli definiti"
+
+#: options.h:612
+msgid "Bind defined function symbols locally"
+msgstr "Associa localmente i simboli definiti delle funzioni"
+
+#: options.h:615
+msgid "Generate build ID note"
+msgstr "Genera la nota ID di creazione"
+
+#: options.h:616 options.h:655
+msgid "[=STYLE]"
+msgstr "[=STILE]"
+
+#: options.h:619
+msgid "Check segment addresses for overlaps (default)"
+msgstr "Controlla le sovrapposizioni di segmenti negli indirizzi (predefinito)"
+
+#: options.h:620
+msgid "Do not check segment addresses for overlaps"
+msgstr "Non controlla le sovrapposizioni di segmenti negli indirizzi"
+
+#: options.h:624 options.h:629
+msgid "Compress .debug_* sections in the output file"
+msgstr "Comprime le sezioni .debug_* nel file di output"
+
+#: options.h:630
+msgid "[none]"
+msgstr "[nessuna]"
+
+#: options.h:639
+msgid "Define common symbols"
+msgstr "Definisce i simboli comuni"
+
+#: options.h:640
+msgid "Do not define common symbols"
+msgstr "Non definisce i simboli comuni"
+
+#: options.h:642 options.h:644
+msgid "Alias for -d"
+msgstr "Sinonimo per -d"
+
+#: options.h:647
+msgid "Turn on debugging"
+msgstr "Abilita il debug"
+
+#: options.h:648
+msgid "[all,files,script,task][,...]"
+msgstr "[all,files,script,task][,...]"
+
+#: options.h:651
+msgid "Define a symbol"
+msgstr "Definisce un simbolo"
+
+#: options.h:651
+msgid "SYMBOL=EXPRESSION"
+msgstr "SIMBOLO=ESPRESSIONE"
+
+#: options.h:654
+msgid "Demangle C++ symbols in log messages"
+msgstr "Decodifica i simboli C++ nei messaggi di log"
+
+#: options.h:658
+msgid "Do not demangle C++ symbols in log messages"
+msgstr "Non decodifica i simboli C++ nei messaggi di log"
+
+#: options.h:662
+msgid "Try to detect violations of the One Definition Rule"
+msgstr "Prova a rilevare violazioni alla regola della definizione unica (ODR)"
+
+#: options.h:666
+msgid "Delete all temporary local symbols"
+msgstr "Elimina tutti i simboli locali temporanei"
+
+#: options.h:669
+msgid "Add data symbols to dynamic symbols"
+msgstr "Aggiunge i simboli di dati ai simboli dinamici"
+
+#: options.h:672
+msgid "Add C++ operator new/delete to dynamic symbols"
+msgstr "Aggiunge l'operatore C++ new/delete ai simboli dinamici"
+
+#: options.h:675
+msgid "Add C++ typeinfo to dynamic symbols"
+msgstr "Aggiunge la classe C++ typeinfo ai simboli dinamici"
+
+#: options.h:678
+msgid "Read a list of dynamic symbols"
+msgstr "Legge un elenco di simboli dinamici"
+
+#: options.h:678 options.h:732 options.h:766 options.h:893 options.h:921
+msgid "FILE"
+msgstr "FILE"
+
+#: options.h:681
+msgid "Set program start address"
+msgstr "Imposta l'indirizzo di partenza del programma"
+
+#: options.h:681 options.h:908 options.h:910 options.h:912
+msgid "ADDRESS"
+msgstr "INDIRIZZO"
+
+#: options.h:684
+msgid "Exclude libraries from automatic export"
+msgstr "Esclude le librerie dall'esportazione automatica"
+
+#: options.h:688
+msgid "Export all dynamic symbols"
+msgstr "Esporta tutti i simboli dinamici"
+
+#: options.h:689
+msgid "Do not export all dynamic symbols (default)"
+msgstr "Non esporta tutti i simboli dinamici (predefinito)"
+
+#: options.h:692
+msgid "Create exception frame header"
+msgstr "Crea l'intestazione del frame di eccezione"
+
+#: options.h:695
+msgid "Treat warnings as errors"
+msgstr "Considera gli avvertimenti come errori"
+
+#: options.h:696
+msgid "Do not treat warnings as errors"
+msgstr "Non considera gli avvertimenti come errori"
+
+#: options.h:699
+msgid "Call SYMBOL at unload-time"
+msgstr "Chiama il SIMBOLO quando viene eseguito l'unload"
+
+#: options.h:699 options.h:729 options.h:873 options.h:915 options.h:936
+#: options.h:939
+msgid "SYMBOL"
+msgstr "SIMBOLO"
+
+#: options.h:702
+msgid "Set shared library name"
+msgstr "Imposta il nome della libreria condivisa"
+
+#: options.h:702 options.h:792
+msgid "FILENAME"
+msgstr "NOMEFILE"
+
+#: options.h:705
+msgid "Min fraction of empty buckets in dynamic hash"
+msgstr "Frazione minima di bucket vuoti nell'hash dinamico"
+
+#: options.h:706
+msgid "FRACTION"
+msgstr "FRAZIONE"
+
+#: options.h:709
+msgid "Dynamic hash style"
+msgstr "Stile dell'hash dinamico"
+
+#: options.h:709
+msgid "[sysv,gnu,both]"
+msgstr "[sysv,gnu,both]"
+
+#: options.h:713
+msgid "Set dynamic linker path"
+msgstr "Imposta il percorso del linker dinamico"
+
+#: options.h:713
+msgid "PROGRAM"
+msgstr "PROGRAMMA"
+
+#: options.h:716
+msgid "Work in progress; do not use"
+msgstr "Lavori in corso; non usare"
+
+#: options.h:717
+msgid "Do a full build"
+msgstr "Esegue una creazione completa"
+
+#: options.h:720
+msgid "Assume files changed"
+msgstr "Assume i file come modificati"
+
+#: options.h:723
+msgid "Assume files didn't change"
+msgstr "Assume i file come non modificati"
+
+#: options.h:726
+msgid "Use timestamps to check files (default)"
+msgstr "Effettua un controllo temporale sui file (predefinito)"
+
+#: options.h:729
+msgid "Call SYMBOL at load-time"
+msgstr "Chiama il SIMBOLO quando viene eseguito il load"
+
+#: options.h:732
+msgid "Read only symbol values from FILE"
+msgstr "Legge solo i valori dei simboli dal FILE"
+
+#: options.h:735
+msgid "Search for library LIBNAME"
+msgstr "Cerca la libreria NOMELIB"
+
+#: options.h:735
+msgid "LIBNAME"
+msgstr "NOMELIB"
+
+#: options.h:738
+msgid "Add directory to search path"
+msgstr "Aggiunge la directory al percorso di ricerca"
+
+#: options.h:738 options.h:813 options.h:816 options.h:820 options.h:887
+msgid "DIR"
+msgstr "DIR"
+
+#: options.h:741
+msgid "Ignored for compatibility"
+msgstr "Ignorato per compatibilità"
+
+#: options.h:741
+msgid "EMULATION"
+msgstr "EMULAZIONE"
+
+#: options.h:744
+msgid "Write map file on standard output"
+msgstr "Scrive il file di mappa sullo standard output"
+
+#: options.h:745
+msgid "Write map file"
+msgstr "Scrive il file di mappa"
+
+#: options.h:746
+msgid "MAPFILENAME"
+msgstr "NOMEFILEMAPPA"
+
+#: options.h:749
+msgid "Do not page align data"
+msgstr "Non allinea i dati alla pagina"
+
+#: options.h:751
+msgid "Do not page align data, do not make text readonly"
+msgstr "Non allinea i dati alla pagina, non imposta il testo in sola lettura"
+
+#: options.h:752
+msgid "Page align data, make text readonly"
+msgstr "Allinea i dati alla pagina, imposta il testo in sola lettura"
+
+#: options.h:755
+msgid "Enable use of DT_RUNPATH and DT_FLAGS"
+msgstr "Abilita l'uso di DT_RUNPATH e DT_FLAGS"
+
+#: options.h:756
+msgid "Disable use of DT_RUNPATH and DT_FLAGS"
+msgstr "Disabilita l'uso di DT_RUNPATH e DT_FLAGS"
+
+#: options.h:759
+msgid "Create an output file even if errors occur"
+msgstr "Crea un file di output anche in presenza di errori"
+
+#: options.h:762 options.h:958
+msgid "Report undefined symbols (even with --shared)"
+msgstr "Segnala i simboli indefiniti (anche con --shared)"
+
+#: options.h:766
+msgid "Set output file name"
+msgstr "Imposta il nome del file di output"
+
+#: options.h:769
+msgid "Optimize output file size"
+msgstr "Ottimizza la dimensione del file di output"
+
+#: options.h:769
+msgid "LEVEL"
+msgstr "LIVELLO"
+
+#: options.h:772
+msgid "Set output format"
+msgstr "Imposta il formato di output"
+
+#: options.h:772
+msgid "[binary]"
+msgstr "[binario]"
+
+#: options.h:775 options.h:777
+msgid "Create a position independent executable"
+msgstr "Crea un eseguibile indipendente dalla posizione"
+
+#: options.h:782
+msgid "Load a plugin library"
+msgstr "Carica una libreria di plugin"
+
+#: options.h:782
+msgid "PLUGIN"
+msgstr "PLUGIN"
+
+#: options.h:784
+msgid "Pass an option to the plugin"
+msgstr "Passa un'opzione al plugin"
+
+#: options.h:784
+msgid "OPTION"
+msgstr "OPZIONE"
+
+#: options.h:788
+msgid "Preread archive symbols when multi-threaded"
+msgstr "Esegue una pre-lettura dei simboli di archivio in caso di multi-threading"
+
+#: options.h:791
+msgid "Print symbols defined and used for each input"
+msgstr "Stampa i simboli definiti e usati per ogni input"
+
+#: options.h:795
+msgid "Ignored for SVR4 compatibility"
+msgstr "Ignorato per compatibilità con SVR4"
+
+#: options.h:798
+msgid "Generate relocations in output"
+msgstr "Genera le rilocazioni in output"
+
+#: options.h:801
+msgid "Generate relocatable output"
+msgstr "Genera output rilocabili"
+
+#: options.h:804
+msgid "Relax branches on certain targets"
+msgstr "Rilassa i rami su certi obiettivi"
+
+#: options.h:807
+msgid "keep only symbols listed in this file"
+msgstr "tiene solo i simboli elencati in questo file"
+
+#: options.h:807
+msgid "[file]"
+msgstr "[file]"
+
+#: options.h:813 options.h:816
+msgid "Add DIR to runtime search path"
+msgstr "Aggiunge DIR al percorso di ricerca in esecuzione"
+
+#: options.h:819
+msgid "Add DIR to link time shared library search path"
+msgstr "Aggiunge DIR al percorso di ricerca delle librerie condivise necessarie al linker"
+
+#: options.h:823
+msgid "Strip all symbols"
+msgstr "Elimina tutti i simboli"
+
+#: options.h:825
+msgid "Strip debugging information"
+msgstr "Elimina le informazioni di debug"
+
+#: options.h:827
+msgid "Emit only debug line number information"
+msgstr "Emette solo le informazioni sul numero di riga di debug"
+
+#: options.h:829
+msgid "Strip debug symbols that are unused by gdb (at least versions <= 6.7)"
+msgstr "Elimina i simboli di debug che sono inutilizzati da gdb (almeno nelle versioni <= 6.7)"
+
+#: options.h:832
+msgid "Strip LTO intermediate code sections"
+msgstr "Rimuove le sezioni di codice intermedie LTO"
+
+#: options.h:835
+msgid "(ARM only) The maximum distance from instructions in a group of sections to their stubs. Negative values mean stubs are always after the group. 1 means using default size.\n"
+msgstr "(solo ARM) La distanza massima dalle istruzioni in un gruppo di sezioni ai loro stub. Valori negativi corrispondono a stub che sono sempre dopo il gruppo, 1 significa usare la dimensione predefinita.\n"
+
+#: options.h:838 options.h:852 options.h:956 options.h:975
+msgid "SIZE"
+msgstr "DIMENSIONE"
+
+#: options.h:841
+msgid "Use less memory and more disk I/O (included only for compatibility with GNU ld)"
+msgstr "Usa meno memoria e più I/O del disco (incluso solo per compatibilità con ld di GNU)"
+
+#: options.h:845 options.h:848
+msgid "Generate shared library"
+msgstr "Genera una libreria condivisa"
+
+#: options.h:851
+msgid "Stack size when -fsplit-stack function calls non-split"
+msgstr "Dimensione dello stack quando la funzione -fsplit-stack chiama non-split"
+
+#: options.h:857
+msgid "Do not link against shared libraries"
+msgstr "Non esegue il link alle librerie condivise"
+
+#: options.h:860
+msgid "Identical Code Folding. '--icf=safe' folds only ctors and dtors."
+msgstr "Ripiegamento di codice identico (ICF). \"--icf=safe\" ripiega solo ctors e dtors."
+
+#: options.h:866
+msgid "Number of iterations of ICF (default 2)"
+msgstr "Numero di iterazioni di ICF (predefinito 2)"
+
+#: options.h:866 options.h:899 options.h:901 options.h:903 options.h:905
+msgid "COUNT"
+msgstr "NUMERO"
+
+#: options.h:869
+msgid "List folded identical sections on stderr"
+msgstr "Elenca le sezioni ripiegate identiche sullo stderr"
+
+#: options.h:870
+msgid "Do not list folded identical sections"
+msgstr "Non elenca le sezioni ripiegate identiche"
+
+#: options.h:873
+msgid "Do not fold this symbol during ICF"
+msgstr "Non ripiega questo simbolo durante l'ICF"
+
+#: options.h:876
+msgid "Remove unused sections"
+msgstr "Rimuove le sezioni inutilizzate"
+
+#: options.h:877
+msgid "Don't remove unused sections (default)"
+msgstr "Non rimuove le sezioni inutilizzate (predefinito)"
+
+#: options.h:880
+msgid "List removed unused sections on stderr"
+msgstr "Elenca le sezioni inutilizzate rimosse su stderr"
+
+#: options.h:881
+msgid "Do not list removed unused sections"
+msgstr "Non elenca le sezioni inutilizzate rimosse"
+
+#: options.h:884
+msgid "Print resource usage statistics"
+msgstr "Stampa le statistiche sull'uso delle risorse"
+
+#: options.h:887
+msgid "Set target system root directory"
+msgstr "Imposta la directory root del sistema obiettivo"
+
+#: options.h:890
+msgid "Print the name of each input file"
+msgstr "Stampa il nome di ciascun file di input"
+
+#: options.h:893
+msgid "Read linker script"
+msgstr "Legge lo script del linker"
+
+#: options.h:896
+msgid "Run the linker multi-threaded"
+msgstr "Esegue il linker con thread multiplo"
+
+#: options.h:897
+msgid "Do not run the linker multi-threaded"
+msgstr "Non esegue il linker con thread multiplo"
+
+#: options.h:899
+msgid "Number of threads to use"
+msgstr "Numero di thread da usare"
+
+#: options.h:901
+msgid "Number of threads to use in initial pass"
+msgstr "Numero di thread da usare nella passata iniziale"
+
+#: options.h:903
+msgid "Number of threads to use in middle pass"
+msgstr "Numero di thread da usare nella passata intermedia"
+
+#: options.h:905
+msgid "Number of threads to use in final pass"
+msgstr "Numero di thread da usare nella passata finale"
+
+#: options.h:908
+msgid "Set the address of the bss segment"
+msgstr "Imposta l'indirizzo del segmento bss"
+
+#: options.h:910
+msgid "Set the address of the data segment"
+msgstr "Imposta l'indirizzo del segmento data"
+
+#: options.h:912
+msgid "Set the address of the text segment"
+msgstr "Imposta l'indirizzo del segmento text"
+
+#: options.h:915
+msgid "Create undefined reference to SYMBOL"
+msgstr "Crea riferimenti non definiti al SIMBOLO"
+
+#: options.h:918
+msgid "Synonym for --debug=files"
+msgstr "Sinonimo per --debug=file"
+
+#: options.h:921
+msgid "Read version script"
+msgstr "Legge lo script di versione"
+
+#: options.h:924
+msgid "Warn about duplicate common symbols"
+msgstr "Avvisa in caso di simboli comuni duplicati"
+
+#: options.h:925
+msgid "Do not warn about duplicate common symbols (default)"
+msgstr "Non avvisa in caso di simboli comuni duplicati (predefinito)"
+
+#: options.h:928
+msgid "Warn when skipping an incompatible library"
+msgstr "Avverte quando viene saltata una libreria incompatibile"
+
+#: options.h:929
+msgid "Don't warn when skipping an incompatible library"
+msgstr "Non avverte quando viene saltata una libreria incompatibile"
+
+#: options.h:932
+msgid "Include all archive contents"
+msgstr "Include tutto il contenuto dell'archivio"
+
+#: options.h:933
+msgid "Include only needed archive contents"
+msgstr "Include solo i contenuti necessari dell'archivio"
+
+#: options.h:936
+msgid "Use wrapper functions for SYMBOL"
+msgstr "Usa le funzioni wrapper per il SIMBOLO"
+
+#: options.h:939
+msgid "Trace references to symbol"
+msgstr "Traccia i riferimenti al simbolo"
+
+#: options.h:942
+msgid "Default search path for Solaris compatibility"
+msgstr "Percorso di ricerca predefinito per compatibilità con Solaris"
+
+#: options.h:943
+msgid "PATH"
+msgstr "PERCORSO"
+
+#: options.h:946
+msgid "Start a library search group"
+msgstr "Avvia un gruppo di ricerca di librerie"
+
+#: options.h:948
+msgid "End a library search group"
+msgstr "Termina un gruppo di ricerca di librerie"
+
+#: options.h:953
+msgid "Sort dynamic relocs"
+msgstr "Ordina le rilocazioni dinamiche"
+
+#: options.h:954
+msgid "Do not sort dynamic relocs"
+msgstr "Non ordina le rilocazioni dinamiche"
+
+#: options.h:956
+msgid "Set common page size to SIZE"
+msgstr "Imposta la dimensione comune della pagina a DIMENSIONE"
+
+#: options.h:961
+msgid "Mark output as requiring executable stack"
+msgstr "Marca l'output come richiedente uno stack eseguibile"
+
+#: options.h:963
+msgid "Mark DSO to be initialized first at runtime"
+msgstr "Marca DSO per essere inizializzato per primo durante l'esecuzione"
+
+#: options.h:966
+msgid "Mark object to interpose all DSOs but executable"
+msgstr "Marca l'oggetto per interporre tutti i DSO ad eccezione degli eseguibili"
+
+#: options.h:969
+msgid "Mark object for lazy runtime binding (default)"
+msgstr "Marca l'oggetto per l'associazione durante l'esecuzione apatica (predefinita)"
+
+#: options.h:972
+msgid "Mark object requiring immediate process"
+msgstr "Marca l'oggetto come richiedente una elaborazione immediata"
+
+#: options.h:975
+msgid "Set maximum page size to SIZE"
+msgstr "Imposta la dimensione massima della pagina a DIMENSIONE"
+
+#: options.h:978
+msgid "Do not create copy relocs"
+msgstr "Non crea rilocazioni copia"
+
+#: options.h:980
+msgid "Mark object not to use default search paths"
+msgstr "Marca l'oggetto per non usare i percorsi di ricerca predefiniti"
+
+#: options.h:983
+msgid "Mark DSO non-deletable at runtime"
+msgstr "Marca DSO come non eliminabile durante l'esecuzione"
+
+#: options.h:986
+msgid "Mark DSO not available to dlopen"
+msgstr "Marca DSO come non disponibile per dlopen"
+
+#: options.h:989
+msgid "Mark DSO not available to dldump"
+msgstr "Marca DSO come non disponibile per dldump"
+
+#: options.h:992
+msgid "Mark output as not requiring executable stack"
+msgstr "Marca l'output come non richiedente uno stack eseguibile"
+
+#: options.h:994
+msgid "Mark object for immediate function binding"
+msgstr "Marca l'oggetto per l'associazione alla funziona immediata"
+
+#: options.h:997
+msgid "Mark DSO to indicate that needs immediate $ORIGIN processing at runtime"
+msgstr "Marca DSO per indicare che necessita dell'elaborazione dell'immediato $ORIGIN durante l'esecuzione"
+
+#: options.h:1000
+msgid "Where possible mark variables read-only after relocation"
+msgstr "Dove possibile contrassegna in sola lettura le variabili dopo la rilocazione"
+
+#: options.h:1001
+msgid "Don't mark variables read-only after relocation"
+msgstr "Non contrassegna in sola lettura le variabili dopo la rilocazione"
+
+#: output.cc:1132
+msgid "section group retained but group element discarded"
+msgstr "gruppo di sezione conservato ma elemento del gruppo scartato"
+
+#: output.cc:1860
+#, c-format
+msgid "invalid alignment %lu for section \"%s\""
+msgstr "allineamento %lu non valido per la sezione \"%s\""
+
+#: output.cc:3573
+#, c-format
+msgid "dot moves backward in linker script from 0x%llx to 0x%llx"
+msgstr "nello script del linker dot retrocede da 0x%llx a 0x%llx"
+
+#: output.cc:3576
+#, c-format
+msgid "address of section '%s' moves backward from 0x%llx to 0x%llx"
+msgstr "l'indirizzo della sezione \"%s\" retrocede da 0x%llx a 0x%llx"
+
+#: output.cc:3755
+#, c-format
+msgid "nobits section %s may not precede progbits section %s in same segment"
+msgstr "la sezione nobits %s non può precedere la sezione progbits %s nello stesso segmento"
+
+#: output.cc:3907 output.cc:3975
+#, c-format
+msgid "%s: open: %s"
+msgstr "%s: open: %s"
+
+#: output.cc:3996
+#, c-format
+msgid "%s: mremap: %s"
+msgstr "%s: mremap: %s"
+
+#: output.cc:4005
+#, c-format
+msgid "%s: mmap: %s"
+msgstr "%s: mmap: %s"
+
+#: output.cc:4085
+#, c-format
+msgid "%s: mmap: failed to allocate %lu bytes for output file: %s"
+msgstr "%s: mmap: impossibile allocare %lu byte per il file di output: %s"
+
+#: output.cc:4096
+#, c-format
+msgid "%s: munmap: %s"
+msgstr "%s: munmap: %s"
+
+#: output.cc:4115
+#, c-format
+msgid "%s: write: unexpected 0 return-value"
+msgstr "%s: write: restituito il valore inaspettato 0"
+
+#: output.cc:4117
+#, c-format
+msgid "%s: write: %s"
+msgstr "%s: write: %s"
+
+#: output.cc:4132
+#, c-format
+msgid "%s: close: %s"
+msgstr "%s: close: %s"
+
+#: output.h:520
+msgid "** section headers"
+msgstr "** intestazioni di sezione"
+
+#: output.h:565
+msgid "** segment headers"
+msgstr "** intestazioni di segmento"
+
+#: output.h:613
+msgid "** file header"
+msgstr "** intestazione del file"
+
+#: output.h:833
+msgid "** fill"
+msgstr "** riempimento"
+
+#: output.h:987
+msgid "** string table"
+msgstr "** tabella di stringhe"
+
+#: output.h:1300
+msgid "** dynamic relocs"
+msgstr "** rilocazioni dinamiche"
+
+#: output.h:1301 output.h:1637
+msgid "** relocs"
+msgstr "** rilocazioni"
+
+#: output.h:1662
+msgid "** group"
+msgstr "** gruppo"
+
+#: output.h:1774
+msgid "** GOT"
+msgstr "** GOT"
+
+#: output.h:1916
+msgid "** dynamic"
+msgstr "** dinamico"
+
+#: output.h:2039
+msgid "** symtab xindex"
+msgstr "** xindex symtab"
+
+#: parameters.cc:172
+#, c-format
+msgid "unrecognized output format %s"
+msgstr "formato di output non riconosciuto %s"
+
+#: plugin.cc:106
+#, c-format
+msgid "%s: could not load plugin library"
+msgstr "%s: impossibile caricare la libreria di plugin"
+
+#: plugin.cc:116
+#, c-format
+msgid "%s: could not find onload entry point"
+msgstr "%s: impossibile trovare il punto di ingresso di onload"
+
+#: plugin.cc:426
+msgid "Input files added by plug-ins in --incremental mode not supported yet.\n"
+msgstr "File di input aggiunti dai plugin in modalità --incremental non ancora supportati.\n"
+
+#: powerpc.cc:1502 sparc.cc:2307 x86_64.cc:1632
+#, c-format
+msgid "%s: unsupported REL reloc section"
+msgstr "%s: sezione di rilocazione REL non supportata"
+
+#: readsyms.cc:191
+#, c-format
+msgid "%s: file is empty"
+msgstr "%s: il file è vuoto"
+
+#. Here we have to handle any other input file types we need.
+#: readsyms.cc:575
+#, c-format
+msgid "%s: not an object or archive"
+msgstr "%s: non è un oggetto o un archivio"
+
+#: reduced_debug_output.cc:236
+msgid "Debug abbreviations extend beyond .debug_abbrev section; failed to reduce debug abbreviations"
+msgstr "Le abbreviazioni di debug si estendono oltre la sezione .debug_abbrev, impossibile ridurle"
+
+#: reduced_debug_output.cc:322
+msgid "Extremely large compile unit in debug info; failed to reduce debug info"
+msgstr "Unità di compilazione estremamente grande nelle informazioni di debug, impossibile ridurle"
+
+#: reduced_debug_output.cc:330
+msgid "Debug info extends beyond .debug_info section;failed to reduce debug info"
+msgstr "Le informazioni di debug si estendono oltre la sezione .debug_info, impossibile ridurle"
+
+#: reduced_debug_output.cc:350 reduced_debug_output.cc:392
+msgid "Invalid DIE in debug info; failed to reduce debug info"
+msgstr "DIE non valido nelle informazioni di debug, impossibile ridurle"
+
+#: reduced_debug_output.cc:373
+msgid "Debug info extends beyond .debug_info section; failed to reduce debug info"
+msgstr "Le informazioni di debug si estendono oltre la sezione .debug_info, impossibile ridurle"
+
+#: reloc.cc:297 reloc.cc:858
+#, c-format
+msgid "relocation section %u uses unexpected symbol table %u"
+msgstr "la sezione di rilocazione %u usa una tabella dei simboli %u inattesa"
+
+#: reloc.cc:312 reloc.cc:875
+#, c-format
+msgid "unexpected entsize for reloc section %u: %lu != %u"
+msgstr "entsize inattesa per la sezione di rilocazione %u: %lu != %u"
+
+#: reloc.cc:321 reloc.cc:884
+#, c-format
+msgid "reloc section %u size %lu uneven"
+msgstr "sezione di rilocazione %u di dimensione %lu irregolare"
+
+#: reloc.cc:1203
+#, c-format
+msgid "could not convert call to '%s' to '%s'"
+msgstr "impossibile convertire la chiamata a \"%s\" su \"%s\""
+
+#: reloc.cc:1343
+#, c-format
+msgid "reloc section size %zu is not a multiple of reloc size %d\n"
+msgstr "la dimensione %zu della sezione di rilocazione non è un multiplo di quella di rilocazione %d\n"
+
+#. We should only see externally visible symbols in the symbol
+#. table.
+#: resolve.cc:191
+msgid "invalid STB_LOCAL symbol in external symbols"
+msgstr "simbolo STB_LOCAL non valido nei simboli esterni"
+
+#. Any target which wants to handle STB_LOOS, etc., needs to
+#. define a resolve method.
+#: resolve.cc:197
+msgid "unsupported symbol binding"
+msgstr "associazione di simboli non supportata"
+
+#. A dynamic object cannot reference a hidden or internal symbol
+#. defined in another object.
+#: resolve.cc:266
+#, c-format
+msgid "%s symbol '%s' in %s is referenced by DSO %s"
+msgstr "Il simbolo %s \"%s\" in %s è referenziato da %s DSO"
+
+#: resolve.cc:326
+#, c-format
+msgid "common of '%s' overriding smaller common"
+msgstr "il comune di \"%s\" annulla il comune più piccolo"
+
+#: resolve.cc:331
+#, c-format
+msgid "common of '%s' overidden by larger common"
+msgstr "il comune di \"%s\" è annullato dal comune più grande"
+
+#: resolve.cc:336
+#, c-format
+msgid "multiple common of '%s'"
+msgstr "comune multiplo di \"%s\""
+
+#: resolve.cc:442
+#, c-format
+msgid "multiple definition of '%s'"
+msgstr "definizione multipla di \"%s\""
+
+#: resolve.cc:481
+#, c-format
+msgid "definition of '%s' overriding common"
+msgstr "la definizione di \"%s\" annulla il comune"
+
+#: resolve.cc:516
+#, c-format
+msgid "definition of '%s' overriding dynamic common definition"
+msgstr "la definizione di \"%s\" annulla la definizione del comune dinamico"
+
+#: resolve.cc:636
+#, c-format
+msgid "common '%s' overridden by previous definition"
+msgstr "\"%s\" comune è annullato dalla definizione precedente"
+
+#: resolve.cc:766 resolve.cc:778
+msgid "command line"
+msgstr "riga di comando"
+
+#: script-sections.cc:690
+msgid "dot may not move backward"
+msgstr "dot non può retrocedere"
+
+#: script-sections.cc:757
+msgid "** expression"
+msgstr "** espressione"
+
+#: script-sections.cc:941
+msgid "fill value is not absolute"
+msgstr "il valore di riempimento non è assoluto"
+
+#: script-sections.cc:1913
+#, c-format
+msgid "alignment of section %s is not absolute"
+msgstr "l'allineamento della sezione %s non è assoluto"
+
+#: script-sections.cc:1957
+#, c-format
+msgid "subalign of section %s is not absolute"
+msgstr "il sotto-allineamento della sezione %s non è assoluto"
+
+#: script-sections.cc:1972
+#, c-format
+msgid "fill of section %s is not absolute"
+msgstr "il riempimento della sezione %s non è assoluto"
+
+#: script-sections.cc:2048
+msgid "SPECIAL constraints are not implemented"
+msgstr "i vincoli SPECIAL non sono implementati"
+
+#: script-sections.cc:2090
+msgid "mismatched definition for constrained sections"
+msgstr "definizione non corrispondente per le sezioni vincolate"
+
+#: script-sections.cc:2634
+msgid "DATA_SEGMENT_ALIGN may only appear once in a linker script"
+msgstr "DATA_SEGMENT_ALIGN può comparire solo una volta in uno script del linker"
+
+#: script-sections.cc:2649
+msgid "DATA_SEGMENT_RELRO_END may only appear once in a linker script"
+msgstr "DATA_SEGMENT_RELRO_END può comparire solo una volta in uno script del linker"
+
+#: script-sections.cc:2654
+msgid "DATA_SEGMENT_RELRO_END must follow DATA_SEGMENT_ALIGN"
+msgstr "DATA_SEGMENT_RELRO_END deve seguire DATA_SEGMENT_ALIGN"
+
+#: script-sections.cc:2826
+msgid "no matching section constraint"
+msgstr "nessuna corrispondenza per il vincolo di sezione"
+
+#: script-sections.cc:3151
+msgid "TLS sections are not adjacent"
+msgstr "le sezioni TLS non sono adiacenti"
+
+#: script-sections.cc:3280
+msgid "allocated section not in any segment"
+msgstr "la sezione allocata non è in alcun segmento"
+
+#: script-sections.cc:3309
+#, c-format
+msgid "no segment %s"
+msgstr "nessun segmento %s"
+
+#: script-sections.cc:3323
+msgid "section in two PT_LOAD segments"
+msgstr "sezione in due segmenti PT_LOAD"
+
+#: script-sections.cc:3330
+msgid "allocated section not in any PT_LOAD segment"
+msgstr "la sezione allocata non è in alcun segmento PT_LOAD"
+
+#: script-sections.cc:3358
+msgid "may only specify load address for PT_LOAD segment"
+msgstr "può solo specificare l'indirizzo di caricamento per il segmento PT_LOAD"
+
+#: script-sections.cc:3382
+#, c-format
+msgid "PHDRS load address overrides section %s load address"
+msgstr "l'indirizzo di caricamento PHDRS sovrascrive quello di caricamento della sezione %s"
+
+#. We could support this if we wanted to.
+#: script-sections.cc:3393
+msgid "using only one of FILEHDR and PHDRS is not currently supported"
+msgstr "l'uso individuale di FILEHDR e PHDRS non è attualmente supportato"
+
+#: script-sections.cc:3408
+msgid "sections loaded on first page without room for file and program headers are not supported"
+msgstr "le sezioni caricate sulla prima pagina senza spazio per i file e le intestazioni di programma non sono supportate"
+
+#: script-sections.cc:3414
+msgid "using FILEHDR and PHDRS on more than one PT_LOAD segment is not currently supported"
+msgstr "l'uso di FILEHDR e PHDRS in più di un segmento PT_LOAD non è attualmente supportato"
+
+#: script.cc:1072
+msgid "invalid use of PROVIDE for dot symbol"
+msgstr "uso non valido di PROVIDE per il simbolo dot"
+
+#: script.cc:2132
+#, c-format
+msgid "%s:%d:%d: %s"
+msgstr "%s:%d:%d: %s"
+
+#. There are some options that we could handle here--e.g.,
+#. -lLIBRARY. Should we bother?
+#: script.cc:2297
+#, c-format
+msgid "%s:%d:%d: ignoring command OPTION; OPTION is only valid for scripts specified via -T/--script"
+msgstr "%s:%d:%d: comando OPTION ignorato; OPTION è valido solo per gli script specificati attraverso -T/--script"
+
+#: script.cc:2362
+#, c-format
+msgid "%s:%d:%d: ignoring SEARCH_DIR; SEARCH_DIR is only valid for scripts specified via -T/--script"
+msgstr "%s:%d:%d: SEARCH_DIR ignorato; SEARCH_DIR è valido solo per gli script specificati attraverso -T/--script"
+
+#: script.cc:2606 script.cc:2620
+#, c-format
+msgid "%s:%d:%d: DATA_SEGMENT_ALIGN not in SECTIONS clause"
+msgstr "%s:%d:%d: DATA_SEGMENT_ALIGN non è nella direttiva SECTIONS"
+
+#: script.cc:2739
+msgid "unknown PHDR type (try integer)"
+msgstr "tipo PHDR sconosciuto (provare con intero)"
+
+#: stringpool.cc:528
+#, c-format
+msgid "%s: %s entries: %zu; buckets: %zu\n"
+msgstr "%s: %s voci: %zu; bucket: %zu\n"
+
+#: stringpool.cc:532
+#, c-format
+msgid "%s: %s entries: %zu\n"
+msgstr "%s: %s voci: %zu\n"
+
+#: stringpool.cc:535
+#, c-format
+msgid "%s: %s Stringdata structures: %zu\n"
+msgstr "%s: %s strutture Stringdata: %zu\n"
+
+#: symtab.cc:857
+#, c-format
+msgid "%s: reference to %s"
+msgstr "%s: riferimento a %s"
+
+#: symtab.cc:859
+#, c-format
+msgid "%s: definition of %s"
+msgstr "%s: definizione di %s"
+
+#: symtab.cc:1052
+#, c-format
+msgid "bad global symbol name offset %u at %zu"
+msgstr "posizione %u errata del nome di simbolo globale alla %zu"
+
+#: symtab.cc:1278
+msgid "--just-symbols does not make sense with a shared object"
+msgstr "--just-symbols non ha senso con un oggetto condiviso"
+
+#: symtab.cc:1284
+msgid "too few symbol versions"
+msgstr "troppo poche versioni del simbolo"
+
+#: symtab.cc:1333
+#, c-format
+msgid "bad symbol name offset %u at %zu"
+msgstr "posizione %u errata del nome del simbolo alla %zu"
+
+#: symtab.cc:1396
+#, c-format
+msgid "versym for symbol %zu out of range: %u"
+msgstr "versym per il simbolo %zu fuori dall'intervallo: %u"
+
+#: symtab.cc:1404
+#, c-format
+msgid "versym for symbol %zu has no name: %u"
+msgstr "versym per il simbolo %zu non ha nome: %u"
+
+#: symtab.cc:2549 symtab.cc:2681
+#, c-format
+msgid "%s: unsupported symbol section 0x%x"
+msgstr "%s: sezione del simbolo non supportata 0x%x"
+
+#: symtab.cc:2933
+#, c-format
+msgid "%s: symbol table entries: %zu; buckets: %zu\n"
+msgstr "%s: voci della tabella dei simboli: %zu; bucket: %zu\n"
+
+#: symtab.cc:2936
+#, c-format
+msgid "%s: symbol table entries: %zu\n"
+msgstr "%s: voci della tabella dei simboli: %zu\n"
+
+#: symtab.cc:3007
+#, c-format
+msgid "while linking %s: symbol '%s' defined in multiple places (possible ODR violation):"
+msgstr "durante il link di %s: simbolo \"%s\" definito in posizioni multiple (possibile violazione della ODR):"
+
+#: target-reloc.h:259
+msgid "relocation refers to discarded comdat section"
+msgstr "la rilocazione si riferisce a una sezione comdat scartata"
+
+#: target-reloc.h:298
+#, c-format
+msgid "reloc has bad offset %zu"
+msgstr "la rilocazione ha una posizione %zu errata"
+
+#: target.cc:90
+#, c-format
+msgid "%s: unsupported ELF file type %d"
+msgstr "%s: tipo di file ELF non supportato %d"
+
+#: target.cc:157
+#, c-format
+msgid "linker does not include stack split support required by %s"
+msgstr "il linker non include il supporto allo \"stack split\" richiesto da %s"
+
+#: tls.h:59
+msgid "TLS relocation out of range"
+msgstr "rilocazione TLS fuori dall'intervallo"
+
+#: tls.h:73
+msgid "TLS relocation against invalid instruction"
+msgstr "rilocazione TLS contro una istruzione non valida"
+
+#. This output is intended to follow the GNU standards.
+#: version.cc:65
+#, c-format
+msgid "Copyright 2008 Free Software Foundation, Inc.\n"
+msgstr "Copyright 2008 Free Software Foundation, Inc.\n"
+
+#: version.cc:66
+#, c-format
+msgid ""
+"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) a later version.\n"
+"This program has absolutely no warranty.\n"
+msgstr ""
+"Questo programma è software libero; siete liberi di ridistribuirlo secondo i termini della\n"
+"GNU General Public License versione 3 o (a scelta) una versione più recente.\n"
+"Questo programma non ha assolutamente alcuna garanzia.\n"
+
+#: workqueue-threads.cc:106
+#, c-format
+msgid "%s failed: %s"
+msgstr "%s non riuscito: %s"
+
+#: x86_64.cc:2184
+#, c-format
+msgid "unsupported reloc type %u"
+msgstr "tipo di rilocazione non supportato %u"
+
+#: x86_64.cc:2524
+#, c-format
+msgid "unsupported reloc %u against local symbol"
+msgstr "rilocazione %u contro un simbolo locale non supportata"
diff --git a/binutils-2.25/gold/po/vi.po b/binutils-2.25/gold/po/vi.po
new file mode 100644
index 00000000..fadc16fd
--- /dev/null
+++ b/binutils-2.25/gold/po/vi.po
@@ -0,0 +1,2267 @@
+# Vietnamese translation for Gold.
+# Copyright © 2010 Free Software Foundation, Inc.
+# This file is distributed under the same license as the binutils package.
+# Clytie Siddall <clytie@riverland.net.au>, 2010.
+# Trần Ngọc Quân <vnwildman@gmail.com>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gold-2.22.90\n"
+"Report-Msgid-Bugs-To: bug-binutils@gnu.org\n"
+"POT-Creation-Date: 2010-03-03 15:08+0100\n"
+"PO-Revision-Date: 2012-07-28 13:41+0700\n"
+"Last-Translator: Trần Ngọc Quân <vnwildman@gmail.com>\n"
+"Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n"
+"Language: vi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: LocFactoryEditor 1.8\n"
+"X-Poedit-Language: Vietnamese\n"
+"X-Poedit-Country: VIET NAM\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#: archive.cc:119
+#, c-format
+msgid "%s: no archive symbol table (run ranlib)"
+msgstr "%s: không có bảng ký hiệu kho lưu (hãy chạy ranlib)"
+
+#: archive.cc:204
+#, c-format
+msgid "%s: bad archive symbol table names"
+msgstr "%s: tên bảng ký hiệu kho lưu sai"
+
+#: archive.cc:236
+#, c-format
+msgid "%s: malformed archive header at %zu"
+msgstr "%s: sai dạng phần đầu kho lưu tại %zu"
+
+#: archive.cc:256
+#, c-format
+msgid "%s: malformed archive header size at %zu"
+msgstr "%s: sai dạng kích cỡ phần đầu kho lưu tại %zu"
+
+#: archive.cc:267
+#, c-format
+msgid "%s: malformed archive header name at %zu"
+msgstr "%s: sai dạng tên phần đầu kho lưu tại %zu"
+
+#: archive.cc:297
+#, c-format
+msgid "%s: bad extended name index at %zu"
+msgstr "%s: chỉ mục tên mở rộng sai tại %zu"
+
+#: archive.cc:307
+#, c-format
+msgid "%s: bad extended name entry at header %zu"
+msgstr "%s: mục nhập tên mở rộng sai tại phần đầu %zu"
+
+#: archive.cc:404
+#, c-format
+msgid "%s: short archive header at %zu"
+msgstr "%s: phần đầu kho lưu ngắn tại %zu"
+
+#: archive.cc:560
+#, c-format
+msgid "%s: member at %zu is not an ELF object"
+msgstr "%s: bộ phạn tại %zu không phải là đối tượng ELF"
+
+#: archive.cc:879
+#, c-format
+msgid "%s: archive libraries: %u\n"
+msgstr "%s: thư viện kho lưu : %u\n"
+
+#: archive.cc:881
+#, c-format
+msgid "%s: total archive members: %u\n"
+msgstr "%s: tổng bộ phạn kho lưu : %u\n"
+
+#: archive.cc:883
+#, c-format
+msgid "%s: loaded archive members: %u\n"
+msgstr "%s: đã nạp bộ phạn kho lưu : %u\n"
+
+#: arm.cc:1149 i386.cc:536 sparc.cc:1087 x86_64.cc:565
+msgid "** PLT"
+msgstr "** PLT"
+
+#: arm.cc:1364 i386.cc:880 powerpc.cc:1014 sparc.cc:1502 x86_64.cc:955
+#: x86_64.cc:1265
+#, c-format
+msgid "%s: unsupported reloc %u against local symbol"
+msgstr "%s: sự định vị lại không được hỗ trợ %u so với ký hiệu cục bộ"
+
+#: arm.cc:1404 powerpc.cc:1105 sparc.cc:1592 x86_64.cc:992
+msgid "requires unsupported dynamic reloc; recompile with -fPIC"
+msgstr "yêu cầu sự định vị lại động không được hỗ trợ — hãy biên dịch lại với các tuỳ chọn \"-fPIC\""
+
+#. These are relocations which should only be seen by the
+#. dynamic linker, and should never be seen here.
+#: arm.cc:1519 arm.cc:1739 arm.cc:2354 i386.cc:1002 i386.cc:1334
+#: powerpc.cc:1223 powerpc.cc:1432 sparc.cc:1877 sparc.cc:2238 x86_64.cc:1145
+#: x86_64.cc:1453
+#, c-format
+msgid "%s: unexpected reloc %u in object file"
+msgstr "%s: gặp sự định vị lại không mong đợi %u trong tập tin đối tượng"
+
+#: arm.cc:1538 i386.cc:1171 powerpc.cc:1242 sparc.cc:1896 x86_64.cc:1279
+#: x86_64.cc:1571
+#, c-format
+msgid "%s: unsupported reloc %u against global symbol %s"
+msgstr "%s: sự định vị lại không được hỗ trợ %u so với ký hiệu toàn cục %s"
+
+#: arm.cc:1804 i386.cc:1542
+#, c-format
+msgid "%s: unsupported RELA reloc section"
+msgstr "%s: phần định vị lại RELA không được hỗ trợ"
+
+#: arm.cc:2047
+msgid "relocation R_ARM_MOVW_ABS_NC cannot be used when makinga shared object; recompile with -fPIC"
+msgstr "sự định vị lại \"R_ARM_MOVW_ABS_NC\" không thể sử dụng được khi tạo một đối tượng dùng chung: hãy biên dịch lại với \"-fPIC\""
+
+#: arm.cc:2056
+msgid "relocation R_ARM_MOVT_ABS cannot be used when makinga shared object; recompile with -fPIC"
+msgstr "sự định vị lại \"R_ARM_MOVT_ABS\" không thể sử dụng được khi tạo một đối tượng dùng chung: hãy biên dịch lại với \"-fPIC\""
+
+#: arm.cc:2067
+msgid "relocation R_ARM_THM_MOVW_ABS_NC cannot be used whenmaking a shared object; recompile with -fPIC"
+msgstr "sự định vị lại \"R_ARM_THM_MOVW_ABS_NC\" không thể sử dụng được khi tạo một đối tượng dùng chung: hãy biên dịch lại với \"-fPIC\""
+
+#: arm.cc:2077
+msgid "relocation R_ARM_THM_MOVT_ABS cannot be used whenmaking a shared object; recompile with -fPIC"
+msgstr "sự định vị lại \"R_ARM_THM_MOVT_ABS\" không thể sử dụng được khi tạo một đối tượng dùng chung: hãy biên dịch lại với \"-fPIC\""
+
+#: arm.cc:2141
+msgid "cannot find origin of R_ARM_BASE_PREL"
+msgstr "không tìm thấy gốc của \"R_ARM_BASE_PREL\""
+
+#: arm.cc:2169
+msgid "cannot find origin of R_ARM_BASE_ABS"
+msgstr "không tìm thấy gốc của \"R_ARM_BASE_ABS\""
+
+#: arm.cc:2230 i386.cc:1820 i386.cc:2521 powerpc.cc:1798 sparc.cc:2711
+#: x86_64.cc:1935 x86_64.cc:2518
+#, c-format
+msgid "unexpected reloc %u in object file"
+msgstr "gặp sự định vị lại không mong đợi %u trong tập tin đối tượng"
+
+#: arm.cc:2236 i386.cc:1852 i386.cc:1931 i386.cc:1983 i386.cc:2014
+#: i386.cc:2076 powerpc.cc:1804 sparc.cc:2717 sparc.cc:2900 sparc.cc:2961
+#: sparc.cc:3068 x86_64.cc:1956 x86_64.cc:2039 x86_64.cc:2094 x86_64.cc:2119
+#, c-format
+msgid "unsupported reloc %u"
+msgstr "định vị lại không được hỗ trợ %u"
+
+#: arm.cc:2248
+#, c-format
+msgid "relocation overflow in relocation %u"
+msgstr "tràn vùng định vị lại trong sự định vị lại %u"
+
+#: arm.cc:2256
+#, c-format
+msgid "unexpected opcode while processing relocation %u"
+msgstr "gặp mã thao tác không mong đợi khi xử lý sự định vị lại %u"
+
+#: arm.cc:2359 i386.cc:2535
+#, c-format
+msgid "unsupported reloc %u in object file"
+msgstr "gặp sự định vị lại không được hỗ trợ %u trong tập tin đối tượng"
+
+#: binary.cc:129
+#, c-format
+msgid "cannot open %s: %s:"
+msgstr "không thể mở %s: %s:"
+
+#: compressed_output.cc:128
+msgid "not compressing section data: zlib error"
+msgstr "không đang nén dữ liệu phần: lỗi zlib"
+
+#: cref.cc:244
+#, c-format
+msgid "cannot open symbol count file %s: %s"
+msgstr "không thể mở tập tin đếm ký hiệu %s: %s"
+
+#: descriptors.cc:116
+#, c-format
+msgid "file %s was removed during the link"
+msgstr "tập tin \"%s\" bị gỡ bỏ trong khi liên kết"
+
+#: descriptors.cc:169
+msgid "out of file descriptors and couldn't close any"
+msgstr "cạn bộ mô tả tập tin và không thể đóng bộ nào"
+
+#: descriptors.cc:190 descriptors.cc:226
+#, c-format
+msgid "while closing %s: %s"
+msgstr "trong khi đóng %s: %s"
+
+#: dirsearch.cc:71
+#, c-format
+msgid "%s: can not read directory: %s"
+msgstr "%s: không thể đọc thư mục: %s"
+
+#: dwarf_reader.cc:53 dwarf_reader.cc:84
+msgid "Unusually large LEB128 decoded, debug information may be corrupted"
+msgstr "Giải mã được LEB128 rất lớn: thông tin gỡ lỗi có thể bị hỏng"
+
+#: dynobj.cc:164
+#, c-format
+msgid "unexpected duplicate type %u section: %u, %u"
+msgstr "gặp kiểu trùng không mong đợi %u trong phần: %u, %u"
+
+#: dynobj.cc:200
+#, c-format
+msgid "unexpected link in section %u header: %u != %u"
+msgstr "gặp liên kết không mong đợi trong phần %u dòng đầu: %u != %u"
+
+#: dynobj.cc:236
+#, c-format
+msgid "DYNAMIC section %u link out of range: %u"
+msgstr "liên kết phần ĐỘNG %u vượt ra ngoài giới hạn: %u"
+
+#: dynobj.cc:244
+#, c-format
+msgid "DYNAMIC section %u link %u is not a strtab"
+msgstr "liên kết phần ĐỘNG %u %u không phải strtab"
+
+#: dynobj.cc:273
+#, c-format
+msgid "DT_SONAME value out of range: %lld >= %lld"
+msgstr "giá trị \"DT_SONAME\" ở ngoại phạm vi: %lld ≥ %lld"
+
+#: dynobj.cc:285
+#, c-format
+msgid "DT_NEEDED value out of range: %lld >= %lld"
+msgstr "giá trị \"DT_NEEDED\" ở ngoại phạm vi: %lld ≥ %lld"
+
+#: dynobj.cc:298
+msgid "missing DT_NULL in dynamic segment"
+msgstr "thiếu \"DT_NULL\" trong phân đoạn động"
+
+#: dynobj.cc:344
+#, c-format
+msgid "invalid dynamic symbol table name index: %u"
+msgstr "chỉ mục tên bảng ký hiệu động không hợp lệ: %u"
+
+#: dynobj.cc:351
+#, c-format
+msgid "dynamic symbol table name section has wrong type: %u"
+msgstr "phần tên bảng ký hiệu động có kiểu sai: %u"
+
+#: dynobj.cc:438 object.cc:463 object.cc:1106
+#, c-format
+msgid "bad section name offset for section %u: %lu"
+msgstr "sai đặt khoảng bù tên phần cho phần %u: %lu"
+
+#: dynobj.cc:468
+#, c-format
+msgid "duplicate definition for version %u"
+msgstr "gặp lời xác định trùng cho phiên bản %u"
+
+#: dynobj.cc:497
+#, c-format
+msgid "unexpected verdef version %u"
+msgstr "gặp phiên bản verdef không mong đợi %u"
+
+#: dynobj.cc:513
+#, c-format
+msgid "verdef vd_cnt field too small: %u"
+msgstr "trường \"vd_cnt\" verdef quá nhỏ : %u"
+
+#: dynobj.cc:521
+#, c-format
+msgid "verdef vd_aux field out of range: %u"
+msgstr "trường \"vd_aux\" verdef ở ngoại phạm vi: %u"
+
+#: dynobj.cc:532
+#, c-format
+msgid "verdaux vda_name field out of range: %u"
+msgstr "trường \"vda_name\" verdef ở ngoại phạm vi: %u"
+
+#: dynobj.cc:542
+#, c-format
+msgid "verdef vd_next field out of range: %u"
+msgstr "trường \"vd_next\" verdef ở ngoại phạm vi: %u"
+
+#: dynobj.cc:576
+#, c-format
+msgid "unexpected verneed version %u"
+msgstr "gặp phiên bản verneed không mong đợi %u"
+
+#: dynobj.cc:585
+#, c-format
+msgid "verneed vn_aux field out of range: %u"
+msgstr "trường \"vn_aux\" verneed ở ngoại phạm vi: %u"
+
+#: dynobj.cc:599
+#, c-format
+msgid "vernaux vna_name field out of range: %u"
+msgstr "trường \"vna_name\" vernaux ở ngoại phạm vi: %u"
+
+#: dynobj.cc:610
+#, c-format
+msgid "verneed vna_next field out of range: %u"
+msgstr "trường \"vna_next\" verneed ở ngoại phạm vi: %u"
+
+#: dynobj.cc:621
+#, c-format
+msgid "verneed vn_next field out of range: %u"
+msgstr "trường \"vn_next\" verneed ở ngoại phạm vi: %u"
+
+#: dynobj.cc:670
+msgid "size of dynamic symbols is not multiple of symbol size"
+msgstr "kích cỡ của ký hiệu động không phải là bội số cho kích cỡ ký hiệu"
+
+#: dynobj.cc:1435
+#, c-format
+msgid "symbol %s has undefined version %s"
+msgstr "ký hiệu %s có phiên bản chưa được xác định %s"
+
+#: ehframe.h:82
+msgid "** eh_frame_hdr"
+msgstr "** khung_eh_hdr"
+
+#: ehframe.h:353
+msgid "** eh_frame"
+msgstr "** khung_eh"
+
+#: errors.cc:81
+#, c-format
+msgid "%s: fatal error: "
+msgstr "%s: lỗi nghiêm trọng: "
+
+#: errors.cc:92
+#, c-format
+msgid "%s: error: "
+msgstr "%s: lỗi: "
+
+#: errors.cc:104
+#, c-format
+msgid "%s: warning: "
+msgstr "%s: cảnh báo : "
+
+#: errors.cc:128
+#, c-format
+msgid "%s: %s: error: "
+msgstr "%s: %s: lỗi: "
+
+#: errors.cc:144
+#, c-format
+msgid "%s: %s: warning: "
+msgstr "%s: %s: cảnh báo : "
+
+#: errors.cc:167
+#, c-format
+msgid "%s: %s: error: undefined reference to '%s'\n"
+msgstr "%s: %s: lỗi: tham chiếu chưa xác định đến \"%s\"\n"
+
+#: errors.cc:172
+#, c-format
+msgid "%s: %s: error: undefined reference to '%s', version '%s'\n"
+msgstr "%s: %s: lỗi: tham chiếu chưa xác định đến \"%s\", phiên bản \"%s\"\n"
+
+#: errors.cc:182
+#, c-format
+msgid "%s: "
+msgstr "%s: "
+
+#: expression.cc:172
+#, c-format
+msgid "undefined symbol '%s' referenced in expression"
+msgstr "ký hiệu chưa xác định \"%s\" được tham chiếu trong biểu thức"
+
+#: expression.cc:209
+msgid "invalid reference to dot symbol outside of SECTIONS clause"
+msgstr "tham chiếu sai đến ký hiệu chấm bên ngoài mệnh đề SECTIONS (phần)"
+
+#. Handle unary operators. We use a preprocessor macro as a hack to
+#. capture the C operator.
+#: expression.cc:278
+msgid "unary "
+msgstr "nguyên phân"
+
+#. 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.
+#: expression.cc:400
+msgid "binary "
+msgstr "nhị phân"
+
+#: expression.cc:404
+msgid " by zero"
+msgstr " cho không"
+
+#: expression.cc:575
+msgid "max applied to section relative value"
+msgstr "tối đa áp dụng cho giá trị tương đối của phần"
+
+#: expression.cc:610
+msgid "min applied to section relative value"
+msgstr "tối thiểu áp dụng cho giá trị tương đối của phần"
+
+#: expression.cc:740
+msgid "aligning to section relative value"
+msgstr "sắp hàng theo giá trị tương đối của phần"
+
+#: expression.cc:895
+#, c-format
+msgid "unknown constant %s"
+msgstr "không rõ hằng số %s"
+
+#: expression.cc:1126
+msgid "SEGMENT_START not implemented"
+msgstr "\"SEGMENT_START\" (đầu đoạn) chưa được thực hiện"
+
+#: expression.cc:1135
+msgid "ORIGIN not implemented"
+msgstr "\"ORIGIN\" (gốc) chưa được thực hiện"
+
+#: expression.cc:1141
+msgid "LENGTH not implemented"
+msgstr "\"LENGTH\" (chiều dài) chưa được thực hiện"
+
+#: fileread.cc:65
+#, c-format
+msgid "munmap failed: %s"
+msgstr "munmap bị lỗi: %s"
+
+#: fileread.cc:129
+#, c-format
+msgid "%s: fstat failed: %s"
+msgstr "%s: fstat bị lỗi: %s"
+
+#: fileread.cc:169
+#, c-format
+msgid "could not reopen file %s"
+msgstr "không thể mở lại tập tin %s"
+
+#: fileread.cc:302
+#, c-format
+msgid "%s: pread failed: %s"
+msgstr "%s: pread bị lỗi: %s"
+
+#: fileread.cc:308
+#, c-format
+msgid "%s: file too short: read only %lld of %lld bytes at %lld"
+msgstr "%s: tập tin quá ngắn: đọc được chỉ %lld byte trên %lld byte theo %lld"
+
+#: fileread.cc:372
+#, c-format
+msgid "%s: attempt to map %lld bytes at offset %lld exceeds size of file; the file may be corrupt"
+msgstr "%s: việc thử ánh xạ %lld byte đẳng sau khoảng bù %lld cũng vượt quá kích cỡ tập tin; tập tin có thể bị hỏng"
+
+#: fileread.cc:402
+#, c-format
+msgid "%s: mmap offset %lld size %lld failed: %s"
+msgstr "%s: khoảng bù sơ đồ vùng nhớ (mmap) %lld kích cỡ %lld bị lỗi: %s"
+
+#: fileread.cc:548
+#, c-format
+msgid "%s: lseek failed: %s"
+msgstr "%s: lseek bị lỗi: %s"
+
+#: fileread.cc:554
+#, c-format
+msgid "%s: readv failed: %s"
+msgstr "%s: readv bị lỗi: %s"
+
+#: fileread.cc:557
+#, c-format
+msgid "%s: file too short: read only %zd of %zd bytes at %lld"
+msgstr "%s: tập tin quá ngắn: đọc được chỉ %zd byte trên %zd byte theo %lld"
+
+#: fileread.cc:706
+#, c-format
+msgid "%s: total bytes mapped for read: %llu\n"
+msgstr "%s: tổng byte được ánh xạ để đọc: %llu\n"
+
+#: fileread.cc:708
+#, c-format
+msgid "%s: maximum bytes mapped for read at one time: %llu\n"
+msgstr "%s: số tối đa các byte được ánh xạ để đọc cùng lúc: %llu\n"
+
+#: fileread.cc:791
+#, c-format
+msgid "%s: stat failed: %s"
+msgstr "%s: stat bị lỗi: %s"
+
+#: fileread.cc:849
+#, c-format
+msgid "cannot find %s%s"
+msgstr "không tìm thấy %s%s"
+
+#: fileread.cc:880
+#, c-format
+msgid "cannot find %s"
+msgstr "không tìm thấy %s"
+
+#: fileread.cc:904
+#, c-format
+msgid "cannot open %s: %s"
+msgstr "không thể mở %s: %s"
+
+#: gold-threads.cc:103
+#, c-format
+msgid "pthead_mutextattr_init failed: %s"
+msgstr "pthead_mutextattr_init bị lỗi: %s"
+
+#: gold-threads.cc:107
+#, c-format
+msgid "pthread_mutextattr_settype failed: %s"
+msgstr "pthread_mutextattr_settype bị lỗi: %s"
+
+#: gold-threads.cc:112
+#, c-format
+msgid "pthread_mutex_init failed: %s"
+msgstr "pthread_mutex_init bị lỗi: %s"
+
+#: gold-threads.cc:116
+#, c-format
+msgid "pthread_mutexattr_destroy failed: %s"
+msgstr "pthread_mutexattr_destroy bị lỗi: %s"
+
+#: gold-threads.cc:123
+#, c-format
+msgid "pthread_mutex_destroy failed: %s"
+msgstr "pthread_mutex_destroy bị lỗi: %s"
+
+#: gold-threads.cc:131 gold-threads.cc:382
+#, c-format
+msgid "pthread_mutex_lock failed: %s"
+msgstr "pthread_mutex_lock bị lỗi: %s"
+
+#: gold-threads.cc:139 gold-threads.cc:394
+#, c-format
+msgid "pthread_mutex_unlock failed: %s"
+msgstr "pthread_mutex_unlock bị lỗi: %s"
+
+#: gold-threads.cc:220
+#, c-format
+msgid "pthread_cond_init failed: %s"
+msgstr "pthread_cond_init bị lỗi: %s"
+
+#: gold-threads.cc:227
+#, c-format
+msgid "pthread_cond_destroy failed: %s"
+msgstr "pthread_cond_destroy bị lỗi: %s"
+
+#: gold-threads.cc:236
+#, c-format
+msgid "pthread_cond_wait failed: %s"
+msgstr "pthread_cond_wait bị lỗi: %s"
+
+#: gold-threads.cc:244
+#, c-format
+msgid "pthread_cond_signal failed: %s"
+msgstr "pthread_cond_signal bị lỗi: %s"
+
+#: gold-threads.cc:252
+#, c-format
+msgid "pthread_cond_broadcast failed: %s"
+msgstr "pthread_cond_broadcast bị lỗi: %s"
+
+#: gold-threads.cc:388
+#, c-format
+msgid "pthread_once failed: %s"
+msgstr "pthread_once bị lỗi: %s"
+
+#: gold.cc:91
+#, c-format
+msgid "%s: internal error in %s, at %s:%d\n"
+msgstr "%s: gặp lỗi nội bộ trong %s, tại %s:%d\n"
+
+#: gold.cc:173
+msgid "no input files"
+msgstr "không có tập tin nhập vào"
+
+#: gold.cc:226
+msgid "cannot mix -r with --gc-sections or --icf"
+msgstr "không thể kết hợp tuỳ chọn \"-r\" với \"--gc-sections\", cũng không thể kết hợp nó với \"--icf\""
+
+#: gold.cc:407
+#, c-format
+msgid "cannot mix -static with dynamic object %s"
+msgstr "không thể kết hợp tuỳ chọn \"-static\" (tĩnh) với đối tượng động %s"
+
+#: gold.cc:411
+#, c-format
+msgid "cannot mix -r with dynamic object %s"
+msgstr "không thể kết hợp tuỳ chọn \"-r\" với đối tượng động %s"
+
+#: gold.cc:415
+#, c-format
+msgid "cannot use non-ELF output format with dynamic object %s"
+msgstr "không thể sử dụng định dạng kết xuất khác ELF với đối tượng động %s"
+
+#: gold.cc:427
+#, c-format
+msgid "cannot mix split-stack '%s' and non-split-stack '%s' when using -r"
+msgstr "không thể kết hợp đống chia ra \"%s\" và đống không chia ra \"%s\" khi sử dụng tuỳ chọn \"-r\""
+
+#. FIXME: This needs to specify the location somehow.
+#: i386.cc:232 i386.cc:1669 sparc.cc:234 sparc.cc:2395 x86_64.cc:237
+#: x86_64.cc:1732
+msgid "missing expected TLS relocation"
+msgstr "thiếu sự định vị lại TLS mong đợi"
+
+#: i386.cc:944 x86_64.cc:1068
+#, c-format
+msgid "section symbol %u has bad shndx %u"
+msgstr "ký hiệu phần %u có shndx sai %u"
+
+#: i386.cc:1036 i386.cc:1060 sparc.cc:1777 x86_64.cc:1176 x86_64.cc:1204
+#, c-format
+msgid "local symbol %u has bad shndx %u"
+msgstr "ký hiệu cục bộ %u có shndx sai %u"
+
+#: i386.cc:1991
+msgid "both SUN and GNU model TLS relocations"
+msgstr "định vị lại TLS kiểu cả hai SUN và GNU"
+
+#: i386.cc:2730 x86_64.cc:2719
+#, c-format
+msgid "failed to match split-stack sequence at section %u offset %0zx"
+msgstr "không khớp được dãy đống chia ra tại phần %u khoảng bù %0zx"
+
+#: icf.cc:616
+#, c-format
+msgid "%s: ICF Converged after %u iteration(s)"
+msgstr "%s: ICF đồng quy sau %u lần lặp lại"
+
+#: icf.cc:619
+#, c-format
+msgid "%s: ICF stopped after %u iteration(s)"
+msgstr "%s: ICF bị dừng sau %u lần lặp lại"
+
+#: icf.cc:633
+#, c-format
+msgid "Could not find symbol %s to unfold\n"
+msgstr "Không tìm thấy ký hiệu %s để mở ra\n"
+
+#: incremental.cc:242
+#, c-format
+msgid "the link might take longer: cannot perform incremental link: %s"
+msgstr "tiến trình liên kết có thể chạy lâu hơn — không thể thực hiện tiến trình liên kết dần: %s"
+
+#: incremental.cc:302
+msgid "no incremental data from previous build"
+msgstr "không có dữ liệu dần từ việc xây dựng trước"
+
+#: incremental.cc:309 incremental.cc:332
+msgid "invalid incremental build data"
+msgstr "gặp dữ liệu xây dựng dần sai"
+
+#: incremental.cc:321
+msgid "different version of incremental build data"
+msgstr "gặp phiên bản khác về dữ liệu xây dựng dần"
+
+#: incremental.cc:338
+msgid "command line changed"
+msgstr "dòng lệnh bị thay đổi"
+
+#: incremental.cc:362
+#, c-format
+msgid "unsupported ELF machine number %d"
+msgstr "số thứ tự máy ELF không được hỗ trợ %d"
+
+#: incremental.cc:387
+msgid "output is not an ELF file."
+msgstr "kết xuất không phải là một tập tin ELF."
+
+#: incremental.cc:410
+msgid "unsupported file: 32-bit, big-endian"
+msgstr "tập tin không được hỗ trợ : 32-bit về cuối lớn"
+
+#: incremental.cc:419
+msgid "unsupported file: 32-bit, little-endian"
+msgstr "tập tin không được hỗ trợ : 32-bit về cuối nhỏ"
+
+#: incremental.cc:431
+msgid "unsupported file: 64-bit, big-endian"
+msgstr "tập tin không được hỗ trợ : 64-bit về cuối lớn"
+
+#: incremental.cc:440
+msgid "unsupported file: 64-bit, little-endian"
+msgstr "tập tin không được hỗ trợ : 64-bit về cuối nhỏ"
+
+#: layout.cc:1887
+#, c-format
+msgid "--build-id=uuid failed: could not open /dev/urandom: %s"
+msgstr "--build-id=uuid bị lỗi: không mở được /dev/urandom: %s"
+
+#: layout.cc:1894
+#, c-format
+msgid "/dev/urandom: read failed: %s"
+msgstr "/dev/urandom: lỗi đọc: %s"
+
+#: layout.cc:1896
+#, c-format
+msgid "/dev/urandom: expected %zu bytes, got %zd bytes"
+msgstr "/dev/urandom: mong đợi %zu byte, còn nhận %zd byte"
+
+#: layout.cc:1918
+#, c-format
+msgid "--build-id argument '%s' not a valid hex number"
+msgstr "đối số mã số xây dựng «--build-id\" \"%s\" không phải một số thập lục đúng"
+
+#: layout.cc:1924
+#, c-format
+msgid "unrecognized --build-id argument '%s'"
+msgstr "không nhận ra đối số mã số xây dựng «--build-id\" \"%s\""
+
+#: layout.cc:2337
+#, c-format
+msgid "load segment overlap [0x%llx -> 0x%llx] and [0x%llx -> 0x%llx]"
+msgstr "đoạn nạp chồng lấp [0x%llx -> 0x%llx] và [0x%llx -> 0x%llx]"
+
+#: mapfile.cc:70
+#, c-format
+msgid "cannot open map file %s: %s"
+msgstr "không thể mở tập tin sơ đồ %s: %s"
+
+#: mapfile.cc:84
+#, c-format
+msgid "cannot close map file: %s"
+msgstr "không thể đóng tập tin sơ đồ : %s"
+
+#: mapfile.cc:116
+#, c-format
+msgid ""
+"Archive member included because of file (symbol)\n"
+"\n"
+msgstr ""
+"Gồm bộ phạn kho lưu do tập tin (ký hiệu)\n"
+"\n"
+
+#: mapfile.cc:159
+#, c-format
+msgid ""
+"\n"
+"Allocating common symbols\n"
+msgstr ""
+"\n"
+"Đang cấp phát các ký hiệu dùng chung\n"
+
+#: mapfile.cc:161
+#, c-format
+msgid ""
+"Common symbol size file\n"
+"\n"
+msgstr ""
+"Ký hiệu chung kích cỡ tập tin\n"
+"\n"
+
+#: mapfile.cc:195
+#, c-format
+msgid ""
+"\n"
+"Memory map\n"
+"\n"
+msgstr ""
+"\n"
+"Sơ đồ vùng nhớ\n"
+"\n"
+
+#: mapfile.cc:361
+#, c-format
+msgid ""
+"\n"
+"Discarded input sections\n"
+"\n"
+msgstr ""
+"\n"
+"Các phần nhập bị huỷ\n"
+"\n"
+
+#: merge.cc:455
+#, c-format
+msgid "%s: %s merged constants size: %lu; input: %zu; output: %zu\n"
+msgstr "%s: %s kích cỡ các hằng số gộp lại: %lu; vào: %zu; ra: %zu\n"
+
+#: merge.cc:478
+msgid "mergeable string section length not multiple of character size"
+msgstr "chiều dài phần chuỗi có thể gộp lại không phải là bội số cho kích cỡ ký tự"
+
+#: merge.cc:494
+#, c-format
+msgid "%s: last entry in mergeable string section '%s' not null terminated"
+msgstr "%s: phần chuỗi có thể gộp lại chứa mục nhập cuối cùng \"%s\" không phải chấm dứt vô giá trị"
+
+#: merge.cc:613
+#, c-format
+msgid "%s: %s input: %zu\n"
+msgstr "%s: vào %s: %zu\n"
+
+#: merge.h:300
+msgid "** merge constants"
+msgstr "** hằng số gộp lại"
+
+#: merge.h:422
+msgid "** merge strings"
+msgstr "** chuỗi gộp lại"
+
+#: object.cc:75
+msgid "missing SHT_SYMTAB_SHNDX section"
+msgstr "thiếu phần \"SHT_SYMTAB_SHNDX\""
+
+#: object.cc:119
+#, c-format
+msgid "symbol %u out of range for SHT_SYMTAB_SHNDX section"
+msgstr "ký hiệu %u ở ngoại phạm vi cho phần \"SHT_SYMTAB_SHNDX\""
+
+#: object.cc:126
+#, c-format
+msgid "extended index for symbol %u out of range: %u"
+msgstr "chỉ mục mở rộng cho ký hiệu %u ở ngoại phạm vi: %u"
+
+#: object.cc:148 object.cc:2331 output.cc:4052
+#, c-format
+msgid "%s: %s"
+msgstr "%s: %s"
+
+#: object.cc:190
+#, c-format
+msgid "section name section has wrong type: %u"
+msgstr "phần tên phần có kiểu sai: %u"
+
+#: object.cc:546
+#, c-format
+msgid "invalid symbol table name index: %u"
+msgstr "sai đặt chỉ mục tên bảng ký hiệu : %u"
+
+#: object.cc:552
+#, c-format
+msgid "symbol table name section has wrong type: %u"
+msgstr "phần tên bảng ký hiệu có kiểu sau: %u"
+
+#: object.cc:641
+#, c-format
+msgid "section group %u info %u out of range"
+msgstr "thông tin %1$u về nhóm phần %2$u ở ngoài phạm vi"
+
+#: object.cc:660
+#, c-format
+msgid "symbol %u name offset %u out of range"
+msgstr "khoảng bù tên %1$u của ký hiệu %2$u ở ngoài phạm vi"
+
+#: object.cc:678
+#, c-format
+msgid "symbol %u invalid section index %u"
+msgstr "sai đặt chỉ mục phần %1$u của ký hiệu %2$u"
+
+#: object.cc:723
+#, c-format
+msgid "section %u in section group %u out of range"
+msgstr "phần %u trong nhóm phần %u ở ngoại phạm vi"
+
+#: object.cc:731
+#, c-format
+msgid "invalid section group %u refers to earlier section %u"
+msgstr "sai đặt nhóm phần %u mà tham chiếu đến phần trước %u"
+
+#: object.cc:1037 reloc.cc:271 reloc.cc:838
+#, c-format
+msgid "relocation section %u has bad info %u"
+msgstr "phần định vị lại %u có thông tin sai %u"
+
+#: object.cc:1231
+#, c-format
+msgid "%s: removing unused section from '%s' in file '%s'"
+msgstr "%s: đang gỡ bỏ phần không dùng khỏi \"%s\" trong tập tin \"%s\""
+
+#: object.cc:1257
+#, c-format
+msgid "%s: ICF folding section '%s' in file '%s'into '%s' in file '%s'"
+msgstr "%s: ICF đang gấp phần \"%s\" trong tập tin \"%s\" vào \"%s\" trong tập tin \"%s\""
+
+#: object.cc:1454
+msgid "size of symbols is not multiple of symbol size"
+msgstr "kích cỡ của ký hiệu không phải là bội số cho kích cỡ ký hiệu"
+
+#: object.cc:1563
+#, c-format
+msgid "local symbol %u section name out of range: %u >= %u"
+msgstr "tên phần của ký hiệu %u ở ngoại phạm vi: %u ≥ %u"
+
+#: object.cc:1652
+#, c-format
+msgid "unknown section index %u for local symbol %u"
+msgstr "không rõ chỉ mục phần %u cho ký hiệu cục bộ %u"
+
+#: object.cc:1661
+#, c-format
+msgid "local symbol %u section index %u out of range"
+msgstr "chỉ mục phần %1$u của ký hiệu cục bộ %2$u ở ngoại phạm vi"
+
+#: object.cc:2169
+#, c-format
+msgid "%s is not supported but is required for %s in %s"
+msgstr "%s không được hỗ trợ còn yêu cầu cho %s trong %s"
+
+#: object.cc:2273
+#, c-format
+msgid "%s: unsupported ELF machine number %d"
+msgstr "%s: số thứ tự máy ELF không được hỗ trợ %d"
+
+#: object.cc:2283
+#, c-format
+msgid "%s: incompatible target"
+msgstr "%s: đích đến không tương thích"
+
+#: object.cc:2347 plugin.cc:1019
+#, c-format
+msgid "%s: not configured to support 32-bit big-endian object"
+msgstr "%s: không phải được cấu hình để hỗ trợ đối tượng về cuối lớn 32-bit"
+
+#: object.cc:2363 plugin.cc:1028
+#, c-format
+msgid "%s: not configured to support 32-bit little-endian object"
+msgstr "%s: không phải được cấu hình để hỗ trợ đối tượng về cuối nhỏ 32-bit"
+
+#: object.cc:2382 plugin.cc:1040
+#, c-format
+msgid "%s: not configured to support 64-bit big-endian object"
+msgstr "%s: không phải được cấu hình để hỗ trợ đối tượng về cuối lớn 64-bit"
+
+#: object.cc:2398 plugin.cc:1049
+#, c-format
+msgid "%s: not configured to support 64-bit little-endian object"
+msgstr "%s: không phải được cấu hình để hỗ trợ đối tượng về cuối nhỏ 64-bit"
+
+#: options.cc:156
+#, c-format
+msgid ""
+"Usage: %s [options] file...\n"
+"Options:\n"
+msgstr ""
+"Sử dụng: %s [tùy_chọn ...] tệp...\n"
+"Tùy chọn:\n"
+
+#. config.guess and libtool.m4 look in ld --help output for the
+#. string "supported targets".
+#: options.cc:164
+#, c-format
+msgid "%s: supported targets:"
+msgstr "%s: đích được hỗ trợ :"
+
+#: options.cc:176
+#, c-format
+msgid "Report bugs to %s\n"
+msgstr "Hãy thông báo lỗi cho %s\n"
+
+#: options.cc:193 options.cc:203 options.cc:213
+#, c-format
+msgid "%s: invalid option value (expected an integer): %s"
+msgstr "%s: giá trị tuỳ chọn sai (mong đợi số nguyên): %s"
+
+#: options.cc:223
+#, c-format
+msgid "%s: invalid option value (expected a floating point number): %s"
+msgstr "%s: giá trị tuỳ chọn sai (mong đợi số dấu phẩy động): %s"
+
+#: options.cc:232
+#, c-format
+msgid "%s: must take a non-empty argument"
+msgstr "%s: phải nhận một đối số khác trống"
+
+#: options.cc:273
+#, c-format
+msgid "%s: must take one of the following arguments: %s"
+msgstr "%s: phải nhận một của những đối số theo đây: %s"
+
+#: options.cc:300
+#, c-format
+msgid " Supported targets:\n"
+msgstr " Đích được hỗ trợ :\n"
+
+#: options.cc:409
+#, c-format
+msgid "unable to parse script file %s"
+msgstr "không thể phân tích cú pháp của tập tin văn lệnh %s"
+
+#: options.cc:417
+#, c-format
+msgid "unable to parse version script file %s"
+msgstr "không thể phân tích cú pháp của tập tin văn lệnh phiên bản %s"
+
+#: options.cc:425
+#, c-format
+msgid "unable to parse dynamic-list script file %s"
+msgstr "không thể phân tích cú pháp của tập tin văn lệnh danh sách động %s"
+
+#: options.cc:522
+#, c-format
+msgid "format '%s' not supported; treating as elf (supported formats: elf, binary)"
+msgstr "định dạng \"%s\" không được hỗ trợ nên xử lý như là ELF (định dạng được hỗ trợ : elf, nhị phân)"
+
+#: options.cc:538
+#, c-format
+msgid "%s: use the --help option for usage information\n"
+msgstr "%s: hãy sử dụng tùy chọn trợ giúp \"--help\" để xem thông tin về cách sử dụng\n"
+
+#: options.cc:547
+#, c-format
+msgid "%s: %s: %s\n"
+msgstr "%s: %s: %s\n"
+
+#: options.cc:651
+msgid "unexpected argument"
+msgstr "gặp đối số không mong đợi"
+
+#: options.cc:664 options.cc:725
+msgid "missing argument"
+msgstr "thiếu đối số"
+
+#: options.cc:736
+msgid "unknown -z option"
+msgstr "tùy chọn không rõ \"-z\""
+
+#: options.cc:935
+#, c-format
+msgid "ignoring --threads: %s was compiled without thread support"
+msgstr "đang bỏ qua tuỳ chọn \"--threads\": %s đã được biên dịch mà không hỗ trợ nhánh"
+
+#: options.cc:942
+#, c-format
+msgid "ignoring --thread-count: %s was compiled without thread support"
+msgstr "đang bỏ qua tuỳ chọn \"--thread-count\": %s đã được biên dịch mà không hỗ trợ nhánh"
+
+#: options.cc:981
+#, c-format
+msgid "unable to open -retain-symbols-file file %s: %s"
+msgstr "không thể mở tập tin giữ lại ký hiệu (-retain-symbols-file) %s: %s"
+
+#: options.cc:1003
+msgid "-shared and -static are incompatible"
+msgstr "hai tùy chọn \"-shared\" (dùng chung) và \"-static\" (tĩnh) không tương thích với nhau"
+
+#: options.cc:1005
+msgid "-shared and -pie are incompatible"
+msgstr "hai tùy chọn \"-shared\" (dùng chung) và \"-pie\" không tương thích với nhau"
+
+#: options.cc:1008
+msgid "-shared and -r are incompatible"
+msgstr "hai tùy chọn \"-shared\" (dùng chung) và \"-r\" không tương thích với nhau"
+
+#: options.cc:1010
+msgid "-pie and -r are incompatible"
+msgstr "hai tùy chọn \"-pie\" và \"-r\" không tương thích với nhau"
+
+#: options.cc:1014
+msgid "-retain-symbols-file does not yet work with -r"
+msgstr "tuỳ chọn \"-retain-symbols-file\" chưa hoạt động cùng với \"-r\""
+
+#: options.cc:1020
+msgid "binary output format not compatible with -shared or -pie or -r"
+msgstr "định dạng kết xuất nhị phân không tương thích với tuỳ chọn \"-shared\" (dùng chung) hoặc \"-pie\" hoặc \"-r\""
+
+#: options.cc:1026
+#, c-format
+msgid "--hash-bucket-empty-fraction value %g out of range [0.0, 1.0)"
+msgstr "giá trị \"--hash-bucket-empty-fraction\" %g ở ngoại phạm vi [0.0, 1.0)"
+
+#: options.cc:1031
+msgid "Options --incremental-changed, --incremental-unchanged, --incremental-unknown require the use of --incremental"
+msgstr ""
+"Mỗi tuỳ chọn dưới đây:\n"
+" --incremental-changed (dần thay đổi)\n"
+" --incremental-unchanged (dần không thay đổi)\n"
+" --incremental-unknown (dần không rõ)\n"
+"thì yêu cầu lập tuỳ chọn \"--incremental\" (dần)."
+
+#: options.cc:1097
+msgid "May not nest groups"
+msgstr "Không cho phép nhóm lồng nhau"
+
+#: options.cc:1109
+msgid "Group end without group start"
+msgstr "Có cuối nhóm mà không có đầu nhóm"
+
+#. I guess it's neither a long option nor a short option.
+#: options.cc:1174
+msgid "unknown option"
+msgstr "tùy chọn không rõ"
+
+#: options.cc:1201
+#, c-format
+msgid "%s: missing group end\n"
+msgstr "%s: thiếu cuối nhóm\n"
+
+#: options.h:571
+msgid "Report usage information"
+msgstr "Thông báo thông tin về cách sử dụng"
+
+#: options.h:573
+msgid "Report version information"
+msgstr "Thông báo thông tin về phiên bản"
+
+#: options.h:575
+msgid "Report version and target information"
+msgstr "Thông báo thông tin về phiên bản và đích"
+
+#: options.h:584 options.h:635
+msgid "Not supported"
+msgstr "Không được hỗ trợ"
+
+#: options.h:585 options.h:636
+msgid "Do not copy DT_NEEDED tags from shared libraries"
+msgstr "Đừng sao chép thẻ \"DT_NEEDED\" từ thư viện dùng chung"
+
+#: options.h:588
+msgid "Allow unresolved references in shared libraries"
+msgstr "Cho phép tham chiếu chưa tháo gỡ trong thư viện dùng chung"
+
+#: options.h:589
+msgid "Do not allow unresolved references in shared libraries"
+msgstr "Đừng cho phép tham chiếu chưa tháo gỡ trong thư viện dùng chung"
+
+#: options.h:592
+msgid "Only set DT_NEEDED for shared libraries if used"
+msgstr "Chỉ lập thẻ \"DT_NEEDED\" cho thư viện dùng chung (nếu dùng)"
+
+#: options.h:593
+msgid "Always DT_NEEDED for shared libraries"
+msgstr "Lúc nào cũng lập thẻ \"DT_NEEDED\" cho thư viện dùng chung"
+
+#: options.h:600
+msgid "Set input format"
+msgstr "Lập định dạng đầu vào"
+
+#: options.h:603
+msgid "-l searches for shared libraries"
+msgstr "tuỳ chọn \"-l\" tìm kiếm thư viện dùng chung"
+
+#: options.h:605
+msgid "-l does not search for shared libraries"
+msgstr "tuỳ chọn \"-l\" không tìm kiếm thư viện dùng chung"
+
+#: options.h:609
+msgid "Bind defined symbols locally"
+msgstr "Tổ hợp cục bộ ký hiệu được xác định"
+
+#: options.h:612
+msgid "Bind defined function symbols locally"
+msgstr "Tổ hợp cục bộ ký hiệu hàm được xác định"
+
+#: options.h:615
+msgid "Generate build ID note"
+msgstr "Tạo ghi chú mã số xây dựng"
+
+#: options.h:616 options.h:655
+msgid "[=STYLE]"
+msgstr "[=KIỂU_DÁNG]"
+
+#: options.h:619
+msgid "Check segment addresses for overlaps (default)"
+msgstr "Kiểm tra địa chỉ phần có chồng chéo (mặc định)"
+
+#: options.h:620
+msgid "Do not check segment addresses for overlaps"
+msgstr "Đừng kiểm tra địa chỉ phần có chồng chéo"
+
+#: options.h:624 options.h:629
+msgid "Compress .debug_* sections in the output file"
+msgstr "Nén phần \".debug_*\" trong tập tin kết xuất"
+
+#: options.h:630
+msgid "[none]"
+msgstr "[không có]"
+
+#: options.h:639
+msgid "Define common symbols"
+msgstr "Xác định các ký hiệu chung"
+
+#: options.h:640
+msgid "Do not define common symbols"
+msgstr "Đừng xác định các ký hiệu chung"
+
+#: options.h:642 options.h:644
+msgid "Alias for -d"
+msgstr "Bí danh cho \"-d\""
+
+#: options.h:647
+msgid "Turn on debugging"
+msgstr "Bật gỡ lỗi"
+
+#: options.h:648
+msgid "[all,files,script,task][,...]"
+msgstr ""
+"[all,files,script,task][,...]\n"
+"\n"
+"all\ttất cả\n"
+"files\tcác tập tin\n"
+"script\tvăn lệnh\n"
+"task\tcông việc"
+
+#: options.h:651
+msgid "Define a symbol"
+msgstr "Xác định một ký hiệu"
+
+#: options.h:651
+msgid "SYMBOL=EXPRESSION"
+msgstr "KÝ_HIỆU=BIỂU_THỨC"
+
+#: options.h:654
+msgid "Demangle C++ symbols in log messages"
+msgstr "Tháo gỡ ký hiệu C++ trong thông điệp ghi lưu"
+
+#: options.h:658
+msgid "Do not demangle C++ symbols in log messages"
+msgstr "Đừng tháo gỡ ký hiệu C++ trong thông điệp ghi lưu"
+
+#: options.h:662
+msgid "Try to detect violations of the One Definition Rule"
+msgstr "Thử phát hiện sự vi phạm Quy tắc xác định đơn"
+
+#: options.h:666
+msgid "Delete all temporary local symbols"
+msgstr "Xoá bỏ tất cả các ký hiệu cục bộ tạm thời"
+
+#: options.h:669
+msgid "Add data symbols to dynamic symbols"
+msgstr "Thêm ký hiệu dữ liệu vào ký hiệu động"
+
+#: options.h:672
+msgid "Add C++ operator new/delete to dynamic symbols"
+msgstr "Thêm vào ký hiệu động toán từ mới/xoá (new/delete) kiểu C++"
+
+#: options.h:675
+msgid "Add C++ typeinfo to dynamic symbols"
+msgstr "Thêm vào ký hiệu động toán từ loại thông tin (typeinfo) kiểu C++"
+
+#: options.h:678
+msgid "Read a list of dynamic symbols"
+msgstr "Đọc một danh sách các ký hiệu động"
+
+#: options.h:678 options.h:732 options.h:766 options.h:893 options.h:921
+msgid "FILE"
+msgstr "TỆP"
+
+#: options.h:681
+msgid "Set program start address"
+msgstr "Đặt địa chỉ bắt đầu của chương trình"
+
+#: options.h:681 options.h:908 options.h:910 options.h:912
+msgid "ADDRESS"
+msgstr "ĐỊA_CHỈ"
+
+#: options.h:684
+msgid "Exclude libraries from automatic export"
+msgstr "Loại trừ thư viện ra việc tự động xuất khẩu"
+
+#: options.h:688
+msgid "Export all dynamic symbols"
+msgstr "Xuất mọi ký hiệu động"
+
+#: options.h:689
+msgid "Do not export all dynamic symbols (default)"
+msgstr "Đừng xuất ký hiệu động (mặc định)"
+
+#: options.h:692
+msgid "Create exception frame header"
+msgstr "Tạo phần đầu khung ngoại lệ"
+
+#: options.h:695
+msgid "Treat warnings as errors"
+msgstr "Xử lý cảnh báo là lỗi"
+
+#: options.h:696
+msgid "Do not treat warnings as errors"
+msgstr "Đừng xử lý cảnh báo là lỗi"
+
+#: options.h:699
+msgid "Call SYMBOL at unload-time"
+msgstr "Gọi KÝ_HIỆU vào lúc bỏ nạp"
+
+#: options.h:699 options.h:729 options.h:873 options.h:915 options.h:936
+#: options.h:939
+msgid "SYMBOL"
+msgstr "KÝ_HIỆU"
+
+#: options.h:702
+msgid "Set shared library name"
+msgstr "Lập tên thư viện dùng chung"
+
+#: options.h:702 options.h:792
+msgid "FILENAME"
+msgstr "TÊN_TỆP"
+
+#: options.h:705
+msgid "Min fraction of empty buckets in dynamic hash"
+msgstr "Tối thiểu phân số các xô trống trong hàm tạo chuỗi duy nhất động"
+
+#: options.h:706
+msgid "FRACTION"
+msgstr "PHÂN_SỐ"
+
+#: options.h:709
+msgid "Dynamic hash style"
+msgstr "Kiểu dáng hàm tạo chuỗi duy nhất động"
+
+#: options.h:709
+msgid "[sysv,gnu,both]"
+msgstr ""
+"[sysv,gnu,both]\n"
+"\n"
+"both\tcả hai"
+
+#: options.h:713
+msgid "Set dynamic linker path"
+msgstr "Lập đường dẫn đến bộ liên kết động"
+
+#: options.h:713
+msgid "PROGRAM"
+msgstr "CHƯƠNG_TRÌNH"
+
+#: options.h:716
+msgid "Work in progress; do not use"
+msgstr "Vẫn còn được phát triển: đừng sử dụng"
+
+#: options.h:717
+msgid "Do a full build"
+msgstr "Xây dựng hoàn toàn"
+
+#: options.h:720
+msgid "Assume files changed"
+msgstr "Giả sử tập tin bị thay đổi"
+
+#: options.h:723
+msgid "Assume files didn't change"
+msgstr "Giả sử tập tin chưa thay đổi"
+
+#: options.h:726
+msgid "Use timestamps to check files (default)"
+msgstr "Sử dụng nhãn thời gian để kiểm tra tập tin (mặc định)"
+
+#: options.h:729
+msgid "Call SYMBOL at load-time"
+msgstr "Gọi KÝ_HIỆU vào lúc nạp"
+
+#: options.h:732
+msgid "Read only symbol values from FILE"
+msgstr "Đọc chỉ những giá trị ký hiệu từ tập tin đưa ra"
+
+#: options.h:735
+msgid "Search for library LIBNAME"
+msgstr "Tìm kiếm thư viện tên này"
+
+#: options.h:735
+msgid "LIBNAME"
+msgstr "TÊN_THƯ_VIỆN"
+
+#: options.h:738
+msgid "Add directory to search path"
+msgstr "Thêm thư mục này vào đường dẫn tìm kiếm"
+
+#: options.h:738 options.h:813 options.h:816 options.h:820 options.h:887
+msgid "DIR"
+msgstr "TMỤC"
+
+#: options.h:741
+msgid "Ignored for compatibility"
+msgstr "Bị bỏ qua để tương thích"
+
+#: options.h:741
+msgid "EMULATION"
+msgstr "MÔ_PHỎNG"
+
+#: options.h:744
+msgid "Write map file on standard output"
+msgstr "In tập tin sơ đồ ra đầu ra tiêu chuẩn"
+
+#: options.h:745
+msgid "Write map file"
+msgstr "Ghi tập tin sơ đồ"
+
+#: options.h:746
+msgid "MAPFILENAME"
+msgstr "TÊN_TỆP_SƠ_ĐỒ"
+
+#: options.h:749
+msgid "Do not page align data"
+msgstr "Đừng chỉnh canh dữ liệu theo trang"
+
+#: options.h:751
+msgid "Do not page align data, do not make text readonly"
+msgstr "Đừng chỉnh canh dữ liệu theo trang, đừng đặt văn bản là chỉ-đọc"
+
+#: options.h:752
+msgid "Page align data, make text readonly"
+msgstr "Chỉnh canh dữ liệu theo trang, đặt văn bản là chỉ-đọc"
+
+#: options.h:755
+msgid "Enable use of DT_RUNPATH and DT_FLAGS"
+msgstr "Bật sử dụng \"DT_RUNPATH\" và \"DT_FLAGS\""
+
+#: options.h:756
+msgid "Disable use of DT_RUNPATH and DT_FLAGS"
+msgstr "Tắt sử dụng \"DT_RUNPATH\" và \"DT_FLAGS\""
+
+#: options.h:759
+msgid "Create an output file even if errors occur"
+msgstr "Tạo tập tin kết xuất thậm chí nếu gặp lỗi"
+
+#: options.h:762 options.h:958
+msgid "Report undefined symbols (even with --shared)"
+msgstr "Thông báo ký hiệu chưa xác định (ngay cả khi lập tuỳ chọn \"--shared\")"
+
+#: options.h:766
+msgid "Set output file name"
+msgstr "Đặt tên tập tin kết xuất"
+
+#: options.h:769
+msgid "Optimize output file size"
+msgstr "Tối ưu hoá kích cỡ tập tin kết xuất"
+
+#: options.h:769
+msgid "LEVEL"
+msgstr "CẤP"
+
+#: options.h:772
+msgid "Set output format"
+msgstr "Đặt định dạng kết xuất"
+
+#: options.h:772
+msgid "[binary]"
+msgstr "[nhị phân]"
+
+#: options.h:775 options.h:777
+msgid "Create a position independent executable"
+msgstr "Tạo một bản thực hiện không phụ thuộc vào vị trí"
+
+#: options.h:782
+msgid "Load a plugin library"
+msgstr "Nạp một thư viện phần bổ sung"
+
+#: options.h:782
+msgid "PLUGIN"
+msgstr "PHẦN BỔ SUNG"
+
+#: options.h:784
+msgid "Pass an option to the plugin"
+msgstr "Gửi một tuỳ chọn cho phần bổ sung"
+
+#: options.h:784
+msgid "OPTION"
+msgstr "TÙY CHỌN"
+
+#: options.h:788
+msgid "Preread archive symbols when multi-threaded"
+msgstr "Đọc sẵn các ký hiệu kho lưu khi chạy đa luồng"
+
+#: options.h:791
+msgid "Print symbols defined and used for each input"
+msgstr "In ra những ký hiệu được xác định và sử dụng cho mỗi đầu vào"
+
+#: options.h:795
+msgid "Ignored for SVR4 compatibility"
+msgstr "Bị bỏ qua để tương thích với SVR4"
+
+#: options.h:798
+msgid "Generate relocations in output"
+msgstr "Tạo ra sự định vị lại trong kết xuất"
+
+#: options.h:801
+msgid "Generate relocatable output"
+msgstr "Tạo ra kết xuất có thể định vị lại"
+
+#: options.h:804
+msgid "Relax branches on certain targets"
+msgstr "Lơi ra nhánh trên một số đích nào đó"
+
+#: options.h:807
+msgid "keep only symbols listed in this file"
+msgstr "giữ chỉ những ký hiệu nằm trong tập tin này"
+
+#: options.h:807
+msgid "[file]"
+msgstr "[tệp]"
+
+#: options.h:813 options.h:816
+msgid "Add DIR to runtime search path"
+msgstr "Thêm TMỤC vào đường dẫn tìm kiếm lúc chạy"
+
+#: options.h:819
+msgid "Add DIR to link time shared library search path"
+msgstr "Thêm TMỤC vào đường dẫn tìm kiếm thư viện dùng chung vào lúc liên kết"
+
+#: options.h:823
+msgid "Strip all symbols"
+msgstr "Tước mọi ký hiệu"
+
+#: options.h:825
+msgid "Strip debugging information"
+msgstr "Tước thông tin gỡ lỗi"
+
+#: options.h:827
+msgid "Emit only debug line number information"
+msgstr "Xuất chỉ thông tin về số thứ tự dòng gỡ lỗi"
+
+#: options.h:829
+msgid "Strip debug symbols that are unused by gdb (at least versions <= 6.7)"
+msgstr "Tước ký hiệu gỡ lỗi không phải do gdb dùng (ít nhất phiên bản ≤ 6.7)"
+
+#: options.h:832
+msgid "Strip LTO intermediate code sections"
+msgstr "Tước các phần mã trung gian LTO"
+
+#: options.h:835
+msgid "(ARM only) The maximum distance from instructions in a group of sections to their stubs. Negative values mean stubs are always after the group. 1 means using default size.\n"
+msgstr "(Chỉ cho ARM) Khoảng cách tối đa giữa câu lệnh và mẩu trong một nhóm phần. Giá trị âm đặt mẩu đẳng sau nhóm; giá trị 1 sử dụng kích cỡ mặc định.\n"
+
+#: options.h:838 options.h:852 options.h:956 options.h:975
+msgid "SIZE"
+msgstr "CỠ"
+
+#: options.h:841
+msgid "Use less memory and more disk I/O (included only for compatibility with GNU ld)"
+msgstr "Sử dụng vùng nhớ nhỏ hơn và vùng V/R đĩa lớn hơn (bao gồm chỉ để tương thích với ld của GNU)"
+
+#: options.h:845 options.h:848
+msgid "Generate shared library"
+msgstr "Tạo thư viện dùng chung"
+
+#: options.h:851
+msgid "Stack size when -fsplit-stack function calls non-split"
+msgstr "Kích cỡ đống khi hàm \"-fsplit-stack\" gọi \"non-split\""
+
+#: options.h:857
+msgid "Do not link against shared libraries"
+msgstr "Đừng liên kết so với thư viện dùng chung"
+
+#: options.h:860
+msgid "Identical Code Folding. '--icf=safe' folds only ctors and dtors."
+msgstr "ICF = gấp lại mã trùng. \"--icf-safe\" chỉ gấp lại các ctor và dtor."
+
+#: options.h:866
+msgid "Number of iterations of ICF (default 2)"
+msgstr "Số các lần lặp lại ICF (mặc định là 2)"
+
+#: options.h:866 options.h:899 options.h:901 options.h:903 options.h:905
+msgid "COUNT"
+msgstr "SỐ_ĐẾM"
+
+#: options.h:869
+msgid "List folded identical sections on stderr"
+msgstr "Liệt kê các phần trùng gấp lại trên đầu lỗi tiêu chuẩn"
+
+#: options.h:870
+msgid "Do not list folded identical sections"
+msgstr "Đừng liệt kê phần trùng gấp lại"
+
+#: options.h:873
+msgid "Do not fold this symbol during ICF"
+msgstr "Đừng gấp lại ký hiệu này trong khi ICF"
+
+#: options.h:876
+msgid "Remove unused sections"
+msgstr "Gỡ bỏ phần không dùng nào"
+
+#: options.h:877
+msgid "Don't remove unused sections (default)"
+msgstr "Đừng gỡ bỏ phần không dùng (mặc định)"
+
+#: options.h:880
+msgid "List removed unused sections on stderr"
+msgstr "Liệt kê trên đầu lỗi tiêu chuẩn các phần không dùng bị gỡ bỏ"
+
+#: options.h:881
+msgid "Do not list removed unused sections"
+msgstr "Không liệt kê phần không dùng bị gỡ bỏ"
+
+#: options.h:884
+msgid "Print resource usage statistics"
+msgstr "In ra thống kê cách sử dụng tài nguyên"
+
+#: options.h:887
+msgid "Set target system root directory"
+msgstr "Lập thư mục gốc của hệ thống đích"
+
+#: options.h:890
+msgid "Print the name of each input file"
+msgstr "In ra tên của mỗi tập tin nhập vào"
+
+#: options.h:893
+msgid "Read linker script"
+msgstr "Đọc văn lệnh liên kết"
+
+#: options.h:896
+msgid "Run the linker multi-threaded"
+msgstr "Chạy bộ liên kết một cách đa luồng"
+
+#: options.h:897
+msgid "Do not run the linker multi-threaded"
+msgstr "Đừng chạy bộ liên kết một cách đa luồng"
+
+#: options.h:899
+msgid "Number of threads to use"
+msgstr "Số các nhánh cần dùng"
+
+#: options.h:901
+msgid "Number of threads to use in initial pass"
+msgstr "Số các nhánh cần dùng trong lần đi qua đầu tiên"
+
+#: options.h:903
+msgid "Number of threads to use in middle pass"
+msgstr "Số các nhánh cần dùng trong lần đi qua vừa"
+
+#: options.h:905
+msgid "Number of threads to use in final pass"
+msgstr "Số các nhánh cần dùng trong lần đi qua cuối cùng"
+
+#: options.h:908
+msgid "Set the address of the bss segment"
+msgstr "Đặt địa chỉ của đoạn \"bss\""
+
+#: options.h:910
+msgid "Set the address of the data segment"
+msgstr "Đặt địa chỉ của đoạn \"data\" (dữ liệu)"
+
+#: options.h:912
+msgid "Set the address of the text segment"
+msgstr "Đặt địa chỉ của đoạn \"text\" (văn bản)"
+
+#: options.h:915
+msgid "Create undefined reference to SYMBOL"
+msgstr "Tạo tham chiếu chưa xác định đến ký hiệu này"
+
+#: options.h:918
+msgid "Synonym for --debug=files"
+msgstr "Bằng \"--debug=files\""
+
+#: options.h:921
+msgid "Read version script"
+msgstr "Đọc văn lệnh phiên bản"
+
+#: options.h:924
+msgid "Warn about duplicate common symbols"
+msgstr "Cảnh báo về ký hiệu chung trùng"
+
+#: options.h:925
+msgid "Do not warn about duplicate common symbols (default)"
+msgstr "Không cảnh báo về ký hiệu chung trùng (mặc định)"
+
+#: options.h:928
+msgid "Warn when skipping an incompatible library"
+msgstr "Cảnh báo khi bỏ qua một thư viện không tương thích"
+
+#: options.h:929
+msgid "Don't warn when skipping an incompatible library"
+msgstr "Không cảnh báo khi bỏ qua một thư viện không tương thích"
+
+#: options.h:932
+msgid "Include all archive contents"
+msgstr "Bao gồm toàn bộ nội dung kho lưu"
+
+#: options.h:933
+msgid "Include only needed archive contents"
+msgstr "Bao gồm chỉ nội dung kho lưu yêu cầu"
+
+#: options.h:936
+msgid "Use wrapper functions for SYMBOL"
+msgstr "Sử dụng các hàm bao bọc cho KÝ_HIỆU"
+
+#: options.h:939
+msgid "Trace references to symbol"
+msgstr "Tìm đường của tham chiếu đến ký hiệu"
+
+#: options.h:942
+msgid "Default search path for Solaris compatibility"
+msgstr "Đường dẫn tìm kiếm mặc định để tương thích với Solaris"
+
+#: options.h:943
+msgid "PATH"
+msgstr "ĐƯỜNG_DẪN"
+
+#: options.h:946
+msgid "Start a library search group"
+msgstr "Bắt đầu một nhóm tìm kiếm thư viện"
+
+#: options.h:948
+msgid "End a library search group"
+msgstr "Kết thúc một nhóm tìm kiếm thư viện"
+
+#: options.h:953
+msgid "Sort dynamic relocs"
+msgstr "Sắp xếp các sự định vị lại động"
+
+#: options.h:954
+msgid "Do not sort dynamic relocs"
+msgstr "Đừng sắp xếp các sự định vị lại động"
+
+#: options.h:956
+msgid "Set common page size to SIZE"
+msgstr "Đặt kích cỡ trang chung thành CỠ"
+
+#: options.h:961
+msgid "Mark output as requiring executable stack"
+msgstr "Đánh dấu kết xuất như là yêu cầu đống có thể thực hiện được"
+
+#: options.h:963
+msgid "Mark DSO to be initialized first at runtime"
+msgstr "Đánh dấu DSO để được sơ khởi trước hết vào lúc chạy"
+
+#: options.h:966
+msgid "Mark object to interpose all DSOs but executable"
+msgstr "Đánh dấu đối tượng để chèn tất cả các DSO trừ bản có thể thực hiện được"
+
+#: options.h:969
+msgid "Mark object for lazy runtime binding (default)"
+msgstr "Đánh dấu đối tượng để tổ hợp lười vào lúc chạy (mặc định)"
+
+#: options.h:972
+msgid "Mark object requiring immediate process"
+msgstr "Đánh dấu đối tượng yêu cầu xử lý ngay lập tức"
+
+#: options.h:975
+msgid "Set maximum page size to SIZE"
+msgstr "Đặt kích cỡ trang tối đa thành CỠ"
+
+#: options.h:978
+msgid "Do not create copy relocs"
+msgstr "Không tạo bản sao định vị lại"
+
+#: options.h:980
+msgid "Mark object not to use default search paths"
+msgstr "Đánh dấu đối tượng không nên dùng đường dẫn tìm kiếm mặc định"
+
+#: options.h:983
+msgid "Mark DSO non-deletable at runtime"
+msgstr "Đánh dấu DSO không thể được xoá vào lúc chạy."
+
+#: options.h:986
+msgid "Mark DSO not available to dlopen"
+msgstr "Đánh dấu DSO không sẵn sàng cho dlopen"
+
+#: options.h:989
+msgid "Mark DSO not available to dldump"
+msgstr "Đánh dấu DSO không sẵn sàng cho dldump"
+
+#: options.h:992
+msgid "Mark output as not requiring executable stack"
+msgstr "Đánh dấu kết xuất như là không yêu cầu đống có thể thực hiện được"
+
+#: options.h:994
+msgid "Mark object for immediate function binding"
+msgstr "Đánh dấu đối tượng yêu cầu tổ hợp hàm ngay lập tức"
+
+#: options.h:997
+msgid "Mark DSO to indicate that needs immediate $ORIGIN processing at runtime"
+msgstr "Đánh dấu DSO để ngụ ý nó yêu cầu xử lý $ORIGIN ngay lập tức vào lúc chạy"
+
+#: options.h:1000
+msgid "Where possible mark variables read-only after relocation"
+msgstr "Khi có thể, đánh dấu biến là chỉ-đọc sau khi định vị lại"
+
+#: options.h:1001
+msgid "Don't mark variables read-only after relocation"
+msgstr "Đừng đánh dấu biến là chỉ-đọc sau khi định vị lại"
+
+#: output.cc:1132
+msgid "section group retained but group element discarded"
+msgstr "nhóm phần được giữ lại còn phần tử nhóm bị hủy"
+
+#: output.cc:1860
+#, c-format
+msgid "invalid alignment %lu for section \"%s\""
+msgstr "sai chỉnh canh %lu cho phần \"%s\""
+
+#: output.cc:3573
+#, c-format
+msgid "dot moves backward in linker script from 0x%llx to 0x%llx"
+msgstr "chấm đi ngược trong văn lệnh liên kết từ 0x%llx về 0x%llx"
+
+#: output.cc:3576
+#, c-format
+msgid "address of section '%s' moves backward from 0x%llx to 0x%llx"
+msgstr "địa chỉ của phần \"%s\" đi ngược từ 0x%llx về 0x%llx"
+
+#: output.cc:3755
+#, c-format
+msgid "nobits section %s may not precede progbits section %s in same segment"
+msgstr "phần \"nobits\" %s có thể không phải đi trước phần \"progbits\" %s trong cùng một đoạn"
+
+#: output.cc:3907 output.cc:3975
+#, c-format
+msgid "%s: open: %s"
+msgstr "%s: mở : %s"
+
+#: output.cc:3996
+#, c-format
+msgid "%s: mremap: %s"
+msgstr "%s: mremap: %s"
+
+#: output.cc:4005
+#, c-format
+msgid "%s: mmap: %s"
+msgstr "%s: mmap: %s"
+
+#: output.cc:4085
+#, c-format
+msgid "%s: mmap: failed to allocate %lu bytes for output file: %s"
+msgstr "%s: mmap: không cấp phát được %lu byte cho tập tin kết xuất: %s"
+
+#: output.cc:4096
+#, c-format
+msgid "%s: munmap: %s"
+msgstr "%s: munmap: %s"
+
+#: output.cc:4115
+#, c-format
+msgid "%s: write: unexpected 0 return-value"
+msgstr "%s: ghi: gặp giá trị trả lại 0 không mong đợi"
+
+#: output.cc:4117
+#, c-format
+msgid "%s: write: %s"
+msgstr "%s: ghi: %s"
+
+#: output.cc:4132
+#, c-format
+msgid "%s: close: %s"
+msgstr "%s: đóng: %s"
+
+#: output.h:520
+msgid "** section headers"
+msgstr "** dòng đầu phần"
+
+#: output.h:565
+msgid "** segment headers"
+msgstr "** dòng đầu đoạn"
+
+#: output.h:613
+msgid "** file header"
+msgstr "** dòng đầu tập tin"
+
+#: output.h:833
+msgid "** fill"
+msgstr "** tô đầy"
+
+#: output.h:987
+msgid "** string table"
+msgstr "** bảng chuỗi"
+
+#: output.h:1300
+msgid "** dynamic relocs"
+msgstr "** sự định vị lại động"
+
+#: output.h:1301 output.h:1637
+msgid "** relocs"
+msgstr "** sự định vị lại"
+
+#: output.h:1662
+msgid "** group"
+msgstr "** nhóm"
+
+#: output.h:1774
+msgid "** GOT"
+msgstr "** GOT"
+
+#: output.h:1916
+msgid "** dynamic"
+msgstr "** động"
+
+#: output.h:2039
+msgid "** symtab xindex"
+msgstr "** symtab xindex"
+
+#: parameters.cc:172
+#, c-format
+msgid "unrecognized output format %s"
+msgstr "không nhận ra định dạng kết xuất %s"
+
+#: plugin.cc:106
+#, c-format
+msgid "%s: could not load plugin library"
+msgstr "%s: không nạp được thư viện phần bổ sung"
+
+#: plugin.cc:116
+#, c-format
+msgid "%s: could not find onload entry point"
+msgstr "%s: không tìm thấy điểm vào khi nạp"
+
+#: plugin.cc:426
+msgid "Input files added by plug-ins in --incremental mode not supported yet.\n"
+msgstr "tập tin đầu vào được thêm vào phần bổ sung trong chế độ dần (--incremental) chưa được hỗ trợ.\n"
+
+#: powerpc.cc:1502 sparc.cc:2307 x86_64.cc:1632
+#, c-format
+msgid "%s: unsupported REL reloc section"
+msgstr "%s: phần định vị lại REL không được hỗ trợ"
+
+#: readsyms.cc:191
+#, c-format
+msgid "%s: file is empty"
+msgstr "%s: tập tin còn trống"
+
+#. Here we have to handle any other input file types we need.
+#: readsyms.cc:575
+#, c-format
+msgid "%s: not an object or archive"
+msgstr "%s: không phải một đối tượng hay kho lưu"
+
+#: reduced_debug_output.cc:236
+msgid "Debug abbreviations extend beyond .debug_abbrev section; failed to reduce debug abbreviations"
+msgstr "Viết tắt gỡ lỗi kéo dài qua phần \".debug_abbrev\": không giảm được viết tắt gỡ lỗi"
+
+#: reduced_debug_output.cc:322
+msgid "Extremely large compile unit in debug info; failed to reduce debug info"
+msgstr "Gặp đơn vị biên dịch rất lớn trong thông tin gỡ lỗi: không giảm được thông tin gỡ lỗi"
+
+#: reduced_debug_output.cc:330
+msgid "Debug info extends beyond .debug_info section;failed to reduce debug info"
+msgstr "Thông tin gỡ lỗi kéo dài qua phần \".debug_info\": không giảm được thông tin gỡ lỗi"
+
+#: reduced_debug_output.cc:350 reduced_debug_output.cc:392
+msgid "Invalid DIE in debug info; failed to reduce debug info"
+msgstr "Gặp DIE sai trong thông tin gỡ lỗi: không giảm được thông tin gỡ lỗi"
+
+#: reduced_debug_output.cc:373
+msgid "Debug info extends beyond .debug_info section; failed to reduce debug info"
+msgstr "Thông tin gỡ lỗi kéo dài qua phần \".debug_info\": không giảm được thông tin gỡ lỗi"
+
+#: reloc.cc:297 reloc.cc:858
+#, c-format
+msgid "relocation section %u uses unexpected symbol table %u"
+msgstr "phần định vị lại %u dùng bảng ký hiệu không mong đợi %u"
+
+#: reloc.cc:312 reloc.cc:875
+#, c-format
+msgid "unexpected entsize for reloc section %u: %lu != %u"
+msgstr "phần định vị lại %u có kích cỡ entsize không mong đợi: %lu != %u"
+
+#: reloc.cc:321 reloc.cc:884
+#, c-format
+msgid "reloc section %u size %lu uneven"
+msgstr "phần định vị lại %u có kích cỡ %lu không đều"
+
+#: reloc.cc:1203
+#, c-format
+msgid "could not convert call to '%s' to '%s'"
+msgstr "không thể chuyển đổi cuộc gọi \"%s\" sang \"%s\""
+
+#: reloc.cc:1343
+#, c-format
+msgid "reloc section size %zu is not a multiple of reloc size %d\n"
+msgstr "kích cỡ phần định vị lại %zu không phải là bội số cho kích cỡ sự định vị lại %d\n"
+
+#. We should only see externally visible symbols in the symbol
+#. table.
+#: resolve.cc:191
+msgid "invalid STB_LOCAL symbol in external symbols"
+msgstr "gặp ký hiệu \"STB_LOCAL\" sai trong những ký hiệu bên ngoài"
+
+#. Any target which wants to handle STB_LOOS, etc., needs to
+#. define a resolve method.
+#: resolve.cc:197
+msgid "unsupported symbol binding"
+msgstr "tổ hợp ký hiệu không được hỗ trợ"
+
+#. A dynamic object cannot reference a hidden or internal symbol
+#. defined in another object.
+#: resolve.cc:266
+#, c-format
+msgid "%s symbol '%s' in %s is referenced by DSO %s"
+msgstr "ký hiệu %s \"%s\" trong %s được tham chiếu bởi DSO %s"
+
+#: resolve.cc:326
+#, c-format
+msgid "common of '%s' overriding smaller common"
+msgstr "điều chung của \"%s\" ghi đè lên điều chung nhỏ hơn"
+
+#: resolve.cc:331
+#, c-format
+msgid "common of '%s' overidden by larger common"
+msgstr "điều chung của \"%s\" bị ghi đè bởi điều chung lớn hơn"
+
+#: resolve.cc:336
+#, c-format
+msgid "multiple common of '%s'"
+msgstr "nhiều điều chung của \"%s\""
+
+#: resolve.cc:442
+#, c-format
+msgid "multiple definition of '%s'"
+msgstr "nhiều lời xác định \"%s\""
+
+#: resolve.cc:481
+#, c-format
+msgid "definition of '%s' overriding common"
+msgstr "lời xác định của \"%s\" ghi đè lên điều chung"
+
+#: resolve.cc:516
+#, c-format
+msgid "definition of '%s' overriding dynamic common definition"
+msgstr "lời xác định của \"%s\" ghi đè lên lời xác định chung động"
+
+#: resolve.cc:636
+#, c-format
+msgid "common '%s' overridden by previous definition"
+msgstr "điều chung \"%s\" bị ghi đè bởi lời xác định trước"
+
+#: resolve.cc:766 resolve.cc:778
+msgid "command line"
+msgstr "dòng lệnh"
+
+#: script-sections.cc:690
+msgid "dot may not move backward"
+msgstr "chấm không thể di chuyển về phía sau"
+
+#: script-sections.cc:757
+msgid "** expression"
+msgstr "** biểu thức"
+
+#: script-sections.cc:941
+msgid "fill value is not absolute"
+msgstr "giá trị tô đầy không phải là tuyệt đối"
+
+#: script-sections.cc:1913
+#, c-format
+msgid "alignment of section %s is not absolute"
+msgstr "sự chỉnh canh phần %s không phải là tuyệt đối"
+
+#: script-sections.cc:1957
+#, c-format
+msgid "subalign of section %s is not absolute"
+msgstr "sự chỉnh canh phụ phần %s không phải là tuyệt đối"
+
+#: script-sections.cc:1972
+#, c-format
+msgid "fill of section %s is not absolute"
+msgstr "tô đầy phần %s không phải là tuyệt đối"
+
+#: script-sections.cc:2048
+msgid "SPECIAL constraints are not implemented"
+msgstr "ràng buộc SPECIAL (đặc biệt) chưa được thực hiện"
+
+#: script-sections.cc:2090
+msgid "mismatched definition for constrained sections"
+msgstr "lời xác định không tương ứng với phần ràng buộc"
+
+#: script-sections.cc:2634
+msgid "DATA_SEGMENT_ALIGN may only appear once in a linker script"
+msgstr "\"DATA_SEGMENT_ALIGN\" chỉ có thể xuất hiện một lần trong một văn lệnh liên kết"
+
+#: script-sections.cc:2649
+msgid "DATA_SEGMENT_RELRO_END may only appear once in a linker script"
+msgstr "\"DATA_SEGMENT_RELRO_END\" chỉ có thể xuất hiện một lần trong một văn lệnh liên kết"
+
+#: script-sections.cc:2654
+msgid "DATA_SEGMENT_RELRO_END must follow DATA_SEGMENT_ALIGN"
+msgstr "\"DATA_SEGMENT_RELRO_END\" phải theo sau \"DATA_SEGMENT_ALIGN\""
+
+#: script-sections.cc:2826
+msgid "no matching section constraint"
+msgstr "không có ràng buộc phần tương ứng"
+
+#: script-sections.cc:3151
+msgid "TLS sections are not adjacent"
+msgstr "các phần TLS không phải kề nhau"
+
+#: script-sections.cc:3280
+msgid "allocated section not in any segment"
+msgstr "phần đã cấp phát không nằm trong đoạn nào"
+
+#: script-sections.cc:3309
+#, c-format
+msgid "no segment %s"
+msgstr "không có phân %s"
+
+#: script-sections.cc:3323
+msgid "section in two PT_LOAD segments"
+msgstr "phần nằm trong hai đoạn \"PT_LOAD\""
+
+#: script-sections.cc:3330
+msgid "allocated section not in any PT_LOAD segment"
+msgstr "phần đã cấp phát không nằm trong đoạn \"PT_LOAD\" nào"
+
+#: script-sections.cc:3358
+msgid "may only specify load address for PT_LOAD segment"
+msgstr "chỉ có thể ghi rõ địa chỉ nạp cho đoạn \"PT_LOAD\""
+
+#: script-sections.cc:3382
+#, c-format
+msgid "PHDRS load address overrides section %s load address"
+msgstr "địa chỉ nạp PHDRS thì ghi đè lên địa chỉ nạp phần %s"
+
+#. We could support this if we wanted to.
+#: script-sections.cc:3393
+msgid "using only one of FILEHDR and PHDRS is not currently supported"
+msgstr "đang dùng chỉ một của FILEHDR và PHDRS hiện thời không được hỗ trợ"
+
+#: script-sections.cc:3408
+msgid "sections loaded on first page without room for file and program headers are not supported"
+msgstr "không hỗ trợ phần được nạp trên trang đầu tiên mà không vừa dòng đầu của tập tin và chương trình"
+
+#: script-sections.cc:3414
+msgid "using FILEHDR and PHDRS on more than one PT_LOAD segment is not currently supported"
+msgstr "hiện thời không hỗ trợ sử dụng FILEHDR và PHDRS trên nhiều đoạn \"PT_LOAD\""
+
+#: script.cc:1072
+msgid "invalid use of PROVIDE for dot symbol"
+msgstr "sai sử dụng \"PROVIDE\" (cung cấp) cho ký hiệu chấm"
+
+#: script.cc:2132
+#, c-format
+msgid "%s:%d:%d: %s"
+msgstr "%s:%d:%d: %s"
+
+#. There are some options that we could handle here--e.g.,
+#. -lLIBRARY. Should we bother?
+#: script.cc:2297
+#, c-format
+msgid "%s:%d:%d: ignoring command OPTION; OPTION is only valid for scripts specified via -T/--script"
+msgstr "%s:%d:%d: đang bỏ qua TÙY_CHỌN về lệnh: TÙY_CHỌN chỉ được chấp nhận cho văn lệnh được ghi rõ thông qua \"-T/--script\""
+
+#: script.cc:2362
+#, c-format
+msgid "%s:%d:%d: ignoring SEARCH_DIR; SEARCH_DIR is only valid for scripts specified via -T/--script"
+msgstr "%s:%d:%d: đang bỏ qua \"SEARCH_DIR\": SEARCH_DIR chỉ được chấp nhận cho văn lệnh được ghi rõ thông qua \"-T/--script\""
+
+#: script.cc:2606 script.cc:2620
+#, c-format
+msgid "%s:%d:%d: DATA_SEGMENT_ALIGN not in SECTIONS clause"
+msgstr "%s:%d:%d: \"DATA_SEGMENT_ALIGN\" không phải trong mệnh đề \"SECTIONS\""
+
+#: script.cc:2739
+msgid "unknown PHDR type (try integer)"
+msgstr "không rõ kiểu PHDR (thử số nguyên)"
+
+#: stringpool.cc:528
+#, c-format
+msgid "%s: %s entries: %zu; buckets: %zu\n"
+msgstr "%s: mục nhập %s: %zu; xô: %zu\n"
+
+#: stringpool.cc:532
+#, c-format
+msgid "%s: %s entries: %zu\n"
+msgstr "%s: mục nhập %s: %zu\n"
+
+#: stringpool.cc:535
+#, c-format
+msgid "%s: %s Stringdata structures: %zu\n"
+msgstr "%s: %s cấu trúc Stringdata (dữ liệu chuỗi): %zu\n"
+
+#: symtab.cc:857
+#, c-format
+msgid "%s: reference to %s"
+msgstr "%s: tham chiếu đến %s"
+
+#: symtab.cc:859
+#, c-format
+msgid "%s: definition of %s"
+msgstr "%s: lời xác định %s"
+
+#: symtab.cc:1052
+#, c-format
+msgid "bad global symbol name offset %u at %zu"
+msgstr "sai đặt khoảng bù tên ký hiệu toàn cục %u tại %zu"
+
+#: symtab.cc:1278
+msgid "--just-symbols does not make sense with a shared object"
+msgstr "\"--just-symbols\" (chỉ ký hiệu) không có ý nghĩa với một đối tượng dùng chung"
+
+#: symtab.cc:1284
+msgid "too few symbol versions"
+msgstr "quá ít phiên bản ký hiệu"
+
+#: symtab.cc:1333
+#, c-format
+msgid "bad symbol name offset %u at %zu"
+msgstr "sai đặt khoảng bù tên ký hiệu %u tại %zu"
+
+#: symtab.cc:1396
+#, c-format
+msgid "versym for symbol %zu out of range: %u"
+msgstr "versym cho ký hiệu %zu ở ngoại phạm vi: %u"
+
+#: symtab.cc:1404
+#, c-format
+msgid "versym for symbol %zu has no name: %u"
+msgstr "versym cho ký hiệu %zu không có tên: %u"
+
+#: symtab.cc:2549 symtab.cc:2681
+#, c-format
+msgid "%s: unsupported symbol section 0x%x"
+msgstr "%s: phần ký hiệu không được hỗ trợ 0x%x"
+
+#: symtab.cc:2933
+#, c-format
+msgid "%s: symbol table entries: %zu; buckets: %zu\n"
+msgstr "%s: mục nhập bảng ký hiệu: %zu; xô : %zu\n"
+
+#: symtab.cc:2936
+#, c-format
+msgid "%s: symbol table entries: %zu\n"
+msgstr "%s: mục nhập bảng ký hiệu: %zu\n"
+
+#: symtab.cc:3007
+#, c-format
+msgid "while linking %s: symbol '%s' defined in multiple places (possible ODR violation):"
+msgstr "trong khi liên kết %s: ký hiệu \"%s\" được xác định trong nhiều lần (có thể vi phạm quy tắc xác định đơn):"
+
+#: target-reloc.h:259
+msgid "relocation refers to discarded comdat section"
+msgstr "định vị lại tham chiếu đến đoạn comdat bị hủy"
+
+#: target-reloc.h:298
+#, c-format
+msgid "reloc has bad offset %zu"
+msgstr "sự định vị lại có khoảng bù sai %zu"
+
+#: target.cc:90
+#, c-format
+msgid "%s: unsupported ELF file type %d"
+msgstr "%s: dạng tập tin ELF không được hỗ trợ %d"
+
+#: target.cc:157
+#, c-format
+msgid "linker does not include stack split support required by %s"
+msgstr "bộ liên kết không bao gồm hỗ trợ chia đống ra yêu cầu bởi %s"
+
+#: tls.h:59
+msgid "TLS relocation out of range"
+msgstr "sự định vị lại TLS ở ngoại phạm vi"
+
+#: tls.h:73
+msgid "TLS relocation against invalid instruction"
+msgstr "sự định vị lại TLS so với câu lệnh sai"
+
+#. This output is intended to follow the GNU standards.
+#: version.cc:65
+#, c-format
+msgid "Copyright 2008 Free Software Foundation, Inc.\n"
+msgstr "Tác quyền © năm 2008 của Tổ chức Phần mềm Tự do.\n"
+
+#: version.cc:66
+#, c-format
+msgid ""
+"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) a later version.\n"
+"This program has absolutely no warranty.\n"
+msgstr ""
+"Chương trình này là phần mềm tự do; bạn có quyền phát hành lại\n"
+"nó với điều kiện của Giấy Phép Công Cộng GNU (GPL)\n"
+"phiên bản 3 hoặc (tùy chọn) bắt cứ phiên bản sau nào.\n"
+"Chương trình này không bảo đảm gì cả.\n"
+
+#: workqueue-threads.cc:106
+#, c-format
+msgid "%s failed: %s"
+msgstr "%s: bị lỗi: %s"
+
+#: x86_64.cc:2184
+#, c-format
+msgid "unsupported reloc type %u"
+msgstr "kiểu định vị lại không được hỗ trợ %u"
+
+#: x86_64.cc:2524
+#, c-format
+msgid "unsupported reloc %u against local symbol"
+msgstr "sự định vị lại không được hỗ trợ %u so với ký hiệu cục bộ"
diff --git a/binutils-2.25/gold/powerpc.cc b/binutils-2.25/gold/powerpc.cc
new file mode 100644
index 00000000..880b367c
--- /dev/null
+++ b/binutils-2.25/gold/powerpc.cc
@@ -0,0 +1,7754 @@
+// powerpc.cc -- powerpc target support for gold.
+
+// Copyright 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+// Written by David S. Miller <davem@davemloft.net>
+// and David Edelsohn <edelsohn@gnu.org>
+
+// 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 <set>
+#include <algorithm>
+#include "elfcpp.h"
+#include "dwarf.h"
+#include "parameters.h"
+#include "reloc.h"
+#include "powerpc.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 "errors.h"
+#include "gc.h"
+
+namespace
+{
+
+using namespace gold;
+
+template<int size, bool big_endian>
+class Output_data_plt_powerpc;
+
+template<int size, bool big_endian>
+class Output_data_brlt_powerpc;
+
+template<int size, bool big_endian>
+class Output_data_got_powerpc;
+
+template<int size, bool big_endian>
+class Output_data_glink;
+
+template<int size, bool big_endian>
+class Stub_table;
+
+inline bool
+is_branch_reloc(unsigned int r_type);
+
+template<int size, bool big_endian>
+class Powerpc_relobj : public Sized_relobj_file<size, big_endian>
+{
+public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef Unordered_set<Section_id, Section_id_hash> Section_refs;
+ typedef Unordered_map<Address, Section_refs> Access_from;
+
+ Powerpc_relobj(const std::string& name, Input_file* input_file, off_t offset,
+ const typename elfcpp::Ehdr<size, big_endian>& ehdr)
+ : Sized_relobj_file<size, big_endian>(name, input_file, offset, ehdr),
+ special_(0), has_small_toc_reloc_(false), opd_valid_(false),
+ opd_ent_(), access_from_map_(), has14_(), stub_table_()
+ { }
+
+ ~Powerpc_relobj()
+ { }
+
+ // The .got2 section shndx.
+ unsigned int
+ got2_shndx() const
+ {
+ if (size == 32)
+ return this->special_;
+ else
+ return 0;
+ }
+
+ // The .opd section shndx.
+ unsigned int
+ opd_shndx() const
+ {
+ if (size == 32)
+ return 0;
+ else
+ return this->special_;
+ }
+
+ // Init OPD entry arrays.
+ void
+ init_opd(size_t opd_size)
+ {
+ size_t count = this->opd_ent_ndx(opd_size);
+ this->opd_ent_.resize(count);
+ }
+
+ // Return section and offset of function entry for .opd + R_OFF.
+ unsigned int
+ get_opd_ent(Address r_off, Address* value = NULL) const
+ {
+ size_t ndx = this->opd_ent_ndx(r_off);
+ gold_assert(ndx < this->opd_ent_.size());
+ gold_assert(this->opd_ent_[ndx].shndx != 0);
+ if (value != NULL)
+ *value = this->opd_ent_[ndx].off;
+ return this->opd_ent_[ndx].shndx;
+ }
+
+ // Set section and offset of function entry for .opd + R_OFF.
+ void
+ set_opd_ent(Address r_off, unsigned int shndx, Address value)
+ {
+ size_t ndx = this->opd_ent_ndx(r_off);
+ gold_assert(ndx < this->opd_ent_.size());
+ this->opd_ent_[ndx].shndx = shndx;
+ this->opd_ent_[ndx].off = value;
+ }
+
+ // Return discard flag for .opd + R_OFF.
+ bool
+ get_opd_discard(Address r_off) const
+ {
+ size_t ndx = this->opd_ent_ndx(r_off);
+ gold_assert(ndx < this->opd_ent_.size());
+ return this->opd_ent_[ndx].discard;
+ }
+
+ // Set discard flag for .opd + R_OFF.
+ void
+ set_opd_discard(Address r_off)
+ {
+ size_t ndx = this->opd_ent_ndx(r_off);
+ gold_assert(ndx < this->opd_ent_.size());
+ this->opd_ent_[ndx].discard = true;
+ }
+
+ bool
+ opd_valid() const
+ { return this->opd_valid_; }
+
+ void
+ set_opd_valid()
+ { this->opd_valid_ = true; }
+
+ // Examine .rela.opd to build info about function entry points.
+ void
+ scan_opd_relocs(size_t reloc_count,
+ const unsigned char* prelocs,
+ const unsigned char* plocal_syms);
+
+ // Perform the Sized_relobj_file method, then set up opd info from
+ // .opd relocs.
+ void
+ do_read_relocs(Read_relocs_data*);
+
+ bool
+ do_find_special_sections(Read_symbols_data* sd);
+
+ // Adjust this local symbol value. Return false if the symbol
+ // should be discarded from the output file.
+ bool
+ do_adjust_local_symbol(Symbol_value<size>* lv) const
+ {
+ if (size == 64 && this->opd_shndx() != 0)
+ {
+ bool is_ordinary;
+ if (lv->input_shndx(&is_ordinary) != this->opd_shndx())
+ return true;
+ if (this->get_opd_discard(lv->input_value()))
+ return false;
+ }
+ return true;
+ }
+
+ Access_from*
+ access_from_map()
+ { return &this->access_from_map_; }
+
+ // Add a reference from SRC_OBJ, SRC_INDX to this object's .opd
+ // section at DST_OFF.
+ void
+ add_reference(Object* src_obj,
+ unsigned int src_indx,
+ typename elfcpp::Elf_types<size>::Elf_Addr dst_off)
+ {
+ Section_id src_id(src_obj, src_indx);
+ this->access_from_map_[dst_off].insert(src_id);
+ }
+
+ // Add a reference to the code section specified by the .opd entry
+ // at DST_OFF
+ void
+ add_gc_mark(typename elfcpp::Elf_types<size>::Elf_Addr dst_off)
+ {
+ size_t ndx = this->opd_ent_ndx(dst_off);
+ if (ndx >= this->opd_ent_.size())
+ this->opd_ent_.resize(ndx + 1);
+ this->opd_ent_[ndx].gc_mark = true;
+ }
+
+ void
+ process_gc_mark(Symbol_table* symtab)
+ {
+ for (size_t i = 0; i < this->opd_ent_.size(); i++)
+ if (this->opd_ent_[i].gc_mark)
+ {
+ unsigned int shndx = this->opd_ent_[i].shndx;
+ symtab->gc()->worklist().push(Section_id(this, shndx));
+ }
+ }
+
+ // Return offset in output GOT section that this object will use
+ // as a TOC pointer. Won't be just a constant with multi-toc support.
+ Address
+ toc_base_offset() const
+ { return 0x8000; }
+
+ void
+ set_has_small_toc_reloc()
+ { has_small_toc_reloc_ = true; }
+
+ bool
+ has_small_toc_reloc() const
+ { return has_small_toc_reloc_; }
+
+ void
+ set_has_14bit_branch(unsigned int shndx)
+ {
+ if (shndx >= this->has14_.size())
+ this->has14_.resize(shndx + 1);
+ this->has14_[shndx] = true;
+ }
+
+ bool
+ has_14bit_branch(unsigned int shndx) const
+ { return shndx < this->has14_.size() && this->has14_[shndx]; }
+
+ void
+ set_stub_table(unsigned int shndx, Stub_table<size, big_endian>* stub_table)
+ {
+ if (shndx >= this->stub_table_.size())
+ this->stub_table_.resize(shndx + 1);
+ this->stub_table_[shndx] = stub_table;
+ }
+
+ Stub_table<size, big_endian>*
+ stub_table(unsigned int shndx)
+ {
+ if (shndx < this->stub_table_.size())
+ return this->stub_table_[shndx];
+ return NULL;
+ }
+
+private:
+ struct Opd_ent
+ {
+ unsigned int shndx;
+ bool discard : 1;
+ bool gc_mark : 1;
+ Address off;
+ };
+
+ // Return index into opd_ent_ array for .opd entry at OFF.
+ // .opd entries are 24 bytes long, but they can be spaced 16 bytes
+ // apart when the language doesn't use the last 8-byte word, the
+ // environment pointer. Thus dividing the entry section offset by
+ // 16 will give an index into opd_ent_ that works for either layout
+ // of .opd. (It leaves some elements of the vector unused when .opd
+ // entries are spaced 24 bytes apart, but we don't know the spacing
+ // until relocations are processed, and in any case it is possible
+ // for an object to have some entries spaced 16 bytes apart and
+ // others 24 bytes apart.)
+ size_t
+ opd_ent_ndx(size_t off) const
+ { return off >> 4;}
+
+ // For 32-bit the .got2 section shdnx, for 64-bit the .opd section shndx.
+ unsigned int special_;
+
+ // For 64-bit, whether this object uses small model relocs to access
+ // the toc.
+ bool has_small_toc_reloc_;
+
+ // Set at the start of gc_process_relocs, when we know opd_ent_
+ // vector is valid. The flag could be made atomic and set in
+ // do_read_relocs with memory_order_release and then tested with
+ // memory_order_acquire, potentially resulting in fewer entries in
+ // access_from_map_.
+ bool opd_valid_;
+
+ // The first 8-byte word of an OPD entry gives the address of the
+ // entry point of the function. Relocatable object files have a
+ // relocation on this word. The following vector records the
+ // section and offset specified by these relocations.
+ std::vector<Opd_ent> opd_ent_;
+
+ // References made to this object's .opd section when running
+ // gc_process_relocs for another object, before the opd_ent_ vector
+ // is valid for this object.
+ Access_from access_from_map_;
+
+ // Whether input section has a 14-bit branch reloc.
+ std::vector<bool> has14_;
+
+ // The stub table to use for a given input section.
+ std::vector<Stub_table<size, big_endian>*> stub_table_;
+};
+
+template<int size, bool big_endian>
+class Powerpc_dynobj : public Sized_dynobj<size, big_endian>
+{
+public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+
+ Powerpc_dynobj(const std::string& name, Input_file* input_file, off_t offset,
+ const typename elfcpp::Ehdr<size, big_endian>& ehdr)
+ : Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr),
+ opd_shndx_(0), opd_ent_()
+ { }
+
+ ~Powerpc_dynobj()
+ { }
+
+ // Call Sized_dynobj::do_read_symbols to read the symbols then
+ // read .opd from a dynamic object, filling in opd_ent_ vector,
+ void
+ do_read_symbols(Read_symbols_data*);
+
+ // The .opd section shndx.
+ unsigned int
+ opd_shndx() const
+ {
+ return this->opd_shndx_;
+ }
+
+ // The .opd section address.
+ Address
+ opd_address() const
+ {
+ return this->opd_address_;
+ }
+
+ // Init OPD entry arrays.
+ void
+ init_opd(size_t opd_size)
+ {
+ size_t count = this->opd_ent_ndx(opd_size);
+ this->opd_ent_.resize(count);
+ }
+
+ // Return section and offset of function entry for .opd + R_OFF.
+ unsigned int
+ get_opd_ent(Address r_off, Address* value = NULL) const
+ {
+ size_t ndx = this->opd_ent_ndx(r_off);
+ gold_assert(ndx < this->opd_ent_.size());
+ gold_assert(this->opd_ent_[ndx].shndx != 0);
+ if (value != NULL)
+ *value = this->opd_ent_[ndx].off;
+ return this->opd_ent_[ndx].shndx;
+ }
+
+ // Set section and offset of function entry for .opd + R_OFF.
+ void
+ set_opd_ent(Address r_off, unsigned int shndx, Address value)
+ {
+ size_t ndx = this->opd_ent_ndx(r_off);
+ gold_assert(ndx < this->opd_ent_.size());
+ this->opd_ent_[ndx].shndx = shndx;
+ this->opd_ent_[ndx].off = value;
+ }
+
+private:
+ // Used to specify extent of executable sections.
+ struct Sec_info
+ {
+ Sec_info(Address start_, Address len_, unsigned int shndx_)
+ : start(start_), len(len_), shndx(shndx_)
+ { }
+
+ bool
+ operator<(const Sec_info& that) const
+ { return this->start < that.start; }
+
+ Address start;
+ Address len;
+ unsigned int shndx;
+ };
+
+ struct Opd_ent
+ {
+ unsigned int shndx;
+ Address off;
+ };
+
+ // Return index into opd_ent_ array for .opd entry at OFF.
+ size_t
+ opd_ent_ndx(size_t off) const
+ { return off >> 4;}
+
+ // For 64-bit the .opd section shndx and address.
+ unsigned int opd_shndx_;
+ Address opd_address_;
+
+ // The first 8-byte word of an OPD entry gives the address of the
+ // entry point of the function. Records the section and offset
+ // corresponding to the address. Note that in dynamic objects,
+ // offset is *not* relative to the section.
+ std::vector<Opd_ent> opd_ent_;
+};
+
+template<int size, bool big_endian>
+class Target_powerpc : public Sized_target<size, big_endian>
+{
+ public:
+ typedef
+ Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian> Reloc_section;
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename elfcpp::Elf_types<size>::Elf_Swxword Signed_address;
+ static const Address invalid_address = static_cast<Address>(0) - 1;
+ // Offset of tp and dtp pointers from start of TLS block.
+ static const Address tp_offset = 0x7000;
+ static const Address dtp_offset = 0x8000;
+
+ Target_powerpc()
+ : Sized_target<size, big_endian>(&powerpc_info),
+ got_(NULL), plt_(NULL), iplt_(NULL), brlt_section_(NULL),
+ glink_(NULL), rela_dyn_(NULL), copy_relocs_(elfcpp::R_POWERPC_COPY),
+ tlsld_got_offset_(-1U),
+ stub_tables_(), branch_lookup_table_(), branch_info_(),
+ plt_thread_safe_(false)
+ {
+ }
+
+ // Process the relocations to determine unreferenced sections for
+ // garbage collection.
+ void
+ gc_process_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols);
+
+ // Scan the relocations to look for symbol adjustments.
+ void
+ scan_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols);
+
+ // Map input .toc section to output .got section.
+ const char*
+ do_output_section_name(const Relobj*, const char* name, size_t* plen) const
+ {
+ if (size == 64 && strcmp(name, ".toc") == 0)
+ {
+ *plen = 4;
+ return ".got";
+ }
+ return NULL;
+ }
+
+ // Provide linker defined save/restore functions.
+ void
+ define_save_restore_funcs(Layout*, Symbol_table*);
+
+ // No stubs unless a final link.
+ bool
+ do_may_relax() const
+ { return !parameters->options().relocatable(); }
+
+ bool
+ do_relax(int, const Input_objects*, Symbol_table*, Layout*, const Task*);
+
+ void
+ do_plt_fde_location(const Output_data*, unsigned char*,
+ uint64_t*, off_t*) const;
+
+ // Stash info about branches, for stub generation.
+ void
+ push_branch(Powerpc_relobj<size, big_endian>* ppc_object,
+ unsigned int data_shndx, Address r_offset,
+ unsigned int r_type, unsigned int r_sym, Address addend)
+ {
+ Branch_info info(ppc_object, data_shndx, r_offset, r_type, r_sym, addend);
+ this->branch_info_.push_back(info);
+ if (r_type == elfcpp::R_POWERPC_REL14
+ || r_type == elfcpp::R_POWERPC_REL14_BRTAKEN
+ || r_type == elfcpp::R_POWERPC_REL14_BRNTAKEN)
+ ppc_object->set_has_14bit_branch(data_shndx);
+ }
+
+ Stub_table<size, big_endian>*
+ new_stub_table();
+
+ void
+ do_define_standard_symbols(Symbol_table*, Layout*);
+
+ // 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;
+
+ // Return the PLT address to use for a local symbol.
+ uint64_t
+ do_plt_address_for_local(const Relobj*, unsigned int) const;
+
+ // Return the PLT address to use for a global symbol.
+ uint64_t
+ do_plt_address_for_global(const Symbol*) const;
+
+ // Return the offset to use for the GOT_INDX'th got entry which is
+ // for a local tls symbol specified by OBJECT, SYMNDX.
+ int64_t
+ do_tls_offset_for_local(const Relobj* object,
+ unsigned int symndx,
+ unsigned int got_indx) const;
+
+ // Return the offset to use for the GOT_INDX'th got entry which is
+ // for global tls symbol GSYM.
+ int64_t
+ do_tls_offset_for_global(Symbol* gsym, unsigned int got_indx) const;
+
+ void
+ do_function_location(Symbol_location*) const;
+
+ bool
+ do_can_check_for_function_pointers() const
+ { return true; }
+
+ // Relocate a section.
+ void
+ relocate_section(const Relocate_info<size, 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,
+ 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<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols,
+ Relocatable_relocs*);
+
+ // Emit relocations for a section.
+ void
+ relocate_relocs(const Relocate_info<size, big_endian>*,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ typename elfcpp::Elf_types<size>::Elf_Off
+ offset_in_output_section,
+ const Relocatable_relocs*,
+ unsigned char*,
+ Address view_address,
+ section_size_type,
+ unsigned char* reloc_view,
+ section_size_type reloc_view_size);
+
+ // 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 the size of the GOT section.
+ section_size_type
+ got_size() const
+ {
+ gold_assert(this->got_ != NULL);
+ return this->got_->data_size();
+ }
+
+ // Get the PLT section.
+ const Output_data_plt_powerpc<size, big_endian>*
+ plt_section() const
+ {
+ gold_assert(this->plt_ != NULL);
+ return this->plt_;
+ }
+
+ // Get the IPLT section.
+ const Output_data_plt_powerpc<size, big_endian>*
+ iplt_section() const
+ {
+ gold_assert(this->iplt_ != NULL);
+ return this->iplt_;
+ }
+
+ // Get the .glink section.
+ const Output_data_glink<size, big_endian>*
+ glink_section() const
+ {
+ gold_assert(this->glink_ != NULL);
+ return this->glink_;
+ }
+
+ bool has_glink() const
+ { return this->glink_ != NULL; }
+
+ // Get the GOT section.
+ const Output_data_got_powerpc<size, big_endian>*
+ got_section() const
+ {
+ gold_assert(this->got_ != NULL);
+ return this->got_;
+ }
+
+ // Get the GOT section, creating it if necessary.
+ Output_data_got_powerpc<size, big_endian>*
+ got_section(Symbol_table*, Layout*);
+
+ Object*
+ do_make_elf_object(const std::string&, Input_file*, off_t,
+ const elfcpp::Ehdr<size, big_endian>&);
+
+ // Return the number of entries in the GOT.
+ unsigned int
+ got_entry_count() const
+ {
+ if (this->got_ == NULL)
+ return 0;
+ return this->got_size() / (size / 8);
+ }
+
+ // 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;
+
+ // Add any special sections for this symbol to the gc work list.
+ // For powerpc64, this adds the code section of a function
+ // descriptor.
+ void
+ do_gc_mark_symbol(Symbol_table* symtab, Symbol* sym) const;
+
+ // Handle target specific gc actions when adding a gc reference from
+ // SRC_OBJ, SRC_SHNDX to a location specified by DST_OBJ, DST_SHNDX
+ // and DST_OFF. For powerpc64, this adds a referenc to the code
+ // section of a function descriptor.
+ void
+ do_gc_add_reference(Symbol_table* symtab,
+ Object* src_obj,
+ unsigned int src_shndx,
+ Object* dst_obj,
+ unsigned int dst_shndx,
+ Address dst_off) const;
+
+ typedef std::vector<Stub_table<size, big_endian>*> Stub_tables;
+ const Stub_tables&
+ stub_tables() const
+ { return this->stub_tables_; }
+
+ const Output_data_brlt_powerpc<size, big_endian>*
+ brlt_section() const
+ { return this->brlt_section_; }
+
+ void
+ add_branch_lookup_table(Address to)
+ {
+ unsigned int off = this->branch_lookup_table_.size() * (size / 8);
+ this->branch_lookup_table_.insert(std::make_pair(to, off));
+ }
+
+ Address
+ find_branch_lookup_table(Address to)
+ {
+ typename Branch_lookup_table::const_iterator p
+ = this->branch_lookup_table_.find(to);
+ return p == this->branch_lookup_table_.end() ? invalid_address : p->second;
+ }
+
+ void
+ write_branch_lookup_table(unsigned char *oview)
+ {
+ for (typename Branch_lookup_table::const_iterator p
+ = this->branch_lookup_table_.begin();
+ p != this->branch_lookup_table_.end();
+ ++p)
+ {
+ elfcpp::Swap<size, big_endian>::writeval(oview + p->second, p->first);
+ }
+ }
+
+ bool
+ plt_thread_safe() const
+ { return this->plt_thread_safe_; }
+
+ private:
+
+ class Track_tls
+ {
+ public:
+ enum Tls_get_addr
+ {
+ NOT_EXPECTED = 0,
+ EXPECTED = 1,
+ SKIP = 2,
+ NORMAL = 3
+ };
+
+ Track_tls()
+ : tls_get_addr_(NOT_EXPECTED),
+ relinfo_(NULL), relnum_(0), r_offset_(0)
+ { }
+
+ ~Track_tls()
+ {
+ if (this->tls_get_addr_ != NOT_EXPECTED)
+ this->missing();
+ }
+
+ void
+ missing(void)
+ {
+ if (this->relinfo_ != NULL)
+ gold_error_at_location(this->relinfo_, this->relnum_, this->r_offset_,
+ _("missing expected __tls_get_addr call"));
+ }
+
+ void
+ expect_tls_get_addr_call(
+ const Relocate_info<size, big_endian>* relinfo,
+ size_t relnum,
+ Address r_offset)
+ {
+ this->tls_get_addr_ = EXPECTED;
+ this->relinfo_ = relinfo;
+ this->relnum_ = relnum;
+ this->r_offset_ = r_offset;
+ }
+
+ void
+ expect_tls_get_addr_call()
+ { this->tls_get_addr_ = EXPECTED; }
+
+ void
+ skip_next_tls_get_addr_call()
+ {this->tls_get_addr_ = SKIP; }
+
+ Tls_get_addr
+ maybe_skip_tls_get_addr_call(unsigned int r_type, const Symbol* gsym)
+ {
+ bool is_tls_call = ((r_type == elfcpp::R_POWERPC_REL24
+ || r_type == elfcpp::R_PPC_PLTREL24)
+ && gsym != NULL
+ && strcmp(gsym->name(), "__tls_get_addr") == 0);
+ Tls_get_addr last_tls = this->tls_get_addr_;
+ this->tls_get_addr_ = NOT_EXPECTED;
+ if (is_tls_call && last_tls != EXPECTED)
+ return last_tls;
+ else if (!is_tls_call && last_tls != NOT_EXPECTED)
+ {
+ this->missing();
+ return EXPECTED;
+ }
+ return NORMAL;
+ }
+
+ private:
+ // What we're up to regarding calls to __tls_get_addr.
+ // On powerpc, the branch and link insn making a call to
+ // __tls_get_addr is marked with a relocation, R_PPC64_TLSGD,
+ // R_PPC64_TLSLD, R_PPC_TLSGD or R_PPC_TLSLD, in addition to the
+ // usual R_POWERPC_REL24 or R_PPC_PLTREL25 relocation on a call.
+ // The marker relocation always comes first, and has the same
+ // symbol as the reloc on the insn setting up the __tls_get_addr
+ // argument. This ties the arg setup insn with the call insn,
+ // allowing ld to safely optimize away the call. We check that
+ // every call to __tls_get_addr has a marker relocation, and that
+ // every marker relocation is on a call to __tls_get_addr.
+ Tls_get_addr tls_get_addr_;
+ // Info about the last reloc for error message.
+ const Relocate_info<size, big_endian>* relinfo_;
+ size_t relnum_;
+ Address r_offset_;
+ };
+
+ // The class which scans relocations.
+ class Scan : protected Track_tls
+ {
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+
+ Scan()
+ : Track_tls(), issued_non_pic_error_(false)
+ { }
+
+ static inline int
+ get_reference_flags(unsigned int r_type);
+
+ inline void
+ local(Symbol_table* symtab, Layout* layout, Target_powerpc* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+ const elfcpp::Sym<size, big_endian>& lsym,
+ bool is_discarded);
+
+ inline void
+ global(Symbol_table* symtab, Layout* layout, Target_powerpc* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+ Symbol* gsym);
+
+ inline bool
+ local_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
+ Target_powerpc* ,
+ Sized_relobj_file<size, big_endian>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<size, big_endian>& ,
+ unsigned int r_type,
+ const elfcpp::Sym<size, big_endian>&)
+ {
+ // PowerPC64 .opd is not folded, so any identical function text
+ // may be folded and we'll still keep function addresses distinct.
+ // That means no reloc is of concern here.
+ if (size == 64)
+ return false;
+ // For 32-bit, conservatively assume anything but calls to
+ // function code might be taking the address of the function.
+ return !is_branch_reloc(r_type);
+ }
+
+ inline bool
+ global_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
+ Target_powerpc* ,
+ Sized_relobj_file<size, big_endian>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<size, big_endian>& ,
+ unsigned int r_type,
+ Symbol*)
+ {
+ // As above.
+ if (size == 64)
+ return false;
+ return !is_branch_reloc(r_type);
+ }
+
+ static bool
+ reloc_needs_plt_for_ifunc(Sized_relobj_file<size, big_endian>* object,
+ unsigned int r_type, bool report_err);
+
+ private:
+ static void
+ unsupported_reloc_local(Sized_relobj_file<size, big_endian>*,
+ unsigned int r_type);
+
+ static void
+ unsupported_reloc_global(Sized_relobj_file<size, big_endian>*,
+ unsigned int r_type, Symbol*);
+
+ static void
+ generate_tls_call(Symbol_table* symtab, Layout* layout,
+ Target_powerpc* target);
+
+ void
+ check_non_pic(Relobj*, unsigned int r_type);
+
+ // Whether we have issued an error about a non-PIC compilation.
+ bool issued_non_pic_error_;
+ };
+
+ Address
+ symval_for_branch(const Symbol_table* symtab, Address value,
+ const Sized_symbol<size>* gsym,
+ Powerpc_relobj<size, big_endian>* object,
+ unsigned int *dest_shndx);
+
+ // The class which implements relocation.
+ class Relocate : protected Track_tls
+ {
+ public:
+ // Use 'at' branch hints when true, 'y' when false.
+ // FIXME maybe: set this with an option.
+ static const bool is_isa_v2 = true;
+
+ Relocate()
+ : Track_tls()
+ { }
+
+ // Do a relocation. Return false if the caller should not issue
+ // any warnings about this relocation.
+ inline bool
+ relocate(const Relocate_info<size, big_endian>*, Target_powerpc*,
+ Output_section*, size_t relnum,
+ const elfcpp::Rela<size, big_endian>&,
+ unsigned int r_type, const Sized_symbol<size>*,
+ const Symbol_value<size>*,
+ unsigned char*,
+ typename elfcpp::Elf_types<size>::Elf_Addr,
+ section_size_type);
+ };
+
+ class Relocate_comdat_behavior
+ {
+ public:
+ // Decide what the linker should do for relocations that refer to
+ // discarded comdat sections.
+ inline Comdat_behavior
+ get(const char* name)
+ {
+ gold::Default_comdat_behavior default_behavior;
+ Comdat_behavior ret = default_behavior.get(name);
+ if (ret == CB_WARNING)
+ {
+ if (size == 32
+ && (strcmp(name, ".fixup") == 0
+ || strcmp(name, ".got2") == 0))
+ ret = CB_IGNORE;
+ if (size == 64
+ && (strcmp(name, ".opd") == 0
+ || strcmp(name, ".toc") == 0
+ || strcmp(name, ".toc1") == 0))
+ ret = CB_IGNORE;
+ }
+ return ret;
+ }
+ };
+
+ // 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*)
+ {
+ gold_unreachable();
+ return 0;
+ }
+ };
+
+ // 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
+ optimize_tls_gd(bool is_final)
+ {
+ // If we are generating a shared library, then we can't do anything
+ // in the linker.
+ if (parameters->options().shared())
+ return tls::TLSOPT_NONE;
+
+ if (!is_final)
+ return tls::TLSOPT_TO_IE;
+ return tls::TLSOPT_TO_LE;
+ }
+
+ tls::Tls_optimization
+ optimize_tls_ld()
+ {
+ if (parameters->options().shared())
+ return tls::TLSOPT_NONE;
+
+ return tls::TLSOPT_TO_LE;
+ }
+
+ tls::Tls_optimization
+ optimize_tls_ie(bool is_final)
+ {
+ if (!is_final || parameters->options().shared())
+ return tls::TLSOPT_NONE;
+
+ return tls::TLSOPT_TO_LE;
+ }
+
+ // Create glink.
+ void
+ make_glink_section(Layout*);
+
+ // Create the PLT section.
+ void
+ make_plt_section(Symbol_table*, Layout*);
+
+ void
+ make_iplt_section(Symbol_table*, Layout*);
+
+ void
+ make_brlt_section(Layout*);
+
+ // Create a PLT entry for a global symbol.
+ void
+ make_plt_entry(Symbol_table*, Layout*, Symbol*);
+
+ // Create a PLT entry for a local IFUNC symbol.
+ void
+ make_local_ifunc_plt_entry(Symbol_table*, Layout*,
+ Sized_relobj_file<size, big_endian>*,
+ unsigned int);
+
+
+ // Create a GOT entry for local dynamic __tls_get_addr.
+ unsigned int
+ tlsld_got_offset(Symbol_table* symtab, Layout* layout,
+ Sized_relobj_file<size, big_endian>* object);
+
+ unsigned int
+ tlsld_got_offset() const
+ {
+ return this->tlsld_got_offset_;
+ }
+
+ // Get the dynamic reloc section, creating it if necessary.
+ Reloc_section*
+ rela_dyn_section(Layout*);
+
+ // Similarly, but for ifunc symbols get the one for ifunc.
+ Reloc_section*
+ rela_dyn_section(Symbol_table*, Layout*, bool for_ifunc);
+
+ // Copy a relocation against a global symbol.
+ void
+ copy_reloc(Symbol_table* symtab, Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int shndx, Output_section* output_section,
+ Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
+ {
+ this->copy_relocs_.copy_reloc(symtab, layout,
+ symtab->get_sized_symbol<size>(sym),
+ object, shndx, output_section,
+ reloc, this->rela_dyn_section(layout));
+ }
+
+ // Look over all the input sections, deciding where to place stubs.
+ void
+ group_sections(Layout*, const Task*);
+
+ // Sort output sections by address.
+ struct Sort_sections
+ {
+ bool
+ operator()(const Output_section* sec1, const Output_section* sec2)
+ { return sec1->address() < sec2->address(); }
+ };
+
+ class Branch_info
+ {
+ public:
+ Branch_info(Powerpc_relobj<size, big_endian>* ppc_object,
+ unsigned int data_shndx,
+ Address r_offset,
+ unsigned int r_type,
+ unsigned int r_sym,
+ Address addend)
+ : object_(ppc_object), shndx_(data_shndx), offset_(r_offset),
+ r_type_(r_type), r_sym_(r_sym), addend_(addend)
+ { }
+
+ ~Branch_info()
+ { }
+
+ // If this branch needs a plt call stub, or a long branch stub, make one.
+ void
+ make_stub(Stub_table<size, big_endian>*,
+ Stub_table<size, big_endian>*,
+ Symbol_table*) const;
+
+ private:
+ // The branch location..
+ Powerpc_relobj<size, big_endian>* object_;
+ unsigned int shndx_;
+ Address offset_;
+ // ..and the branch type and destination.
+ unsigned int r_type_;
+ unsigned int r_sym_;
+ Address addend_;
+ };
+
+ // Information about this specific target which we pass to the
+ // general Target structure.
+ static Target::Target_info powerpc_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,
+ GOT_TYPE_TLSGD, // double entry for @got@tlsgd
+ GOT_TYPE_DTPREL, // entry for @got@dtprel
+ GOT_TYPE_TPREL // entry for @got@tprel
+ };
+
+ // The GOT section.
+ Output_data_got_powerpc<size, big_endian>* got_;
+ // The PLT section. This is a container for a table of addresses,
+ // and their relocations. Each address in the PLT has a dynamic
+ // relocation (R_*_JMP_SLOT) and each address will have a
+ // corresponding entry in .glink for lazy resolution of the PLT.
+ // ppc32 initialises the PLT to point at the .glink entry, while
+ // ppc64 leaves this to ld.so. To make a call via the PLT, the
+ // linker adds a stub that loads the PLT entry into ctr then
+ // branches to ctr. There may be more than one stub for each PLT
+ // entry. DT_JMPREL points at the first PLT dynamic relocation and
+ // DT_PLTRELSZ gives the total size of PLT dynamic relocations.
+ Output_data_plt_powerpc<size, big_endian>* plt_;
+ // The IPLT section. Like plt_, this is a container for a table of
+ // addresses and their relocations, specifically for STT_GNU_IFUNC
+ // functions that resolve locally (STT_GNU_IFUNC functions that
+ // don't resolve locally go in PLT). Unlike plt_, these have no
+ // entry in .glink for lazy resolution, and the relocation section
+ // does not have a 1-1 correspondence with IPLT addresses. In fact,
+ // the relocation section may contain relocations against
+ // STT_GNU_IFUNC symbols at locations outside of IPLT. The
+ // relocation section will appear at the end of other dynamic
+ // relocations, so that ld.so applies these relocations after other
+ // dynamic relocations. In a static executable, the relocation
+ // section is emitted and marked with __rela_iplt_start and
+ // __rela_iplt_end symbols.
+ Output_data_plt_powerpc<size, big_endian>* iplt_;
+ // Section holding long branch destinations.
+ Output_data_brlt_powerpc<size, big_endian>* brlt_section_;
+ // The .glink section.
+ Output_data_glink<size, big_endian>* glink_;
+ // The dynamic reloc section.
+ Reloc_section* rela_dyn_;
+ // Relocs saved to avoid a COPY reloc.
+ Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
+ // Offset of the GOT entry for local dynamic __tls_get_addr calls.
+ unsigned int tlsld_got_offset_;
+
+ Stub_tables stub_tables_;
+ typedef Unordered_map<Address, unsigned int> Branch_lookup_table;
+ Branch_lookup_table branch_lookup_table_;
+
+ typedef std::vector<Branch_info> Branches;
+ Branches branch_info_;
+
+ bool plt_thread_safe_;
+};
+
+template<>
+Target::Target_info Target_powerpc<32, true>::powerpc_info =
+{
+ 32, // size
+ true, // is_big_endian
+ elfcpp::EM_PPC, // 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/ld.so.1", // dynamic_linker
+ 0x10000000, // default_text_segment_address
+ 64 * 1024, // abi_pagesize (overridable by -z max-page-size)
+ 4 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0, // large_common_section_flags
+ NULL, // attributes_section
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
+};
+
+template<>
+Target::Target_info Target_powerpc<32, false>::powerpc_info =
+{
+ 32, // size
+ false, // is_big_endian
+ elfcpp::EM_PPC, // 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/ld.so.1", // dynamic_linker
+ 0x10000000, // default_text_segment_address
+ 64 * 1024, // abi_pagesize (overridable by -z max-page-size)
+ 4 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0, // large_common_section_flags
+ NULL, // attributes_section
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
+};
+
+template<>
+Target::Target_info Target_powerpc<64, true>::powerpc_info =
+{
+ 64, // size
+ true, // is_big_endian
+ elfcpp::EM_PPC64, // 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/ld.so.1", // dynamic_linker
+ 0x10000000, // default_text_segment_address
+ 64 * 1024, // abi_pagesize (overridable by -z max-page-size)
+ 4 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0, // large_common_section_flags
+ NULL, // attributes_section
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
+};
+
+template<>
+Target::Target_info Target_powerpc<64, false>::powerpc_info =
+{
+ 64, // size
+ false, // is_big_endian
+ elfcpp::EM_PPC64, // 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/ld.so.1", // dynamic_linker
+ 0x10000000, // default_text_segment_address
+ 64 * 1024, // abi_pagesize (overridable by -z max-page-size)
+ 4 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0, // large_common_section_flags
+ NULL, // attributes_section
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
+};
+
+inline bool
+is_branch_reloc(unsigned int r_type)
+{
+ return (r_type == elfcpp::R_POWERPC_REL24
+ || r_type == elfcpp::R_PPC_PLTREL24
+ || r_type == elfcpp::R_PPC_LOCAL24PC
+ || r_type == elfcpp::R_POWERPC_REL14
+ || r_type == elfcpp::R_POWERPC_REL14_BRTAKEN
+ || r_type == elfcpp::R_POWERPC_REL14_BRNTAKEN
+ || r_type == elfcpp::R_POWERPC_ADDR24
+ || r_type == elfcpp::R_POWERPC_ADDR14
+ || r_type == elfcpp::R_POWERPC_ADDR14_BRTAKEN
+ || r_type == elfcpp::R_POWERPC_ADDR14_BRNTAKEN);
+}
+
+// If INSN is an opcode that may be used with an @tls operand, return
+// the transformed insn for TLS optimisation, otherwise return 0. If
+// REG is non-zero only match an insn with RB or RA equal to REG.
+uint32_t
+at_tls_transform(uint32_t insn, unsigned int reg)
+{
+ if ((insn & (0x3f << 26)) != 31 << 26)
+ return 0;
+
+ unsigned int rtra;
+ if (reg == 0 || ((insn >> 11) & 0x1f) == reg)
+ rtra = insn & ((1 << 26) - (1 << 16));
+ else if (((insn >> 16) & 0x1f) == reg)
+ rtra = (insn & (0x1f << 21)) | ((insn & (0x1f << 11)) << 5);
+ else
+ return 0;
+
+ if ((insn & (0x3ff << 1)) == 266 << 1)
+ // add -> addi
+ insn = 14 << 26;
+ else if ((insn & (0x1f << 1)) == 23 << 1
+ && ((insn & (0x1f << 6)) < 14 << 6
+ || ((insn & (0x1f << 6)) >= 16 << 6
+ && (insn & (0x1f << 6)) < 24 << 6)))
+ // load and store indexed -> dform
+ insn = (32 | ((insn >> 6) & 0x1f)) << 26;
+ else if ((insn & (((0x1a << 5) | 0x1f) << 1)) == 21 << 1)
+ // ldx, ldux, stdx, stdux -> ld, ldu, std, stdu
+ insn = ((58 | ((insn >> 6) & 4)) << 26) | ((insn >> 6) & 1);
+ else if ((insn & (((0x1f << 5) | 0x1f) << 1)) == 341 << 1)
+ // lwax -> lwa
+ insn = (58 << 26) | 2;
+ else
+ return 0;
+ insn |= rtra;
+ return insn;
+}
+
+// Modified version of symtab.h class Symbol member
+// Given a direct absolute or pc-relative static relocation against
+// the global symbol, this function returns whether a dynamic relocation
+// is needed.
+
+template<int size>
+bool
+needs_dynamic_reloc(const Symbol* gsym, int flags)
+{
+ // No dynamic relocations in a static link!
+ if (parameters->doing_static_link())
+ return false;
+
+ // A reference to an undefined symbol from an executable should be
+ // statically resolved to 0, and does not need a dynamic relocation.
+ // This matches gnu ld behavior.
+ if (gsym->is_undefined() && !parameters->options().shared())
+ return false;
+
+ // A reference to an absolute symbol does not need a dynamic relocation.
+ if (gsym->is_absolute())
+ return false;
+
+ // An absolute reference within a position-independent output file
+ // will need a dynamic relocation.
+ if ((flags & Symbol::ABSOLUTE_REF)
+ && parameters->options().output_is_position_independent())
+ return true;
+
+ // A function call that can branch to a local PLT entry does not need
+ // a dynamic relocation.
+ if ((flags & Symbol::FUNCTION_CALL) && gsym->has_plt_offset())
+ return false;
+
+ // A reference to any PLT entry in a non-position-independent executable
+ // does not need a dynamic relocation.
+ // Except due to having function descriptors on powerpc64 we don't define
+ // functions to their plt code in an executable, so this doesn't apply.
+ if (size == 32
+ && !parameters->options().output_is_position_independent()
+ && gsym->has_plt_offset())
+ return false;
+
+ // A reference to a symbol defined in a dynamic object or to a
+ // symbol that is preemptible will need a dynamic relocation.
+ if (gsym->is_from_dynobj()
+ || gsym->is_undefined()
+ || gsym->is_preemptible())
+ return true;
+
+ // For all other cases, return FALSE.
+ return false;
+}
+
+// Modified version of symtab.h class Symbol member
+// Whether we should use the PLT offset associated with a symbol for
+// a relocation. FLAGS is a set of Reference_flags.
+
+template<int size>
+bool
+use_plt_offset(const Symbol* gsym, int flags)
+{
+ // If the symbol doesn't have a PLT offset, then naturally we
+ // don't want to use it.
+ if (!gsym->has_plt_offset())
+ return false;
+
+ // For a STT_GNU_IFUNC symbol we always have to use the PLT entry.
+ if (gsym->type() == elfcpp::STT_GNU_IFUNC)
+ return true;
+
+ // If we are going to generate a dynamic relocation, then we will
+ // wind up using that, so no need to use the PLT entry.
+ if (needs_dynamic_reloc<size>(gsym, flags))
+ return false;
+
+ // If the symbol is from a dynamic object, we need to use the PLT
+ // entry.
+ if (gsym->is_from_dynobj())
+ return true;
+
+ // If we are generating a shared object, and this symbol is
+ // undefined or preemptible, we need to use the PLT entry.
+ if (parameters->options().shared()
+ && (gsym->is_undefined() || gsym->is_preemptible()))
+ return true;
+
+ // If this is a call to a weak undefined symbol, we need to use
+ // the PLT entry; the symbol may be defined by a library loaded
+ // at runtime.
+ if ((flags & Symbol::FUNCTION_CALL) && gsym->is_weak_undefined())
+ return true;
+
+ // Otherwise we can use the regular definition.
+ return false;
+}
+
+template<int size, bool big_endian>
+class Powerpc_relocate_functions
+{
+public:
+ enum Overflow_check
+ {
+ CHECK_NONE,
+ CHECK_SIGNED,
+ CHECK_BITFIELD
+ };
+
+ enum Status
+ {
+ STATUS_OK,
+ STATUS_OVERFLOW
+ };
+
+private:
+ typedef Powerpc_relocate_functions<size, big_endian> This;
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+
+ template<int valsize>
+ static inline bool
+ has_overflow_signed(Address value)
+ {
+ // limit = 1 << (valsize - 1) without shift count exceeding size of type
+ Address limit = static_cast<Address>(1) << ((valsize - 1) >> 1);
+ limit <<= ((valsize - 1) >> 1);
+ limit <<= ((valsize - 1) - 2 * ((valsize - 1) >> 1));
+ return value + limit > (limit << 1) - 1;
+ }
+
+ template<int valsize>
+ static inline bool
+ has_overflow_bitfield(Address value)
+ {
+ Address limit = static_cast<Address>(1) << ((valsize - 1) >> 1);
+ limit <<= ((valsize - 1) >> 1);
+ limit <<= ((valsize - 1) - 2 * ((valsize - 1) >> 1));
+ return value > (limit << 1) - 1 && value + limit > (limit << 1) - 1;
+ }
+
+ template<int valsize>
+ static inline Status
+ overflowed(Address value, Overflow_check overflow)
+ {
+ if (overflow == CHECK_SIGNED)
+ {
+ if (has_overflow_signed<valsize>(value))
+ return STATUS_OVERFLOW;
+ }
+ else if (overflow == CHECK_BITFIELD)
+ {
+ if (has_overflow_bitfield<valsize>(value))
+ return STATUS_OVERFLOW;
+ }
+ return STATUS_OK;
+ }
+
+ // Do a simple RELA relocation
+ template<int valsize>
+ static inline Status
+ rela(unsigned char* view, Address value, Overflow_check overflow)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, value);
+ return overflowed<valsize>(value, overflow);
+ }
+
+ template<int valsize>
+ static inline Status
+ rela(unsigned char* view,
+ unsigned int right_shift,
+ typename elfcpp::Valtype_base<valsize>::Valtype dst_mask,
+ Address value,
+ Overflow_check overflow)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ Valtype reloc = value >> right_shift;
+ val &= ~dst_mask;
+ reloc &= dst_mask;
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
+ return overflowed<valsize>(value >> right_shift, overflow);
+ }
+
+ // Do a simple RELA relocation, unaligned.
+ template<int valsize>
+ static inline Status
+ rela_ua(unsigned char* view, Address value, Overflow_check overflow)
+ {
+ elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view, value);
+ return overflowed<valsize>(value, overflow);
+ }
+
+ template<int valsize>
+ static inline Status
+ rela_ua(unsigned char* view,
+ unsigned int right_shift,
+ typename elfcpp::Valtype_base<valsize>::Valtype dst_mask,
+ Address value,
+ Overflow_check overflow)
+ {
+ typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
+ Valtype;
+ Valtype val = elfcpp::Swap<valsize, big_endian>::readval(view);
+ Valtype reloc = value >> right_shift;
+ val &= ~dst_mask;
+ reloc &= dst_mask;
+ elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view, val | reloc);
+ return overflowed<valsize>(value >> right_shift, overflow);
+ }
+
+public:
+ // R_PPC64_ADDR64: (Symbol + Addend)
+ static inline void
+ addr64(unsigned char* view, Address value)
+ { This::template rela<64>(view, value, CHECK_NONE); }
+
+ // R_PPC64_UADDR64: (Symbol + Addend) unaligned
+ static inline void
+ addr64_u(unsigned char* view, Address value)
+ { This::template rela_ua<64>(view, value, CHECK_NONE); }
+
+ // R_POWERPC_ADDR32: (Symbol + Addend)
+ static inline Status
+ addr32(unsigned char* view, Address value, Overflow_check overflow)
+ { return This::template rela<32>(view, value, overflow); }
+
+ // R_POWERPC_UADDR32: (Symbol + Addend) unaligned
+ static inline Status
+ addr32_u(unsigned char* view, Address value, Overflow_check overflow)
+ { return This::template rela_ua<32>(view, value, overflow); }
+
+ // R_POWERPC_ADDR24: (Symbol + Addend) & 0x3fffffc
+ static inline Status
+ addr24(unsigned char* view, Address value, Overflow_check overflow)
+ {
+ Status stat = This::template rela<32>(view, 0, 0x03fffffc, value, overflow);
+ if (overflow != CHECK_NONE && (value & 3) != 0)
+ stat = STATUS_OVERFLOW;
+ return stat;
+ }
+
+ // R_POWERPC_ADDR16: (Symbol + Addend) & 0xffff
+ static inline Status
+ addr16(unsigned char* view, Address value, Overflow_check overflow)
+ { return This::template rela<16>(view, value, overflow); }
+
+ // R_POWERPC_ADDR16: (Symbol + Addend) & 0xffff, unaligned
+ static inline Status
+ addr16_u(unsigned char* view, Address value, Overflow_check overflow)
+ { return This::template rela_ua<16>(view, value, overflow); }
+
+ // R_POWERPC_ADDR16_DS: (Symbol + Addend) & 0xfffc
+ static inline Status
+ addr16_ds(unsigned char* view, Address value, Overflow_check overflow)
+ {
+ Status stat = This::template rela<16>(view, 0, 0xfffc, value, overflow);
+ if (overflow != CHECK_NONE && (value & 3) != 0)
+ stat = STATUS_OVERFLOW;
+ return stat;
+ }
+
+ // R_POWERPC_ADDR16_HI: ((Symbol + Addend) >> 16) & 0xffff
+ static inline void
+ addr16_hi(unsigned char* view, Address value)
+ { This::template rela<16>(view, 16, 0xffff, value, CHECK_NONE); }
+
+ // R_POWERPC_ADDR16_HA: ((Symbol + Addend + 0x8000) >> 16) & 0xffff
+ static inline void
+ addr16_ha(unsigned char* view, Address value)
+ { This::addr16_hi(view, value + 0x8000); }
+
+ // R_POWERPC_ADDR16_HIGHER: ((Symbol + Addend) >> 32) & 0xffff
+ static inline void
+ addr16_hi2(unsigned char* view, Address value)
+ { This::template rela<16>(view, 32, 0xffff, value, CHECK_NONE); }
+
+ // R_POWERPC_ADDR16_HIGHERA: ((Symbol + Addend + 0x8000) >> 32) & 0xffff
+ static inline void
+ addr16_ha2(unsigned char* view, Address value)
+ { This::addr16_hi2(view, value + 0x8000); }
+
+ // R_POWERPC_ADDR16_HIGHEST: ((Symbol + Addend) >> 48) & 0xffff
+ static inline void
+ addr16_hi3(unsigned char* view, Address value)
+ { This::template rela<16>(view, 48, 0xffff, value, CHECK_NONE); }
+
+ // R_POWERPC_ADDR16_HIGHESTA: ((Symbol + Addend + 0x8000) >> 48) & 0xffff
+ static inline void
+ addr16_ha3(unsigned char* view, Address value)
+ { This::addr16_hi3(view, value + 0x8000); }
+
+ // R_POWERPC_ADDR14: (Symbol + Addend) & 0xfffc
+ static inline Status
+ addr14(unsigned char* view, Address value, Overflow_check overflow)
+ {
+ Status stat = This::template rela<32>(view, 0, 0xfffc, value, overflow);
+ if (overflow != CHECK_NONE && (value & 3) != 0)
+ stat = STATUS_OVERFLOW;
+ return stat;
+ }
+};
+
+// Stash away the index of .got2 or .opd in a relocatable object, if
+// such a section exists.
+
+template<int size, bool big_endian>
+bool
+Powerpc_relobj<size, big_endian>::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<const char*>(namesu);
+ section_size_type names_size = sd->section_names_size;
+ const unsigned char* s;
+
+ s = this->template find_shdr<size, big_endian>(pshdrs,
+ size == 32 ? ".got2" : ".opd",
+ names, names_size, NULL);
+ if (s != NULL)
+ {
+ unsigned int ndx = (s - pshdrs) / elfcpp::Elf_sizes<size>::shdr_size;
+ this->special_ = ndx;
+ }
+ return Sized_relobj_file<size, big_endian>::do_find_special_sections(sd);
+}
+
+// Examine .rela.opd to build info about function entry points.
+
+template<int size, bool big_endian>
+void
+Powerpc_relobj<size, big_endian>::scan_opd_relocs(
+ size_t reloc_count,
+ const unsigned char* prelocs,
+ const unsigned char* plocal_syms)
+{
+ if (size == 64)
+ {
+ typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
+ Reltype;
+ const int reloc_size
+ = Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ Address expected_off = 0;
+ bool regular = true;
+ unsigned int opd_ent_size = 0;
+
+ for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+ Reltype reloc(prelocs);
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info
+ = reloc.get_r_info();
+ unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+ if (r_type == elfcpp::R_PPC64_ADDR64)
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ typename elfcpp::Elf_types<size>::Elf_Addr value;
+ bool is_ordinary;
+ unsigned int shndx;
+ if (r_sym < this->local_symbol_count())
+ {
+ typename elfcpp::Sym<size, big_endian>
+ lsym(plocal_syms + r_sym * sym_size);
+ shndx = lsym.get_st_shndx();
+ shndx = this->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+ value = lsym.get_st_value();
+ }
+ else
+ shndx = this->symbol_section_and_value(r_sym, &value,
+ &is_ordinary);
+ this->set_opd_ent(reloc.get_r_offset(), shndx,
+ value + reloc.get_r_addend());
+ if (i == 2)
+ {
+ expected_off = reloc.get_r_offset();
+ opd_ent_size = expected_off;
+ }
+ else if (expected_off != reloc.get_r_offset())
+ regular = false;
+ expected_off += opd_ent_size;
+ }
+ else if (r_type == elfcpp::R_PPC64_TOC)
+ {
+ if (expected_off - opd_ent_size + 8 != reloc.get_r_offset())
+ regular = false;
+ }
+ else
+ {
+ gold_warning(_("%s: unexpected reloc type %u in .opd section"),
+ this->name().c_str(), r_type);
+ regular = false;
+ }
+ }
+ if (reloc_count <= 2)
+ opd_ent_size = this->section_size(this->opd_shndx());
+ if (opd_ent_size != 24 && opd_ent_size != 16)
+ regular = false;
+ if (!regular)
+ {
+ gold_warning(_("%s: .opd is not a regular array of opd entries"),
+ this->name().c_str());
+ opd_ent_size = 0;
+ }
+ }
+}
+
+template<int size, bool big_endian>
+void
+Powerpc_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
+{
+ Sized_relobj_file<size, big_endian>::do_read_relocs(rd);
+ if (size == 64)
+ {
+ for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
+ p != rd->relocs.end();
+ ++p)
+ {
+ if (p->data_shndx == this->opd_shndx())
+ {
+ uint64_t opd_size = this->section_size(this->opd_shndx());
+ gold_assert(opd_size == static_cast<size_t>(opd_size));
+ if (opd_size != 0)
+ {
+ this->init_opd(opd_size);
+ this->scan_opd_relocs(p->reloc_count, p->contents->data(),
+ rd->local_symbols->data());
+ }
+ break;
+ }
+ }
+ }
+}
+
+// Call Sized_dynobj::do_read_symbols to read the symbols then
+// read .opd from a dynamic object, filling in opd_ent_ vector,
+
+template<int size, bool big_endian>
+void
+Powerpc_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
+{
+ Sized_dynobj<size, big_endian>::do_read_symbols(sd);
+ if (size == 64)
+ {
+ const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+ const unsigned char* const pshdrs = sd->section_headers->data();
+ const unsigned char* namesu = sd->section_names->data();
+ const char* names = reinterpret_cast<const char*>(namesu);
+ const unsigned char* s = NULL;
+ const unsigned char* opd;
+ section_size_type opd_size;
+
+ // Find and read .opd section.
+ while (1)
+ {
+ s = this->template find_shdr<size, big_endian>(pshdrs, ".opd", names,
+ sd->section_names_size,
+ s);
+ if (s == NULL)
+ return;
+
+ typename elfcpp::Shdr<size, big_endian> shdr(s);
+ if (shdr.get_sh_type() == elfcpp::SHT_PROGBITS
+ && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0)
+ {
+ this->opd_shndx_ = (s - pshdrs) / shdr_size;
+ this->opd_address_ = shdr.get_sh_addr();
+ opd_size = convert_to_section_size_type(shdr.get_sh_size());
+ opd = this->get_view(shdr.get_sh_offset(), opd_size,
+ true, false);
+ break;
+ }
+ }
+
+ // Build set of executable sections.
+ // Using a set is probably overkill. There is likely to be only
+ // a few executable sections, typically .init, .text and .fini,
+ // and they are generally grouped together.
+ typedef std::set<Sec_info> Exec_sections;
+ Exec_sections exec_sections;
+ s = pshdrs;
+ for (unsigned int i = 1; i < this->shnum(); ++i, s += shdr_size)
+ {
+ typename elfcpp::Shdr<size, big_endian> shdr(s);
+ if (shdr.get_sh_type() == elfcpp::SHT_PROGBITS
+ && ((shdr.get_sh_flags()
+ & (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR))
+ == (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR))
+ && shdr.get_sh_size() != 0)
+ {
+ exec_sections.insert(Sec_info(shdr.get_sh_addr(),
+ shdr.get_sh_size(), i));
+ }
+ }
+ if (exec_sections.empty())
+ return;
+
+ // Look over the OPD entries. This is complicated by the fact
+ // that some binaries will use two-word entries while others
+ // will use the standard three-word entries. In most cases
+ // the third word (the environment pointer for languages like
+ // Pascal) is unused and will be zero. If the third word is
+ // used it should not be pointing into executable sections,
+ // I think.
+ this->init_opd(opd_size);
+ for (const unsigned char* p = opd; p < opd + opd_size; p += 8)
+ {
+ typedef typename elfcpp::Swap<64, big_endian>::Valtype Valtype;
+ const Valtype* valp = reinterpret_cast<const Valtype*>(p);
+ Valtype val = elfcpp::Swap<64, big_endian>::readval(valp);
+ if (val == 0)
+ // Chances are that this is the third word of an OPD entry.
+ continue;
+ typename Exec_sections::const_iterator e
+ = exec_sections.upper_bound(Sec_info(val, 0, 0));
+ if (e != exec_sections.begin())
+ {
+ --e;
+ if (e->start <= val && val < e->start + e->len)
+ {
+ // We have an address in an executable section.
+ // VAL ought to be the function entry, set it up.
+ this->set_opd_ent(p - opd, e->shndx, val);
+ // Skip second word of OPD entry, the TOC pointer.
+ p += 8;
+ }
+ }
+ // If we didn't match any executable sections, we likely
+ // have a non-zero third word in the OPD entry.
+ }
+ }
+}
+
+// Set up some symbols.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::do_define_standard_symbols(
+ Symbol_table* symtab,
+ Layout* layout)
+{
+ if (size == 32)
+ {
+ // Define _GLOBAL_OFFSET_TABLE_ to ensure it isn't seen as
+ // undefined when scanning relocs (and thus requires
+ // non-relative dynamic relocs). The proper value will be
+ // updated later.
+ Symbol *gotsym = symtab->lookup("_GLOBAL_OFFSET_TABLE_", NULL);
+ if (gotsym != NULL && gotsym->is_undefined())
+ {
+ Target_powerpc<size, big_endian>* target =
+ static_cast<Target_powerpc<size, big_endian>*>(
+ parameters->sized_target<size, big_endian>());
+ Output_data_got_powerpc<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
+ Symbol_table::PREDEFINED,
+ got, 0, 0,
+ elfcpp::STT_OBJECT,
+ elfcpp::STB_LOCAL,
+ elfcpp::STV_HIDDEN, 0,
+ false, false);
+ }
+
+ // Define _SDA_BASE_ at the start of the .sdata section + 32768.
+ Symbol *sdasym = symtab->lookup("_SDA_BASE_", NULL);
+ if (sdasym != NULL && sdasym->is_undefined())
+ {
+ Output_data_space* sdata = new Output_data_space(4, "** sdata");
+ Output_section* os
+ = layout->add_output_section_data(".sdata", 0,
+ elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE,
+ sdata, ORDER_SMALL_DATA, false);
+ symtab->define_in_output_data("_SDA_BASE_", NULL,
+ Symbol_table::PREDEFINED,
+ os, 32768, 0, elfcpp::STT_OBJECT,
+ elfcpp::STB_LOCAL, elfcpp::STV_HIDDEN,
+ 0, false, false);
+ }
+ }
+}
+
+// Set up PowerPC target specific relobj.
+
+template<int size, bool big_endian>
+Object*
+Target_powerpc<size, big_endian>::do_make_elf_object(
+ const std::string& name,
+ Input_file* input_file,
+ off_t offset, const elfcpp::Ehdr<size, 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()))
+ {
+ Powerpc_relobj<size, big_endian>* obj =
+ new Powerpc_relobj<size, big_endian>(name, input_file, offset, ehdr);
+ obj->setup();
+ return obj;
+ }
+ else if (et == elfcpp::ET_DYN)
+ {
+ Powerpc_dynobj<size, big_endian>* obj =
+ new Powerpc_dynobj<size, big_endian>(name, input_file, offset, ehdr);
+ obj->setup();
+ return obj;
+ }
+ else
+ {
+ gold_error(_("%s: unsupported ELF file type %d"), name.c_str(), et);
+ return NULL;
+ }
+}
+
+template<int size, bool big_endian>
+class Output_data_got_powerpc : public Output_data_got<size, big_endian>
+{
+public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
+ typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian> Rela_dyn;
+
+ Output_data_got_powerpc(Symbol_table* symtab, Layout* layout)
+ : Output_data_got<size, big_endian>(),
+ symtab_(symtab), layout_(layout),
+ header_ent_cnt_(size == 32 ? 3 : 1),
+ header_index_(size == 32 ? 0x2000 : 0)
+ { }
+
+ // Override all the Output_data_got methods we use so as to first call
+ // reserve_ent().
+ bool
+ add_global(Symbol* gsym, unsigned int got_type)
+ {
+ this->reserve_ent();
+ return Output_data_got<size, big_endian>::add_global(gsym, got_type);
+ }
+
+ bool
+ add_global_plt(Symbol* gsym, unsigned int got_type)
+ {
+ this->reserve_ent();
+ return Output_data_got<size, big_endian>::add_global_plt(gsym, got_type);
+ }
+
+ bool
+ add_global_tls(Symbol* gsym, unsigned int got_type)
+ { return this->add_global_plt(gsym, got_type); }
+
+ void
+ add_global_with_rel(Symbol* gsym, unsigned int got_type,
+ Output_data_reloc_generic* rel_dyn, unsigned int r_type)
+ {
+ this->reserve_ent();
+ Output_data_got<size, big_endian>::
+ add_global_with_rel(gsym, got_type, rel_dyn, r_type);
+ }
+
+ void
+ add_global_pair_with_rel(Symbol* gsym, unsigned int got_type,
+ Output_data_reloc_generic* rel_dyn,
+ unsigned int r_type_1, unsigned int r_type_2)
+ {
+ this->reserve_ent(2);
+ Output_data_got<size, big_endian>::
+ add_global_pair_with_rel(gsym, got_type, rel_dyn, r_type_1, r_type_2);
+ }
+
+ bool
+ add_local(Relobj* object, unsigned int sym_index, unsigned int got_type)
+ {
+ this->reserve_ent();
+ return Output_data_got<size, big_endian>::add_local(object, sym_index,
+ got_type);
+ }
+
+ bool
+ add_local_plt(Relobj* object, unsigned int sym_index, unsigned int got_type)
+ {
+ this->reserve_ent();
+ return Output_data_got<size, big_endian>::add_local_plt(object, sym_index,
+ got_type);
+ }
+
+ bool
+ add_local_tls(Relobj* object, unsigned int sym_index, unsigned int got_type)
+ { return this->add_local_plt(object, sym_index, got_type); }
+
+ void
+ add_local_tls_pair(Relobj* object, unsigned int sym_index,
+ unsigned int got_type,
+ Output_data_reloc_generic* rel_dyn,
+ unsigned int r_type)
+ {
+ this->reserve_ent(2);
+ Output_data_got<size, big_endian>::
+ add_local_tls_pair(object, sym_index, got_type, rel_dyn, r_type);
+ }
+
+ unsigned int
+ add_constant(Valtype constant)
+ {
+ this->reserve_ent();
+ return Output_data_got<size, big_endian>::add_constant(constant);
+ }
+
+ unsigned int
+ add_constant_pair(Valtype c1, Valtype c2)
+ {
+ this->reserve_ent(2);
+ return Output_data_got<size, big_endian>::add_constant_pair(c1, c2);
+ }
+
+ // Offset of _GLOBAL_OFFSET_TABLE_.
+ unsigned int
+ g_o_t() const
+ {
+ return this->got_offset(this->header_index_);
+ }
+
+ // Offset of base used to access the GOT/TOC.
+ // The got/toc pointer reg will be set to this value.
+ Valtype
+ got_base_offset(const Powerpc_relobj<size, big_endian>* object) const
+ {
+ if (size == 32)
+ return this->g_o_t();
+ else
+ return (this->output_section()->address()
+ + object->toc_base_offset()
+ - this->address());
+ }
+
+ // Ensure our GOT has a header.
+ void
+ set_final_data_size()
+ {
+ if (this->header_ent_cnt_ != 0)
+ this->make_header();
+ Output_data_got<size, big_endian>::set_final_data_size();
+ }
+
+ // First word of GOT header needs some values that are not
+ // handled by Output_data_got so poke them in here.
+ // For 32-bit, address of .dynamic, for 64-bit, address of TOCbase.
+ void
+ do_write(Output_file* of)
+ {
+ Valtype val = 0;
+ if (size == 32 && this->layout_->dynamic_data() != NULL)
+ val = this->layout_->dynamic_section()->address();
+ if (size == 64)
+ val = this->output_section()->address() + 0x8000;
+ this->replace_constant(this->header_index_, val);
+ Output_data_got<size, big_endian>::do_write(of);
+ }
+
+private:
+ void
+ reserve_ent(unsigned int cnt = 1)
+ {
+ if (this->header_ent_cnt_ == 0)
+ return;
+ if (this->num_entries() + cnt > this->header_index_)
+ this->make_header();
+ }
+
+ void
+ make_header()
+ {
+ this->header_ent_cnt_ = 0;
+ this->header_index_ = this->num_entries();
+ if (size == 32)
+ {
+ Output_data_got<size, big_endian>::add_constant(0);
+ Output_data_got<size, big_endian>::add_constant(0);
+ Output_data_got<size, big_endian>::add_constant(0);
+
+ // Define _GLOBAL_OFFSET_TABLE_ at the header
+ Symbol *gotsym = this->symtab_->lookup("_GLOBAL_OFFSET_TABLE_", NULL);
+ if (gotsym != NULL)
+ {
+ Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(gotsym);
+ sym->set_value(this->g_o_t());
+ }
+ else
+ this->symtab_->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
+ Symbol_table::PREDEFINED,
+ this, this->g_o_t(), 0,
+ elfcpp::STT_OBJECT,
+ elfcpp::STB_LOCAL,
+ elfcpp::STV_HIDDEN, 0,
+ false, false);
+ }
+ else
+ Output_data_got<size, big_endian>::add_constant(0);
+ }
+
+ // Stashed pointers.
+ Symbol_table* symtab_;
+ Layout* layout_;
+
+ // GOT header size.
+ unsigned int header_ent_cnt_;
+ // GOT header index.
+ unsigned int header_index_;
+};
+
+// Get the GOT section, creating it if necessary.
+
+template<int size, bool big_endian>
+Output_data_got_powerpc<size, big_endian>*
+Target_powerpc<size, big_endian>::got_section(Symbol_table* symtab,
+ Layout* layout)
+{
+ if (this->got_ == NULL)
+ {
+ gold_assert(symtab != NULL && layout != NULL);
+
+ this->got_
+ = new Output_data_got_powerpc<size, big_endian>(symtab, layout);
+
+ layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+ this->got_, ORDER_DATA, false);
+ }
+
+ return this->got_;
+}
+
+// Get the dynamic reloc section, creating it if necessary.
+
+template<int size, bool big_endian>
+typename Target_powerpc<size, big_endian>::Reloc_section*
+Target_powerpc<size, big_endian>::rela_dyn_section(Layout* layout)
+{
+ if (this->rela_dyn_ == NULL)
+ {
+ gold_assert(layout != NULL);
+ this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
+ layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
+ elfcpp::SHF_ALLOC, this->rela_dyn_,
+ ORDER_DYNAMIC_RELOCS, false);
+ }
+ return this->rela_dyn_;
+}
+
+// Similarly, but for ifunc symbols get the one for ifunc.
+
+template<int size, bool big_endian>
+typename Target_powerpc<size, big_endian>::Reloc_section*
+Target_powerpc<size, big_endian>::rela_dyn_section(Symbol_table* symtab,
+ Layout* layout,
+ bool for_ifunc)
+{
+ if (!for_ifunc)
+ return this->rela_dyn_section(layout);
+
+ if (this->iplt_ == NULL)
+ this->make_iplt_section(symtab, layout);
+ return this->iplt_->rel_plt();
+}
+
+class Stub_control
+{
+ public:
+ // 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 before
+ // the stubbed branches.
+ Stub_control(int32_t size)
+ : state_(NO_GROUP), stub_group_size_(abs(size)),
+ stub14_group_size_(abs(size)),
+ stubs_always_before_branch_(size < 0), suppress_size_errors_(false),
+ group_end_addr_(0), owner_(NULL), output_section_(NULL)
+ {
+ if (stub_group_size_ == 1)
+ {
+ // Default values.
+ if (stubs_always_before_branch_)
+ {
+ stub_group_size_ = 0x1e00000;
+ stub14_group_size_ = 0x7800;
+ }
+ else
+ {
+ stub_group_size_ = 0x1c00000;
+ stub14_group_size_ = 0x7000;
+ }
+ suppress_size_errors_ = true;
+ }
+ }
+
+ // Return true iff input section can be handled by current stub
+ // group.
+ bool
+ can_add_to_stub_group(Output_section* o,
+ const Output_section::Input_section* i,
+ bool has14);
+
+ const Output_section::Input_section*
+ owner()
+ { return owner_; }
+
+ Output_section*
+ output_section()
+ { return output_section_; }
+
+ private:
+ typedef enum
+ {
+ NO_GROUP,
+ FINDING_STUB_SECTION,
+ HAS_STUB_SECTION
+ } State;
+
+ State state_;
+ uint32_t stub_group_size_;
+ uint32_t stub14_group_size_;
+ bool stubs_always_before_branch_;
+ bool suppress_size_errors_;
+ uint64_t group_end_addr_;
+ const Output_section::Input_section* owner_;
+ Output_section* output_section_;
+};
+
+// Return true iff input section can be handled by current stub
+// group.
+
+bool
+Stub_control::can_add_to_stub_group(Output_section* o,
+ const Output_section::Input_section* i,
+ bool has14)
+{
+ uint32_t group_size
+ = has14 ? this->stub14_group_size_ : this->stub_group_size_;
+ bool whole_sec = o->order() == ORDER_INIT || o->order() == ORDER_FINI;
+ uint64_t this_size;
+ uint64_t start_addr = o->address();
+
+ if (whole_sec)
+ // .init and .fini sections are pasted together to form a single
+ // function. We can't be adding stubs in the middle of the function.
+ this_size = o->data_size();
+ else
+ {
+ start_addr += i->relobj()->output_section_offset(i->shndx());
+ this_size = i->data_size();
+ }
+ uint64_t end_addr = start_addr + this_size;
+ bool toobig = this_size > group_size;
+
+ if (toobig && !this->suppress_size_errors_)
+ gold_warning(_("%s:%s exceeds group size"),
+ i->relobj()->name().c_str(),
+ i->relobj()->section_name(i->shndx()).c_str());
+
+ if (this->state_ != HAS_STUB_SECTION
+ && (!whole_sec || this->output_section_ != o)
+ && (this->state_ == NO_GROUP
+ || this->group_end_addr_ - end_addr < group_size))
+ {
+ this->owner_ = i;
+ this->output_section_ = o;
+ }
+
+ if (this->state_ == NO_GROUP)
+ {
+ this->state_ = FINDING_STUB_SECTION;
+ this->group_end_addr_ = end_addr;
+ }
+ else if (this->group_end_addr_ - start_addr < group_size)
+ ;
+ // Adding this section would make the group larger than GROUP_SIZE.
+ else if (this->state_ == FINDING_STUB_SECTION
+ && !this->stubs_always_before_branch_
+ && !toobig)
+ {
+ // But wait, there's more! Input sections up to GROUP_SIZE
+ // bytes before the stub table can be handled by it too.
+ this->state_ = HAS_STUB_SECTION;
+ this->group_end_addr_ = end_addr;
+ }
+ else
+ {
+ this->state_ = NO_GROUP;
+ return false;
+ }
+ return true;
+}
+
+// Look over all the input sections, deciding where to place stubs.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::group_sections(Layout* layout,
+ const Task*)
+{
+ Stub_control stub_control(parameters->options().stub_group_size());
+
+ // Group input sections and insert stub table
+ Stub_table<size, big_endian>* stub_table = NULL;
+ Layout::Section_list section_list;
+ layout->get_executable_sections(&section_list);
+ std::stable_sort(section_list.begin(), section_list.end(), Sort_sections());
+ for (Layout::Section_list::reverse_iterator o = section_list.rbegin();
+ o != section_list.rend();
+ ++o)
+ {
+ typedef Output_section::Input_section_list Input_section_list;
+ for (Input_section_list::const_reverse_iterator i
+ = (*o)->input_sections().rbegin();
+ i != (*o)->input_sections().rend();
+ ++i)
+ {
+ if (i->is_input_section())
+ {
+ Powerpc_relobj<size, big_endian>* ppcobj = static_cast
+ <Powerpc_relobj<size, big_endian>*>(i->relobj());
+ bool has14 = ppcobj->has_14bit_branch(i->shndx());
+ if (!stub_control.can_add_to_stub_group(*o, &*i, has14))
+ {
+ stub_table->init(stub_control.owner(),
+ stub_control.output_section());
+ stub_table = NULL;
+ }
+ if (stub_table == NULL)
+ stub_table = this->new_stub_table();
+ ppcobj->set_stub_table(i->shndx(), stub_table);
+ }
+ }
+ }
+ if (stub_table != NULL)
+ {
+ const Output_section::Input_section* i = stub_control.owner();
+ if (!i->is_input_section())
+ {
+ // Corner case. A new stub group was made for the first
+ // section (last one looked at here) for some reason, but
+ // the first section is already being used as the owner for
+ // a stub table for following sections. Force it into that
+ // stub group.
+ gold_assert(this->stub_tables_.size() >= 2);
+ this->stub_tables_.pop_back();
+ delete stub_table;
+ Powerpc_relobj<size, big_endian>* ppcobj = static_cast
+ <Powerpc_relobj<size, big_endian>*>(i->relobj());
+ ppcobj->set_stub_table(i->shndx(), this->stub_tables_.back());
+ }
+ else
+ stub_table->init(i, stub_control.output_section());
+ }
+}
+
+// If this branch needs a plt call stub, or a long branch stub, make one.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::Branch_info::make_stub(
+ Stub_table<size, big_endian>* stub_table,
+ Stub_table<size, big_endian>* ifunc_stub_table,
+ Symbol_table* symtab) const
+{
+ Symbol* sym = this->object_->global_symbol(this->r_sym_);
+ if (sym != NULL && sym->is_forwarder())
+ sym = symtab->resolve_forwards(sym);
+ const Sized_symbol<size>* gsym = static_cast<const Sized_symbol<size>*>(sym);
+ if (gsym != NULL
+ ? use_plt_offset<size>(gsym, Scan::get_reference_flags(this->r_type_))
+ : this->object_->local_has_plt_offset(this->r_sym_))
+ {
+ if (stub_table == NULL)
+ stub_table = this->object_->stub_table(this->shndx_);
+ if (stub_table == NULL)
+ {
+ // This is a ref from a data section to an ifunc symbol.
+ stub_table = ifunc_stub_table;
+ }
+ gold_assert(stub_table != NULL);
+ if (gsym != NULL)
+ stub_table->add_plt_call_entry(this->object_, gsym,
+ this->r_type_, this->addend_);
+ else
+ stub_table->add_plt_call_entry(this->object_, this->r_sym_,
+ this->r_type_, this->addend_);
+ }
+ else
+ {
+ unsigned int max_branch_offset;
+ if (this->r_type_ == elfcpp::R_POWERPC_REL14
+ || this->r_type_ == elfcpp::R_POWERPC_REL14_BRTAKEN
+ || this->r_type_ == elfcpp::R_POWERPC_REL14_BRNTAKEN)
+ max_branch_offset = 1 << 15;
+ else if (this->r_type_ == elfcpp::R_POWERPC_REL24
+ || this->r_type_ == elfcpp::R_PPC_PLTREL24
+ || this->r_type_ == elfcpp::R_PPC_LOCAL24PC)
+ max_branch_offset = 1 << 25;
+ else
+ return;
+ Address from = this->object_->get_output_section_offset(this->shndx_);
+ gold_assert(from != invalid_address);
+ from += (this->object_->output_section(this->shndx_)->address()
+ + this->offset_);
+ Address to;
+ if (gsym != NULL)
+ {
+ switch (gsym->source())
+ {
+ case Symbol::FROM_OBJECT:
+ {
+ Object* symobj = gsym->object();
+ if (symobj->is_dynamic()
+ || symobj->pluginobj() != NULL)
+ return;
+ bool is_ordinary;
+ unsigned int shndx = gsym->shndx(&is_ordinary);
+ if (shndx == elfcpp::SHN_UNDEF)
+ return;
+ }
+ break;
+
+ case Symbol::IS_UNDEFINED:
+ return;
+
+ default:
+ break;
+ }
+ Symbol_table::Compute_final_value_status status;
+ to = symtab->compute_final_value<size>(gsym, &status);
+ if (status != Symbol_table::CFVS_OK)
+ return;
+ }
+ else
+ {
+ const Symbol_value<size>* psymval
+ = this->object_->local_symbol(this->r_sym_);
+ Symbol_value<size> symval;
+ typedef Sized_relobj_file<size, big_endian> ObjType;
+ typename ObjType::Compute_final_local_value_status status
+ = this->object_->compute_final_local_value(this->r_sym_, psymval,
+ &symval, symtab);
+ if (status != ObjType::CFLV_OK
+ || !symval.has_output_value())
+ return;
+ to = symval.value(this->object_, 0);
+ }
+ to += this->addend_;
+ if (stub_table == NULL)
+ stub_table = this->object_->stub_table(this->shndx_);
+ if (size == 64 && is_branch_reloc(this->r_type_))
+ {
+ unsigned int dest_shndx;
+ Target_powerpc<size, big_endian>* target =
+ static_cast<Target_powerpc<size, big_endian>*>(
+ parameters->sized_target<size, big_endian>());
+ to = target->symval_for_branch(symtab, to, gsym,
+ this->object_, &dest_shndx);
+ }
+ Address delta = to - from;
+ if (delta + max_branch_offset >= 2 * max_branch_offset)
+ {
+ if (stub_table == NULL)
+ {
+ gold_warning(_("%s:%s: branch in non-executable section,"
+ " no long branch stub for you"),
+ this->object_->name().c_str(),
+ this->object_->section_name(this->shndx_).c_str());
+ return;
+ }
+ stub_table->add_long_branch_entry(this->object_, to);
+ }
+ }
+}
+
+// Relaxation hook. This is where we do stub generation.
+
+template<int size, bool big_endian>
+bool
+Target_powerpc<size, big_endian>::do_relax(int pass,
+ const Input_objects*,
+ Symbol_table* symtab,
+ Layout* layout,
+ const Task* task)
+{
+ unsigned int prev_brlt_size = 0;
+ if (pass == 1)
+ {
+ bool thread_safe = parameters->options().plt_thread_safe();
+ if (size == 64 && !parameters->options().user_set_plt_thread_safe())
+ {
+ static const char* const thread_starter[] =
+ {
+ "pthread_create",
+ /* libstdc++ */
+ "_ZNSt6thread15_M_start_threadESt10shared_ptrINS_10_Impl_baseEE",
+ /* librt */
+ "aio_init", "aio_read", "aio_write", "aio_fsync", "lio_listio",
+ "mq_notify", "create_timer",
+ /* libanl */
+ "getaddrinfo_a",
+ /* libgomp */
+ "GOMP_parallel_start",
+ "GOMP_parallel_loop_static_start",
+ "GOMP_parallel_loop_dynamic_start",
+ "GOMP_parallel_loop_guided_start",
+ "GOMP_parallel_loop_runtime_start",
+ "GOMP_parallel_sections_start",
+ };
+
+ if (parameters->options().shared())
+ thread_safe = true;
+ else
+ {
+ for (unsigned int i = 0;
+ i < sizeof(thread_starter) / sizeof(thread_starter[0]);
+ i++)
+ {
+ Symbol* sym = symtab->lookup(thread_starter[i], NULL);
+ thread_safe = (sym != NULL
+ && sym->in_reg()
+ && sym->in_real_elf());
+ if (thread_safe)
+ break;
+ }
+ }
+ }
+ this->plt_thread_safe_ = thread_safe;
+ this->group_sections(layout, task);
+ }
+
+ // We need address of stub tables valid for make_stub.
+ for (typename Stub_tables::iterator p = this->stub_tables_.begin();
+ p != this->stub_tables_.end();
+ ++p)
+ {
+ const Powerpc_relobj<size, big_endian>* object
+ = static_cast<const Powerpc_relobj<size, big_endian>*>((*p)->relobj());
+ Address off = object->get_output_section_offset((*p)->shndx());
+ gold_assert(off != invalid_address);
+ Output_section* os = (*p)->output_section();
+ (*p)->set_address_and_size(os, off);
+ }
+
+ if (pass != 1)
+ {
+ // Clear plt call stubs, long branch stubs and branch lookup table.
+ prev_brlt_size = this->branch_lookup_table_.size();
+ this->branch_lookup_table_.clear();
+ for (typename Stub_tables::iterator p = this->stub_tables_.begin();
+ p != this->stub_tables_.end();
+ ++p)
+ {
+ (*p)->clear_stubs();
+ }
+ }
+
+ // Build all the stubs.
+ Stub_table<size, big_endian>* ifunc_stub_table
+ = this->stub_tables_.size() == 0 ? NULL : this->stub_tables_[0];
+ Stub_table<size, big_endian>* one_stub_table
+ = this->stub_tables_.size() != 1 ? NULL : ifunc_stub_table;
+ for (typename Branches::const_iterator b = this->branch_info_.begin();
+ b != this->branch_info_.end();
+ b++)
+ {
+ b->make_stub(one_stub_table, ifunc_stub_table, symtab);
+ }
+
+ // Did anything change size?
+ unsigned int num_huge_branches = this->branch_lookup_table_.size();
+ bool again = num_huge_branches != prev_brlt_size;
+ if (size == 64 && num_huge_branches != 0)
+ this->make_brlt_section(layout);
+ if (size == 64 && again)
+ this->brlt_section_->set_current_size(num_huge_branches);
+
+ typedef Unordered_set<Output_section*> Output_sections;
+ Output_sections os_need_update;
+ for (typename Stub_tables::iterator p = this->stub_tables_.begin();
+ p != this->stub_tables_.end();
+ ++p)
+ {
+ if ((*p)->size_update())
+ {
+ again = true;
+ (*p)->add_eh_frame(layout);
+ os_need_update.insert((*p)->output_section());
+ }
+ }
+
+ // Set output section offsets for all input sections in an output
+ // section that just changed size. Anything past the stubs will
+ // need updating.
+ for (typename Output_sections::iterator p = os_need_update.begin();
+ p != os_need_update.end();
+ p++)
+ {
+ Output_section* os = *p;
+ Address off = 0;
+ typedef Output_section::Input_section_list Input_section_list;
+ for (Input_section_list::const_iterator i = os->input_sections().begin();
+ i != os->input_sections().end();
+ ++i)
+ {
+ off = align_address(off, i->addralign());
+ if (i->is_input_section() || i->is_relaxed_input_section())
+ i->relobj()->set_section_offset(i->shndx(), off);
+ if (i->is_relaxed_input_section())
+ {
+ Stub_table<size, big_endian>* stub_table
+ = static_cast<Stub_table<size, big_endian>*>(
+ i->relaxed_input_section());
+ off += stub_table->set_address_and_size(os, off);
+ }
+ else
+ off += i->data_size();
+ }
+ // If .branch_lt is part of this output section, then we have
+ // just done the offset adjustment.
+ os->clear_section_offsets_need_adjustment();
+ }
+
+ if (size == 64
+ && !again
+ && num_huge_branches != 0
+ && parameters->options().output_is_position_independent())
+ {
+ // Fill in the BRLT relocs.
+ this->brlt_section_->reset_brlt_sizes();
+ for (typename Branch_lookup_table::const_iterator p
+ = this->branch_lookup_table_.begin();
+ p != this->branch_lookup_table_.end();
+ ++p)
+ {
+ this->brlt_section_->add_reloc(p->first, p->second);
+ }
+ this->brlt_section_->finalize_brlt_sizes();
+ }
+ return again;
+}
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::do_plt_fde_location(const Output_data* plt,
+ unsigned char* oview,
+ uint64_t* paddress,
+ off_t* plen) const
+{
+ uint64_t address = plt->address();
+ off_t len = plt->data_size();
+
+ if (plt == this->glink_)
+ {
+ // See Output_data_glink::do_write() for glink contents.
+ if (size == 64)
+ {
+ // There is one word before __glink_PLTresolve
+ address += 8;
+ len -= 8;
+ }
+ else if (parameters->options().output_is_position_independent())
+ {
+ // There are two FDEs for a position independent glink.
+ // The first covers the branch table, the second
+ // __glink_PLTresolve at the end of glink.
+ off_t resolve_size = this->glink_->pltresolve_size;
+ if (oview[9] == 0)
+ len -= resolve_size;
+ else
+ {
+ address += len - resolve_size;
+ len = resolve_size;
+ }
+ }
+ }
+ else
+ {
+ // Must be a stub table.
+ const Stub_table<size, big_endian>* stub_table
+ = static_cast<const Stub_table<size, big_endian>*>(plt);
+ uint64_t stub_address = stub_table->stub_address();
+ len -= stub_address - address;
+ address = stub_address;
+ }
+
+ *paddress = address;
+ *plen = len;
+}
+
+// A class to handle the PLT data.
+
+template<int size, bool big_endian>
+class Output_data_plt_powerpc : public Output_section_data_build
+{
+ public:
+ typedef Output_data_reloc<elfcpp::SHT_RELA, true,
+ size, big_endian> Reloc_section;
+
+ Output_data_plt_powerpc(Target_powerpc<size, big_endian>* targ,
+ Reloc_section* plt_rel,
+ unsigned int reserved_size,
+ const char* name)
+ : Output_section_data_build(size == 32 ? 4 : 8),
+ rel_(plt_rel),
+ targ_(targ),
+ initial_plt_entry_size_(reserved_size),
+ name_(name)
+ { }
+
+ // Add an entry to the PLT.
+ void
+ add_entry(Symbol*);
+
+ void
+ add_ifunc_entry(Symbol*);
+
+ void
+ add_local_ifunc_entry(Sized_relobj_file<size, big_endian>*, unsigned int);
+
+ // Return the .rela.plt section data.
+ Reloc_section*
+ rel_plt() const
+ {
+ return this->rel_;
+ }
+
+ // Return the number of PLT entries.
+ unsigned int
+ entry_count() const
+ {
+ if (this->current_data_size() == 0)
+ return 0;
+ return ((this->current_data_size() - this->initial_plt_entry_size_)
+ / plt_entry_size);
+ }
+
+ // Return the offset of the first non-reserved PLT entry.
+ unsigned int
+ first_plt_entry_offset()
+ { return this->initial_plt_entry_size_; }
+
+ // Return the size of a PLT entry.
+ static unsigned int
+ get_plt_entry_size()
+ { return plt_entry_size; }
+
+ protected:
+ void
+ do_adjust_output_section(Output_section* os)
+ {
+ os->set_entsize(0);
+ }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, this->name_); }
+
+ private:
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = size == 32 ? 4 : 24;
+
+ // Write out the PLT data.
+ void
+ do_write(Output_file*);
+
+ // The reloc section.
+ Reloc_section* rel_;
+ // Allows access to .glink for do_write.
+ Target_powerpc<size, big_endian>* targ_;
+ // The size of the first reserved entry.
+ int initial_plt_entry_size_;
+ // What to report in map file.
+ const char *name_;
+};
+
+// Add an entry to the PLT.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_powerpc<size, big_endian>::add_entry(Symbol* gsym)
+{
+ if (!gsym->has_plt_offset())
+ {
+ section_size_type off = this->current_data_size();
+ if (off == 0)
+ off += this->first_plt_entry_offset();
+ gsym->set_plt_offset(off);
+ gsym->set_needs_dynsym_entry();
+ unsigned int dynrel = elfcpp::R_POWERPC_JMP_SLOT;
+ this->rel_->add_global(gsym, dynrel, this, off, 0);
+ off += plt_entry_size;
+ this->set_current_data_size(off);
+ }
+}
+
+// Add an entry for a global ifunc symbol that resolves locally, to the IPLT.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_powerpc<size, big_endian>::add_ifunc_entry(Symbol* gsym)
+{
+ if (!gsym->has_plt_offset())
+ {
+ section_size_type off = this->current_data_size();
+ gsym->set_plt_offset(off);
+ unsigned int dynrel = elfcpp::R_POWERPC_IRELATIVE;
+ if (size == 64)
+ dynrel = elfcpp::R_PPC64_JMP_IREL;
+ this->rel_->add_symbolless_global_addend(gsym, dynrel, this, off, 0);
+ off += plt_entry_size;
+ this->set_current_data_size(off);
+ }
+}
+
+// Add an entry for a local ifunc symbol to the IPLT.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_powerpc<size, big_endian>::add_local_ifunc_entry(
+ Sized_relobj_file<size, big_endian>* relobj,
+ unsigned int local_sym_index)
+{
+ if (!relobj->local_has_plt_offset(local_sym_index))
+ {
+ section_size_type off = this->current_data_size();
+ relobj->set_local_plt_offset(local_sym_index, off);
+ unsigned int dynrel = elfcpp::R_POWERPC_IRELATIVE;
+ if (size == 64)
+ dynrel = elfcpp::R_PPC64_JMP_IREL;
+ this->rel_->add_symbolless_local_addend(relobj, local_sym_index, dynrel,
+ this, off, 0);
+ off += plt_entry_size;
+ this->set_current_data_size(off);
+ }
+}
+
+static const uint32_t add_0_11_11 = 0x7c0b5a14;
+static const uint32_t add_2_2_11 = 0x7c425a14;
+static const uint32_t add_3_3_2 = 0x7c631214;
+static const uint32_t add_3_3_13 = 0x7c636a14;
+static const uint32_t add_11_0_11 = 0x7d605a14;
+static const uint32_t add_12_2_11 = 0x7d825a14;
+static const uint32_t add_12_12_11 = 0x7d8c5a14;
+static const uint32_t addi_11_11 = 0x396b0000;
+static const uint32_t addi_12_12 = 0x398c0000;
+static const uint32_t addi_2_2 = 0x38420000;
+static const uint32_t addi_3_2 = 0x38620000;
+static const uint32_t addi_3_3 = 0x38630000;
+static const uint32_t addis_0_2 = 0x3c020000;
+static const uint32_t addis_0_13 = 0x3c0d0000;
+static const uint32_t addis_11_11 = 0x3d6b0000;
+static const uint32_t addis_11_30 = 0x3d7e0000;
+static const uint32_t addis_12_12 = 0x3d8c0000;
+static const uint32_t addis_12_2 = 0x3d820000;
+static const uint32_t addis_3_2 = 0x3c620000;
+static const uint32_t addis_3_13 = 0x3c6d0000;
+static const uint32_t b = 0x48000000;
+static const uint32_t bcl_20_31 = 0x429f0005;
+static const uint32_t bctr = 0x4e800420;
+static const uint32_t blr = 0x4e800020;
+static const uint32_t blrl = 0x4e800021;
+static const uint32_t bnectr_p4 = 0x4ce20420;
+static const uint32_t cmpldi_2_0 = 0x28220000;
+static const uint32_t cror_15_15_15 = 0x4def7b82;
+static const uint32_t cror_31_31_31 = 0x4ffffb82;
+static const uint32_t ld_0_1 = 0xe8010000;
+static const uint32_t ld_0_12 = 0xe80c0000;
+static const uint32_t ld_11_12 = 0xe96c0000;
+static const uint32_t ld_11_2 = 0xe9620000;
+static const uint32_t ld_2_1 = 0xe8410000;
+static const uint32_t ld_2_11 = 0xe84b0000;
+static const uint32_t ld_2_12 = 0xe84c0000;
+static const uint32_t ld_2_2 = 0xe8420000;
+static const uint32_t lfd_0_1 = 0xc8010000;
+static const uint32_t li_0_0 = 0x38000000;
+static const uint32_t li_12_0 = 0x39800000;
+static const uint32_t lis_0_0 = 0x3c000000;
+static const uint32_t lis_11 = 0x3d600000;
+static const uint32_t lis_12 = 0x3d800000;
+static const uint32_t lwz_0_12 = 0x800c0000;
+static const uint32_t lwz_11_11 = 0x816b0000;
+static const uint32_t lwz_11_30 = 0x817e0000;
+static const uint32_t lwz_12_12 = 0x818c0000;
+static const uint32_t lwzu_0_12 = 0x840c0000;
+static const uint32_t lvx_0_12_0 = 0x7c0c00ce;
+static const uint32_t mflr_0 = 0x7c0802a6;
+static const uint32_t mflr_11 = 0x7d6802a6;
+static const uint32_t mflr_12 = 0x7d8802a6;
+static const uint32_t mtctr_0 = 0x7c0903a6;
+static const uint32_t mtctr_11 = 0x7d6903a6;
+static const uint32_t mtctr_12 = 0x7d8903a6;
+static const uint32_t mtlr_0 = 0x7c0803a6;
+static const uint32_t mtlr_12 = 0x7d8803a6;
+static const uint32_t nop = 0x60000000;
+static const uint32_t ori_0_0_0 = 0x60000000;
+static const uint32_t std_0_1 = 0xf8010000;
+static const uint32_t std_0_12 = 0xf80c0000;
+static const uint32_t std_2_1 = 0xf8410000;
+static const uint32_t stfd_0_1 = 0xd8010000;
+static const uint32_t stvx_0_12_0 = 0x7c0c01ce;
+static const uint32_t sub_11_11_12 = 0x7d6c5850;
+static const uint32_t xor_11_11_11 = 0x7d6b5a78;
+
+// Write out the PLT.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_powerpc<size, big_endian>::do_write(Output_file* of)
+{
+ if (size == 32 && this->name_[3] != 'I')
+ {
+ const section_size_type 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);
+ unsigned char* pov = oview;
+ unsigned char* endpov = oview + oview_size;
+
+ // The address of the .glink branch table
+ const Output_data_glink<size, big_endian>* glink
+ = this->targ_->glink_section();
+ elfcpp::Elf_types<32>::Elf_Addr branch_tab = glink->address();
+
+ while (pov < endpov)
+ {
+ elfcpp::Swap<32, big_endian>::writeval(pov, branch_tab);
+ pov += 4;
+ branch_tab += 4;
+ }
+
+ of->write_output_view(offset, oview_size, oview);
+ }
+}
+
+// Create the PLT section.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::make_plt_section(Symbol_table* symtab,
+ Layout* layout)
+{
+ if (this->plt_ == NULL)
+ {
+ if (this->got_ == NULL)
+ this->got_section(symtab, layout);
+
+ if (this->glink_ == NULL)
+ make_glink_section(layout);
+
+ // Ensure that .rela.dyn always appears before .rela.plt This is
+ // necessary due to how, on PowerPC and some other targets, .rela.dyn
+ // needs to include .rela.plt in its range.
+ this->rela_dyn_section(layout);
+
+ Reloc_section* plt_rel = new Reloc_section(false);
+ layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
+ elfcpp::SHF_ALLOC, plt_rel,
+ ORDER_DYNAMIC_PLT_RELOCS, false);
+ this->plt_
+ = new Output_data_plt_powerpc<size, big_endian>(this, plt_rel,
+ size == 32 ? 0 : 24,
+ "** PLT");
+ layout->add_output_section_data(".plt",
+ (size == 32
+ ? elfcpp::SHT_PROGBITS
+ : elfcpp::SHT_NOBITS),
+ elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+ this->plt_,
+ (size == 32
+ ? ORDER_SMALL_DATA
+ : ORDER_SMALL_BSS),
+ false);
+ }
+}
+
+// Create the IPLT section.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::make_iplt_section(Symbol_table* symtab,
+ Layout* layout)
+{
+ if (this->iplt_ == NULL)
+ {
+ this->make_plt_section(symtab, layout);
+
+ Reloc_section* iplt_rel = new Reloc_section(false);
+ this->rela_dyn_->output_section()->add_output_section_data(iplt_rel);
+ this->iplt_
+ = new Output_data_plt_powerpc<size, big_endian>(this, iplt_rel,
+ 0, "** IPLT");
+ this->plt_->output_section()->add_output_section_data(this->iplt_);
+ }
+}
+
+// A section for huge long branch addresses, similar to plt section.
+
+template<int size, bool big_endian>
+class Output_data_brlt_powerpc : public Output_section_data_build
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef Output_data_reloc<elfcpp::SHT_RELA, true,
+ size, big_endian> Reloc_section;
+
+ Output_data_brlt_powerpc(Target_powerpc<size, big_endian>* targ,
+ Reloc_section* brlt_rel)
+ : Output_section_data_build(size == 32 ? 4 : 8),
+ rel_(brlt_rel),
+ targ_(targ)
+ { }
+
+ void
+ reset_brlt_sizes()
+ {
+ this->reset_data_size();
+ this->rel_->reset_data_size();
+ }
+
+ void
+ finalize_brlt_sizes()
+ {
+ this->finalize_data_size();
+ this->rel_->finalize_data_size();
+ }
+
+ // Add a reloc for an entry in the BRLT.
+ void
+ add_reloc(Address to, unsigned int off)
+ { this->rel_->add_relative(elfcpp::R_POWERPC_RELATIVE, this, off, to); }
+
+ // Update section and reloc section size.
+ void
+ set_current_size(unsigned int num_branches)
+ {
+ this->reset_address_and_file_offset();
+ this->set_current_data_size(num_branches * 16);
+ this->finalize_data_size();
+ Output_section* os = this->output_section();
+ os->set_section_offsets_need_adjustment();
+ if (this->rel_ != NULL)
+ {
+ unsigned int reloc_size
+ = Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+ this->rel_->reset_address_and_file_offset();
+ this->rel_->set_current_data_size(num_branches * reloc_size);
+ this->rel_->finalize_data_size();
+ Output_section* os = this->rel_->output_section();
+ os->set_section_offsets_need_adjustment();
+ }
+ }
+
+ protected:
+ void
+ do_adjust_output_section(Output_section* os)
+ {
+ os->set_entsize(0);
+ }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, "** BRLT"); }
+
+ private:
+ // Write out the BRLT data.
+ void
+ do_write(Output_file*);
+
+ // The reloc section.
+ Reloc_section* rel_;
+ Target_powerpc<size, big_endian>* targ_;
+};
+
+// Make the branch lookup table section.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::make_brlt_section(Layout* layout)
+{
+ if (size == 64 && this->brlt_section_ == NULL)
+ {
+ Reloc_section* brlt_rel = NULL;
+ bool is_pic = parameters->options().output_is_position_independent();
+ if (is_pic)
+ {
+ // When PIC we can't fill in .branch_lt (like .plt it can be
+ // a bss style section) but must initialise at runtime via
+ // dynamic relocats.
+ this->rela_dyn_section(layout);
+ brlt_rel = new Reloc_section(false);
+ this->rela_dyn_->output_section()->add_output_section_data(brlt_rel);
+ }
+ this->brlt_section_
+ = new Output_data_brlt_powerpc<size, big_endian>(this, brlt_rel);
+ if (this->plt_ && is_pic)
+ this->plt_->output_section()
+ ->add_output_section_data(this->brlt_section_);
+ else
+ layout->add_output_section_data(".branch_lt",
+ (is_pic ? elfcpp::SHT_NOBITS
+ : elfcpp::SHT_PROGBITS),
+ elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+ this->brlt_section_,
+ (is_pic ? ORDER_SMALL_BSS
+ : ORDER_SMALL_DATA),
+ false);
+ }
+}
+
+// Write out .branch_lt when non-PIC.
+
+template<int size, bool big_endian>
+void
+Output_data_brlt_powerpc<size, big_endian>::do_write(Output_file* of)
+{
+ if (size == 64 && !parameters->options().output_is_position_independent())
+ {
+ const section_size_type 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);
+
+ this->targ_->write_branch_lookup_table(oview);
+ of->write_output_view(offset, oview_size, oview);
+ }
+}
+
+static inline uint32_t
+l(uint32_t a)
+{
+ return a & 0xffff;
+}
+
+static inline uint32_t
+hi(uint32_t a)
+{
+ return l(a >> 16);
+}
+
+static inline uint32_t
+ha(uint32_t a)
+{
+ return hi(a + 0x8000);
+}
+
+template<int size>
+struct Eh_cie
+{
+ static const unsigned char eh_frame_cie[12];
+};
+
+template<int size>
+const unsigned char Eh_cie<size>::eh_frame_cie[] =
+{
+ 1, // CIE version.
+ 'z', 'R', 0, // Augmentation string.
+ 4, // Code alignment.
+ 0x80 - size / 8 , // Data alignment.
+ 65, // RA reg.
+ 1, // Augmentation size.
+ (elfcpp::DW_EH_PE_pcrel
+ | elfcpp::DW_EH_PE_sdata4), // FDE encoding.
+ elfcpp::DW_CFA_def_cfa, 1, 0 // def_cfa: r1 offset 0.
+};
+
+// Describe __glink_PLTresolve use of LR, 64-bit version.
+static const unsigned char glink_eh_frame_fde_64[] =
+{
+ 0, 0, 0, 0, // Replaced with offset to .glink.
+ 0, 0, 0, 0, // Replaced with size of .glink.
+ 0, // Augmentation size.
+ elfcpp::DW_CFA_advance_loc + 1,
+ elfcpp::DW_CFA_register, 65, 12,
+ elfcpp::DW_CFA_advance_loc + 4,
+ elfcpp::DW_CFA_restore_extended, 65
+};
+
+// Describe __glink_PLTresolve use of LR, 32-bit version.
+static const unsigned char glink_eh_frame_fde_32[] =
+{
+ 0, 0, 0, 0, // Replaced with offset to .glink.
+ 0, 0, 0, 0, // Replaced with size of .glink.
+ 0, // Augmentation size.
+ elfcpp::DW_CFA_advance_loc + 2,
+ elfcpp::DW_CFA_register, 65, 0,
+ elfcpp::DW_CFA_advance_loc + 4,
+ elfcpp::DW_CFA_restore_extended, 65
+};
+
+static const unsigned char default_fde[] =
+{
+ 0, 0, 0, 0, // Replaced with offset to stubs.
+ 0, 0, 0, 0, // Replaced with size of stubs.
+ 0, // Augmentation size.
+ elfcpp::DW_CFA_nop, // Pad.
+ elfcpp::DW_CFA_nop,
+ elfcpp::DW_CFA_nop
+};
+
+template<bool big_endian>
+static inline void
+write_insn(unsigned char* p, uint32_t v)
+{
+ elfcpp::Swap<32, big_endian>::writeval(p, v);
+}
+
+// Stub_table holds information about plt and long branch stubs.
+// Stubs are built in an area following some input section determined
+// by group_sections(). This input section is converted to a relaxed
+// input section allowing it to be resized to accommodate the stubs
+
+template<int size, bool big_endian>
+class Stub_table : public Output_relaxed_input_section
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ static const Address invalid_address = static_cast<Address>(0) - 1;
+
+ Stub_table(Target_powerpc<size, big_endian>* targ)
+ : Output_relaxed_input_section(NULL, 0, 0),
+ targ_(targ), plt_call_stubs_(), long_branch_stubs_(),
+ orig_data_size_(0), plt_size_(0), last_plt_size_(0),
+ branch_size_(0), last_branch_size_(0), eh_frame_added_(false)
+ { }
+
+ // Delayed Output_relaxed_input_section init.
+ void
+ init(const Output_section::Input_section*, Output_section*);
+
+ // Add a plt call stub.
+ void
+ add_plt_call_entry(const Sized_relobj_file<size, big_endian>*,
+ const Symbol*,
+ unsigned int,
+ Address);
+
+ void
+ add_plt_call_entry(const Sized_relobj_file<size, big_endian>*,
+ unsigned int,
+ unsigned int,
+ Address);
+
+ // Find a given plt call stub.
+ Address
+ find_plt_call_entry(const Symbol*) const;
+
+ Address
+ find_plt_call_entry(const Sized_relobj_file<size, big_endian>*,
+ unsigned int) const;
+
+ Address
+ find_plt_call_entry(const Sized_relobj_file<size, big_endian>*,
+ const Symbol*,
+ unsigned int,
+ Address) const;
+
+ Address
+ find_plt_call_entry(const Sized_relobj_file<size, big_endian>*,
+ unsigned int,
+ unsigned int,
+ Address) const;
+
+ // Add a long branch stub.
+ void
+ add_long_branch_entry(const Powerpc_relobj<size, big_endian>*, Address);
+
+ Address
+ find_long_branch_entry(const Powerpc_relobj<size, big_endian>*,
+ Address) const;
+
+ void
+ clear_stubs()
+ {
+ this->plt_call_stubs_.clear();
+ this->plt_size_ = 0;
+ this->long_branch_stubs_.clear();
+ this->branch_size_ = 0;
+ }
+
+ Address
+ set_address_and_size(const Output_section* os, Address off)
+ {
+ Address start_off = off;
+ off += this->orig_data_size_;
+ Address my_size = this->plt_size_ + this->branch_size_;
+ if (my_size != 0)
+ off = align_address(off, this->stub_align());
+ // Include original section size and alignment padding in size
+ my_size += off - start_off;
+ this->reset_address_and_file_offset();
+ this->set_current_data_size(my_size);
+ this->set_address_and_file_offset(os->address() + start_off,
+ os->offset() + start_off);
+ return my_size;
+ }
+
+ Address
+ stub_address() const
+ {
+ return align_address(this->address() + this->orig_data_size_,
+ this->stub_align());
+ }
+
+ Address
+ stub_offset() const
+ {
+ return align_address(this->offset() + this->orig_data_size_,
+ this->stub_align());
+ }
+
+ section_size_type
+ plt_size() const
+ { return this->plt_size_; }
+
+ bool
+ size_update()
+ {
+ Output_section* os = this->output_section();
+ if (os->addralign() < this->stub_align())
+ {
+ os->set_addralign(this->stub_align());
+ // FIXME: get rid of the insane checkpointing.
+ // We can't increase alignment of the input section to which
+ // stubs are attached; The input section may be .init which
+ // is pasted together with other .init sections to form a
+ // function. Aligning might insert zero padding resulting in
+ // sigill. However we do need to increase alignment of the
+ // output section so that the align_address() on offset in
+ // set_address_and_size() adds the same padding as the
+ // align_address() on address in stub_address().
+ // What's more, we need this alignment for the layout done in
+ // relaxation_loop_body() so that the output section starts at
+ // a suitably aligned address.
+ os->checkpoint_set_addralign(this->stub_align());
+ }
+ if (this->last_plt_size_ != this->plt_size_
+ || this->last_branch_size_ != this->branch_size_)
+ {
+ this->last_plt_size_ = this->plt_size_;
+ this->last_branch_size_ = this->branch_size_;
+ return true;
+ }
+ return false;
+ }
+
+ // Add .eh_frame info for this stub section. Unlike other linker
+ // generated .eh_frame this is added late in the link, because we
+ // only want the .eh_frame info if this particular stub section is
+ // non-empty.
+ void
+ add_eh_frame(Layout* layout)
+ {
+ if (!this->eh_frame_added_)
+ {
+ if (!parameters->options().ld_generated_unwind_info())
+ return;
+
+ // Since we add stub .eh_frame info late, it must be placed
+ // after all other linker generated .eh_frame info so that
+ // merge mapping need not be updated for input sections.
+ // There is no provision to use a different CIE to that used
+ // by .glink.
+ if (!this->targ_->has_glink())
+ return;
+
+ layout->add_eh_frame_for_plt(this,
+ Eh_cie<size>::eh_frame_cie,
+ sizeof (Eh_cie<size>::eh_frame_cie),
+ default_fde,
+ sizeof (default_fde));
+ this->eh_frame_added_ = true;
+ }
+ }
+
+ Target_powerpc<size, big_endian>*
+ targ() const
+ { return targ_; }
+
+ private:
+ class Plt_stub_ent;
+ class Plt_stub_ent_hash;
+ typedef Unordered_map<Plt_stub_ent, unsigned int,
+ Plt_stub_ent_hash> Plt_stub_entries;
+
+ // Alignment of stub section.
+ unsigned int
+ stub_align() const
+ {
+ if (size == 32)
+ return 16;
+ unsigned int min_align = 32;
+ unsigned int user_align = 1 << parameters->options().plt_align();
+ return std::max(user_align, min_align);
+ }
+
+ // Return the plt offset for the given call stub.
+ Address
+ plt_off(typename Plt_stub_entries::const_iterator p, bool* is_iplt) const
+ {
+ const Symbol* gsym = p->first.sym_;
+ if (gsym != NULL)
+ {
+ *is_iplt = (gsym->type() == elfcpp::STT_GNU_IFUNC
+ && gsym->can_use_relative_reloc(false));
+ return gsym->plt_offset();
+ }
+ else
+ {
+ *is_iplt = true;
+ const Sized_relobj_file<size, big_endian>* relobj = p->first.object_;
+ unsigned int local_sym_index = p->first.locsym_;
+ return relobj->local_plt_offset(local_sym_index);
+ }
+ }
+
+ // Size of a given plt call stub.
+ unsigned int
+ plt_call_size(typename Plt_stub_entries::const_iterator p) const
+ {
+ if (size == 32)
+ return 16;
+
+ bool is_iplt;
+ Address plt_addr = this->plt_off(p, &is_iplt);
+ if (is_iplt)
+ plt_addr += this->targ_->iplt_section()->address();
+ else
+ plt_addr += this->targ_->plt_section()->address();
+ Address got_addr = this->targ_->got_section()->output_section()->address();
+ const Powerpc_relobj<size, big_endian>* ppcobj = static_cast
+ <const Powerpc_relobj<size, big_endian>*>(p->first.object_);
+ got_addr += ppcobj->toc_base_offset();
+ Address off = plt_addr - got_addr;
+ bool static_chain = parameters->options().plt_static_chain();
+ bool thread_safe = this->targ_->plt_thread_safe();
+ unsigned int bytes = (4 * 5
+ + 4 * static_chain
+ + 8 * thread_safe
+ + 4 * (ha(off) != 0)
+ + 4 * (ha(off + 8 + 8 * static_chain) != ha(off)));
+ unsigned int align = 1 << parameters->options().plt_align();
+ if (align > 1)
+ bytes = (bytes + align - 1) & -align;
+ return bytes;
+ }
+
+ // Return long branch stub size.
+ unsigned int
+ branch_stub_size(Address to)
+ {
+ Address loc
+ = this->stub_address() + this->last_plt_size_ + this->branch_size_;
+ if (to - loc + (1 << 25) < 2 << 25)
+ return 4;
+ if (size == 64 || !parameters->options().output_is_position_independent())
+ return 16;
+ return 32;
+ }
+
+ // Write out stubs.
+ void
+ do_write(Output_file*);
+
+ // Plt call stub keys.
+ class Plt_stub_ent
+ {
+ public:
+ Plt_stub_ent(const Symbol* sym)
+ : sym_(sym), object_(0), addend_(0), locsym_(0)
+ { }
+
+ Plt_stub_ent(const Sized_relobj_file<size, big_endian>* object,
+ unsigned int locsym_index)
+ : sym_(NULL), object_(object), addend_(0), locsym_(locsym_index)
+ { }
+
+ Plt_stub_ent(const Sized_relobj_file<size, big_endian>* object,
+ const Symbol* sym,
+ unsigned int r_type,
+ Address addend)
+ : sym_(sym), object_(0), addend_(0), locsym_(0)
+ {
+ if (size != 32)
+ this->addend_ = addend;
+ else if (parameters->options().output_is_position_independent()
+ && r_type == elfcpp::R_PPC_PLTREL24)
+ {
+ this->addend_ = addend;
+ if (this->addend_ >= 32768)
+ this->object_ = object;
+ }
+ }
+
+ Plt_stub_ent(const Sized_relobj_file<size, big_endian>* object,
+ unsigned int locsym_index,
+ unsigned int r_type,
+ Address addend)
+ : sym_(NULL), object_(object), addend_(0), locsym_(locsym_index)
+ {
+ if (size != 32)
+ this->addend_ = addend;
+ else if (parameters->options().output_is_position_independent()
+ && r_type == elfcpp::R_PPC_PLTREL24)
+ this->addend_ = addend;
+ }
+
+ bool operator==(const Plt_stub_ent& that) const
+ {
+ return (this->sym_ == that.sym_
+ && this->object_ == that.object_
+ && this->addend_ == that.addend_
+ && this->locsym_ == that.locsym_);
+ }
+
+ const Symbol* sym_;
+ const Sized_relobj_file<size, big_endian>* object_;
+ typename elfcpp::Elf_types<size>::Elf_Addr addend_;
+ unsigned int locsym_;
+ };
+
+ class Plt_stub_ent_hash
+ {
+ public:
+ size_t operator()(const Plt_stub_ent& ent) const
+ {
+ return (reinterpret_cast<uintptr_t>(ent.sym_)
+ ^ reinterpret_cast<uintptr_t>(ent.object_)
+ ^ ent.addend_
+ ^ ent.locsym_);
+ }
+ };
+
+ // Long branch stub keys.
+ class Branch_stub_ent
+ {
+ public:
+ Branch_stub_ent(const Powerpc_relobj<size, big_endian>* obj, Address to)
+ : dest_(to), toc_base_off_(0)
+ {
+ if (size == 64)
+ toc_base_off_ = obj->toc_base_offset();
+ }
+
+ bool operator==(const Branch_stub_ent& that) const
+ {
+ return (this->dest_ == that.dest_
+ && (size == 32
+ || this->toc_base_off_ == that.toc_base_off_));
+ }
+
+ Address dest_;
+ unsigned int toc_base_off_;
+ };
+
+ class Branch_stub_ent_hash
+ {
+ public:
+ size_t operator()(const Branch_stub_ent& ent) const
+ { return ent.dest_ ^ ent.toc_base_off_; }
+ };
+
+ // In a sane world this would be a global.
+ Target_powerpc<size, big_endian>* targ_;
+ // Map sym/object/addend to stub offset.
+ Plt_stub_entries plt_call_stubs_;
+ // Map destination address to stub offset.
+ typedef Unordered_map<Branch_stub_ent, unsigned int,
+ Branch_stub_ent_hash> Branch_stub_entries;
+ Branch_stub_entries long_branch_stubs_;
+ // size of input section
+ section_size_type orig_data_size_;
+ // size of stubs
+ section_size_type plt_size_, last_plt_size_, branch_size_, last_branch_size_;
+ // Whether .eh_frame info has been created for this stub section.
+ bool eh_frame_added_;
+};
+
+// Make a new stub table, and record.
+
+template<int size, bool big_endian>
+Stub_table<size, big_endian>*
+Target_powerpc<size, big_endian>::new_stub_table()
+{
+ Stub_table<size, big_endian>* stub_table
+ = new Stub_table<size, big_endian>(this);
+ this->stub_tables_.push_back(stub_table);
+ return stub_table;
+}
+
+// Delayed stub table initialisation, because we create the stub table
+// before we know to which section it will be attached.
+
+template<int size, bool big_endian>
+void
+Stub_table<size, big_endian>::init(
+ const Output_section::Input_section* owner,
+ Output_section* output_section)
+{
+ this->set_relobj(owner->relobj());
+ this->set_shndx(owner->shndx());
+ this->set_addralign(this->relobj()->section_addralign(this->shndx()));
+ this->set_output_section(output_section);
+ this->orig_data_size_ = owner->current_data_size();
+
+ std::vector<Output_relaxed_input_section*> new_relaxed;
+ new_relaxed.push_back(this);
+ output_section->convert_input_sections_to_relaxed_sections(new_relaxed);
+}
+
+// Add a plt call stub, if we do not already have one for this
+// sym/object/addend combo.
+
+template<int size, bool big_endian>
+void
+Stub_table<size, big_endian>::add_plt_call_entry(
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol* gsym,
+ unsigned int r_type,
+ Address addend)
+{
+ Plt_stub_ent ent(object, gsym, r_type, addend);
+ Address off = this->plt_size_;
+ std::pair<typename Plt_stub_entries::iterator, bool> p
+ = this->plt_call_stubs_.insert(std::make_pair(ent, off));
+ if (p.second)
+ this->plt_size_ = off + this->plt_call_size(p.first);
+}
+
+template<int size, bool big_endian>
+void
+Stub_table<size, big_endian>::add_plt_call_entry(
+ const Sized_relobj_file<size, big_endian>* object,
+ unsigned int locsym_index,
+ unsigned int r_type,
+ Address addend)
+{
+ Plt_stub_ent ent(object, locsym_index, r_type, addend);
+ Address off = this->plt_size_;
+ std::pair<typename Plt_stub_entries::iterator, bool> p
+ = this->plt_call_stubs_.insert(std::make_pair(ent, off));
+ if (p.second)
+ this->plt_size_ = off + this->plt_call_size(p.first);
+}
+
+// Find a plt call stub.
+
+template<int size, bool big_endian>
+typename Stub_table<size, big_endian>::Address
+Stub_table<size, big_endian>::find_plt_call_entry(
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol* gsym,
+ unsigned int r_type,
+ Address addend) const
+{
+ Plt_stub_ent ent(object, gsym, r_type, addend);
+ typename Plt_stub_entries::const_iterator p = this->plt_call_stubs_.find(ent);
+ return p == this->plt_call_stubs_.end() ? invalid_address : p->second;
+}
+
+template<int size, bool big_endian>
+typename Stub_table<size, big_endian>::Address
+Stub_table<size, big_endian>::find_plt_call_entry(const Symbol* gsym) const
+{
+ Plt_stub_ent ent(gsym);
+ typename Plt_stub_entries::const_iterator p = this->plt_call_stubs_.find(ent);
+ return p == this->plt_call_stubs_.end() ? invalid_address : p->second;
+}
+
+template<int size, bool big_endian>
+typename Stub_table<size, big_endian>::Address
+Stub_table<size, big_endian>::find_plt_call_entry(
+ const Sized_relobj_file<size, big_endian>* object,
+ unsigned int locsym_index,
+ unsigned int r_type,
+ Address addend) const
+{
+ Plt_stub_ent ent(object, locsym_index, r_type, addend);
+ typename Plt_stub_entries::const_iterator p = this->plt_call_stubs_.find(ent);
+ return p == this->plt_call_stubs_.end() ? invalid_address : p->second;
+}
+
+template<int size, bool big_endian>
+typename Stub_table<size, big_endian>::Address
+Stub_table<size, big_endian>::find_plt_call_entry(
+ const Sized_relobj_file<size, big_endian>* object,
+ unsigned int locsym_index) const
+{
+ Plt_stub_ent ent(object, locsym_index);
+ typename Plt_stub_entries::const_iterator p = this->plt_call_stubs_.find(ent);
+ return p == this->plt_call_stubs_.end() ? invalid_address : p->second;
+}
+
+// Add a long branch stub if we don't already have one to given
+// destination.
+
+template<int size, bool big_endian>
+void
+Stub_table<size, big_endian>::add_long_branch_entry(
+ const Powerpc_relobj<size, big_endian>* object,
+ Address to)
+{
+ Branch_stub_ent ent(object, to);
+ Address off = this->branch_size_;
+ if (this->long_branch_stubs_.insert(std::make_pair(ent, off)).second)
+ {
+ unsigned int stub_size = this->branch_stub_size(to);
+ this->branch_size_ = off + stub_size;
+ if (size == 64 && stub_size != 4)
+ this->targ_->add_branch_lookup_table(to);
+ }
+}
+
+// Find long branch stub.
+
+template<int size, bool big_endian>
+typename Stub_table<size, big_endian>::Address
+Stub_table<size, big_endian>::find_long_branch_entry(
+ const Powerpc_relobj<size, big_endian>* object,
+ Address to) const
+{
+ Branch_stub_ent ent(object, to);
+ typename Branch_stub_entries::const_iterator p
+ = this->long_branch_stubs_.find(ent);
+ return p == this->long_branch_stubs_.end() ? invalid_address : p->second;
+}
+
+// A class to handle .glink.
+
+template<int size, bool big_endian>
+class Output_data_glink : public Output_section_data
+{
+ public:
+ static const int pltresolve_size = 16*4;
+
+ Output_data_glink(Target_powerpc<size, big_endian>* targ)
+ : Output_section_data(16), targ_(targ)
+ { }
+
+ void
+ add_eh_frame(Layout* layout)
+ {
+ if (!parameters->options().ld_generated_unwind_info())
+ return;
+
+ if (size == 64)
+ layout->add_eh_frame_for_plt(this,
+ Eh_cie<64>::eh_frame_cie,
+ sizeof (Eh_cie<64>::eh_frame_cie),
+ glink_eh_frame_fde_64,
+ sizeof (glink_eh_frame_fde_64));
+ else
+ {
+ // 32-bit .glink can use the default since the CIE return
+ // address reg, LR, is valid.
+ layout->add_eh_frame_for_plt(this,
+ Eh_cie<32>::eh_frame_cie,
+ sizeof (Eh_cie<32>::eh_frame_cie),
+ default_fde,
+ sizeof (default_fde));
+ // Except where LR is used in a PIC __glink_PLTresolve.
+ if (parameters->options().output_is_position_independent())
+ layout->add_eh_frame_for_plt(this,
+ Eh_cie<32>::eh_frame_cie,
+ sizeof (Eh_cie<32>::eh_frame_cie),
+ glink_eh_frame_fde_32,
+ sizeof (glink_eh_frame_fde_32));
+ }
+ }
+
+ protected:
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** glink")); }
+
+ private:
+ void
+ set_final_data_size();
+
+ // Write out .glink
+ void
+ do_write(Output_file*);
+
+ // Allows access to .got and .plt for do_write.
+ Target_powerpc<size, big_endian>* targ_;
+};
+
+template<int size, bool big_endian>
+void
+Output_data_glink<size, big_endian>::set_final_data_size()
+{
+ unsigned int count = this->targ_->plt_entry_count();
+ section_size_type total = 0;
+
+ if (count != 0)
+ {
+ if (size == 32)
+ {
+ // space for branch table
+ total += 4 * (count - 1);
+
+ total += -total & 15;
+ total += this->pltresolve_size;
+ }
+ else
+ {
+ total += this->pltresolve_size;
+
+ // space for branch table
+ total += 8 * count;
+ if (count > 0x8000)
+ total += 4 * (count - 0x8000);
+ }
+ }
+
+ this->set_data_size(total);
+}
+
+// Write out plt and long branch stub code.
+
+template<int size, bool big_endian>
+void
+Stub_table<size, big_endian>::do_write(Output_file* of)
+{
+ if (this->plt_call_stubs_.empty()
+ && this->long_branch_stubs_.empty())
+ return;
+
+ const section_size_type start_off = this->offset();
+ const section_size_type off = this->stub_offset();
+ const section_size_type oview_size =
+ convert_to_section_size_type(this->data_size() - (off - start_off));
+ unsigned char* const oview = of->get_output_view(off, oview_size);
+ unsigned char* p;
+
+ if (size == 64)
+ {
+ const Output_data_got_powerpc<size, big_endian>* got
+ = this->targ_->got_section();
+ Address got_os_addr = got->output_section()->address();
+
+ if (!this->plt_call_stubs_.empty())
+ {
+ // The base address of the .plt section.
+ Address plt_base = this->targ_->plt_section()->address();
+ Address iplt_base = invalid_address;
+
+ // Write out plt call stubs.
+ typename Plt_stub_entries::const_iterator cs;
+ for (cs = this->plt_call_stubs_.begin();
+ cs != this->plt_call_stubs_.end();
+ ++cs)
+ {
+ bool is_iplt;
+ Address pltoff = this->plt_off(cs, &is_iplt);
+ Address plt_addr = pltoff;
+ if (is_iplt)
+ {
+ if (iplt_base == invalid_address)
+ iplt_base = this->targ_->iplt_section()->address();
+ plt_addr += iplt_base;
+ }
+ else
+ plt_addr += plt_base;
+ const Powerpc_relobj<size, big_endian>* ppcobj = static_cast
+ <const Powerpc_relobj<size, big_endian>*>(cs->first.object_);
+ Address got_addr = got_os_addr + ppcobj->toc_base_offset();
+ Address off = plt_addr - got_addr;
+
+ if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
+ gold_error(_("%s: linkage table error against `%s'"),
+ cs->first.object_->name().c_str(),
+ cs->first.sym_->demangled_name().c_str());
+
+ bool static_chain = parameters->options().plt_static_chain();
+ bool thread_safe = this->targ_->plt_thread_safe();
+ bool use_fake_dep = false;
+ Address cmp_branch_off = 0;
+ if (thread_safe)
+ {
+ unsigned int pltindex
+ = ((pltoff - this->targ_->first_plt_entry_offset())
+ / this->targ_->plt_entry_size());
+ Address glinkoff
+ = (this->targ_->glink_section()->pltresolve_size
+ + pltindex * 8);
+ if (pltindex > 32768)
+ glinkoff += (pltindex - 32768) * 4;
+ Address to
+ = this->targ_->glink_section()->address() + glinkoff;
+ Address from
+ = (this->stub_address() + cs->second + 24
+ + 4 * (ha(off) != 0)
+ + 4 * (ha(off + 8 + 8 * static_chain) != ha(off))
+ + 4 * static_chain);
+ cmp_branch_off = to - from;
+ use_fake_dep = cmp_branch_off + (1 << 25) >= (1 << 26);
+ }
+
+ p = oview + cs->second;
+ if (ha(off) != 0)
+ {
+ write_insn<big_endian>(p, std_2_1 + 40), p += 4;
+ write_insn<big_endian>(p, addis_12_2 + ha(off)), p += 4;
+ write_insn<big_endian>(p, ld_11_12 + l(off)), p += 4;
+ if (ha(off + 8 + 8 * static_chain) != ha(off))
+ {
+ write_insn<big_endian>(p, addi_12_12 + l(off)), p += 4;
+ off = 0;
+ }
+ write_insn<big_endian>(p, mtctr_11), p += 4;
+ if (use_fake_dep)
+ {
+ write_insn<big_endian>(p, xor_11_11_11), p += 4;
+ write_insn<big_endian>(p, add_12_12_11), p += 4;
+ }
+ write_insn<big_endian>(p, ld_2_12 + l(off + 8)), p += 4;
+ if (static_chain)
+ write_insn<big_endian>(p, ld_11_12 + l(off + 16)), p += 4;
+ }
+ else
+ {
+ write_insn<big_endian>(p, std_2_1 + 40), p += 4;
+ write_insn<big_endian>(p, ld_11_2 + l(off)), p += 4;
+ if (ha(off + 8 + 8 * static_chain) != ha(off))
+ {
+ write_insn<big_endian>(p, addi_2_2 + l(off)), p += 4;
+ off = 0;
+ }
+ write_insn<big_endian>(p, mtctr_11), p += 4;
+ if (use_fake_dep)
+ {
+ write_insn<big_endian>(p, xor_11_11_11), p += 4;
+ write_insn<big_endian>(p, add_2_2_11), p += 4;
+ }
+ if (static_chain)
+ write_insn<big_endian>(p, ld_11_2 + l(off + 16)), p += 4;
+ write_insn<big_endian>(p, ld_2_2 + l(off + 8)), p += 4;
+ }
+ if (thread_safe && !use_fake_dep)
+ {
+ write_insn<big_endian>(p, cmpldi_2_0), p += 4;
+ write_insn<big_endian>(p, bnectr_p4), p += 4;
+ write_insn<big_endian>(p, b | (cmp_branch_off & 0x3fffffc));
+ }
+ else
+ write_insn<big_endian>(p, bctr);
+ }
+ }
+
+ // Write out long branch stubs.
+ typename Branch_stub_entries::const_iterator bs;
+ for (bs = this->long_branch_stubs_.begin();
+ bs != this->long_branch_stubs_.end();
+ ++bs)
+ {
+ p = oview + this->plt_size_ + bs->second;
+ Address loc = this->stub_address() + this->plt_size_ + bs->second;
+ Address delta = bs->first.dest_ - loc;
+ if (delta + (1 << 25) < 2 << 25)
+ write_insn<big_endian>(p, b | (delta & 0x3fffffc));
+ else
+ {
+ Address brlt_addr
+ = this->targ_->find_branch_lookup_table(bs->first.dest_);
+ gold_assert(brlt_addr != invalid_address);
+ brlt_addr += this->targ_->brlt_section()->address();
+ Address got_addr = got_os_addr + bs->first.toc_base_off_;
+ Address brltoff = brlt_addr - got_addr;
+ if (ha(brltoff) == 0)
+ {
+ write_insn<big_endian>(p, ld_11_2 + l(brltoff)), p += 4;
+ }
+ else
+ {
+ write_insn<big_endian>(p, addis_12_2 + ha(brltoff)), p += 4;
+ write_insn<big_endian>(p, ld_11_12 + l(brltoff)), p += 4;
+ }
+ write_insn<big_endian>(p, mtctr_11), p += 4;
+ write_insn<big_endian>(p, bctr);
+ }
+ }
+ }
+ else
+ {
+ if (!this->plt_call_stubs_.empty())
+ {
+ // The base address of the .plt section.
+ Address plt_base = this->targ_->plt_section()->address();
+ Address iplt_base = invalid_address;
+ // The address of _GLOBAL_OFFSET_TABLE_.
+ Address g_o_t = invalid_address;
+
+ // Write out plt call stubs.
+ typename Plt_stub_entries::const_iterator cs;
+ for (cs = this->plt_call_stubs_.begin();
+ cs != this->plt_call_stubs_.end();
+ ++cs)
+ {
+ bool is_iplt;
+ Address plt_addr = this->plt_off(cs, &is_iplt);
+ if (is_iplt)
+ {
+ if (iplt_base == invalid_address)
+ iplt_base = this->targ_->iplt_section()->address();
+ plt_addr += iplt_base;
+ }
+ else
+ plt_addr += plt_base;
+
+ p = oview + cs->second;
+ if (parameters->options().output_is_position_independent())
+ {
+ Address got_addr;
+ const Powerpc_relobj<size, big_endian>* ppcobj
+ = (static_cast<const Powerpc_relobj<size, big_endian>*>
+ (cs->first.object_));
+ if (ppcobj != NULL && cs->first.addend_ >= 32768)
+ {
+ unsigned int got2 = ppcobj->got2_shndx();
+ got_addr = ppcobj->get_output_section_offset(got2);
+ gold_assert(got_addr != invalid_address);
+ got_addr += (ppcobj->output_section(got2)->address()
+ + cs->first.addend_);
+ }
+ else
+ {
+ if (g_o_t == invalid_address)
+ {
+ const Output_data_got_powerpc<size, big_endian>* got
+ = this->targ_->got_section();
+ g_o_t = got->address() + got->g_o_t();
+ }
+ got_addr = g_o_t;
+ }
+
+ Address off = plt_addr - got_addr;
+ if (ha(off) == 0)
+ {
+ write_insn<big_endian>(p + 0, lwz_11_30 + l(off));
+ write_insn<big_endian>(p + 4, mtctr_11);
+ write_insn<big_endian>(p + 8, bctr);
+ }
+ else
+ {
+ write_insn<big_endian>(p + 0, addis_11_30 + ha(off));
+ write_insn<big_endian>(p + 4, lwz_11_11 + l(off));
+ write_insn<big_endian>(p + 8, mtctr_11);
+ write_insn<big_endian>(p + 12, bctr);
+ }
+ }
+ else
+ {
+ write_insn<big_endian>(p + 0, lis_11 + ha(plt_addr));
+ write_insn<big_endian>(p + 4, lwz_11_11 + l(plt_addr));
+ write_insn<big_endian>(p + 8, mtctr_11);
+ write_insn<big_endian>(p + 12, bctr);
+ }
+ }
+ }
+
+ // Write out long branch stubs.
+ typename Branch_stub_entries::const_iterator bs;
+ for (bs = this->long_branch_stubs_.begin();
+ bs != this->long_branch_stubs_.end();
+ ++bs)
+ {
+ p = oview + this->plt_size_ + bs->second;
+ Address loc = this->stub_address() + this->plt_size_ + bs->second;
+ Address delta = bs->first.dest_ - loc;
+ if (delta + (1 << 25) < 2 << 25)
+ write_insn<big_endian>(p, b | (delta & 0x3fffffc));
+ else if (!parameters->options().output_is_position_independent())
+ {
+ write_insn<big_endian>(p + 0, lis_12 + ha(bs->first.dest_));
+ write_insn<big_endian>(p + 4, addi_12_12 + l(bs->first.dest_));
+ write_insn<big_endian>(p + 8, mtctr_12);
+ write_insn<big_endian>(p + 12, bctr);
+ }
+ else
+ {
+ delta -= 8;
+ write_insn<big_endian>(p + 0, mflr_0);
+ write_insn<big_endian>(p + 4, bcl_20_31);
+ write_insn<big_endian>(p + 8, mflr_12);
+ write_insn<big_endian>(p + 12, addis_12_12 + ha(delta));
+ write_insn<big_endian>(p + 16, addi_12_12 + l(delta));
+ write_insn<big_endian>(p + 20, mtlr_0);
+ write_insn<big_endian>(p + 24, mtctr_12);
+ write_insn<big_endian>(p + 28, bctr);
+ }
+ }
+ }
+}
+
+// Write out .glink.
+
+template<int size, bool big_endian>
+void
+Output_data_glink<size, big_endian>::do_write(Output_file* of)
+{
+ const section_size_type off = this->offset();
+ const section_size_type oview_size =
+ convert_to_section_size_type(this->data_size());
+ unsigned char* const oview = of->get_output_view(off, oview_size);
+ unsigned char* p;
+
+ // The base address of the .plt section.
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ Address plt_base = this->targ_->plt_section()->address();
+
+ if (size == 64)
+ {
+ // Write pltresolve stub.
+ p = oview;
+ Address after_bcl = this->address() + 16;
+ Address pltoff = plt_base - after_bcl;
+
+ elfcpp::Swap<64, big_endian>::writeval(p, pltoff), p += 8;
+
+ write_insn<big_endian>(p, mflr_12), p += 4;
+ write_insn<big_endian>(p, bcl_20_31), p += 4;
+ write_insn<big_endian>(p, mflr_11), p += 4;
+ write_insn<big_endian>(p, ld_2_11 + l(-16)), p += 4;
+ write_insn<big_endian>(p, mtlr_12), p += 4;
+ write_insn<big_endian>(p, add_12_2_11), p += 4;
+ write_insn<big_endian>(p, ld_11_12 + 0), p += 4;
+ write_insn<big_endian>(p, ld_2_12 + 8), p += 4;
+ write_insn<big_endian>(p, mtctr_11), p += 4;
+ write_insn<big_endian>(p, ld_11_12 + 16), p += 4;
+ write_insn<big_endian>(p, bctr), p += 4;
+ while (p < oview + this->pltresolve_size)
+ write_insn<big_endian>(p, nop), p += 4;
+
+ // Write lazy link call stubs.
+ uint32_t indx = 0;
+ while (p < oview + oview_size)
+ {
+ if (indx < 0x8000)
+ {
+ write_insn<big_endian>(p, li_0_0 + indx), p += 4;
+ }
+ else
+ {
+ write_insn<big_endian>(p, lis_0_0 + hi(indx)), p += 4;
+ write_insn<big_endian>(p, ori_0_0_0 + l(indx)), p += 4;
+ }
+ uint32_t branch_off = 8 - (p - oview);
+ write_insn<big_endian>(p, b + (branch_off & 0x3fffffc)), p += 4;
+ indx++;
+ }
+ }
+ else
+ {
+ const Output_data_got_powerpc<size, big_endian>* got
+ = this->targ_->got_section();
+ // The address of _GLOBAL_OFFSET_TABLE_.
+ Address g_o_t = got->address() + got->g_o_t();
+
+ // Write out pltresolve branch table.
+ p = oview;
+ unsigned int the_end = oview_size - this->pltresolve_size;
+ unsigned char* end_p = oview + the_end;
+ while (p < end_p - 8 * 4)
+ write_insn<big_endian>(p, b + end_p - p), p += 4;
+ while (p < end_p)
+ write_insn<big_endian>(p, nop), p += 4;
+
+ // Write out pltresolve call stub.
+ if (parameters->options().output_is_position_independent())
+ {
+ Address res0_off = 0;
+ Address after_bcl_off = the_end + 12;
+ Address bcl_res0 = after_bcl_off - res0_off;
+
+ write_insn<big_endian>(p + 0, addis_11_11 + ha(bcl_res0));
+ write_insn<big_endian>(p + 4, mflr_0);
+ write_insn<big_endian>(p + 8, bcl_20_31);
+ write_insn<big_endian>(p + 12, addi_11_11 + l(bcl_res0));
+ write_insn<big_endian>(p + 16, mflr_12);
+ write_insn<big_endian>(p + 20, mtlr_0);
+ write_insn<big_endian>(p + 24, sub_11_11_12);
+
+ Address got_bcl = g_o_t + 4 - (after_bcl_off + this->address());
+
+ write_insn<big_endian>(p + 28, addis_12_12 + ha(got_bcl));
+ if (ha(got_bcl) == ha(got_bcl + 4))
+ {
+ write_insn<big_endian>(p + 32, lwz_0_12 + l(got_bcl));
+ write_insn<big_endian>(p + 36, lwz_12_12 + l(got_bcl + 4));
+ }
+ else
+ {
+ write_insn<big_endian>(p + 32, lwzu_0_12 + l(got_bcl));
+ write_insn<big_endian>(p + 36, lwz_12_12 + 4);
+ }
+ write_insn<big_endian>(p + 40, mtctr_0);
+ write_insn<big_endian>(p + 44, add_0_11_11);
+ write_insn<big_endian>(p + 48, add_11_0_11);
+ write_insn<big_endian>(p + 52, bctr);
+ write_insn<big_endian>(p + 56, nop);
+ write_insn<big_endian>(p + 60, nop);
+ }
+ else
+ {
+ Address res0 = this->address();
+
+ write_insn<big_endian>(p + 0, lis_12 + ha(g_o_t + 4));
+ write_insn<big_endian>(p + 4, addis_11_11 + ha(-res0));
+ if (ha(g_o_t + 4) == ha(g_o_t + 8))
+ write_insn<big_endian>(p + 8, lwz_0_12 + l(g_o_t + 4));
+ else
+ write_insn<big_endian>(p + 8, lwzu_0_12 + l(g_o_t + 4));
+ write_insn<big_endian>(p + 12, addi_11_11 + l(-res0));
+ write_insn<big_endian>(p + 16, mtctr_0);
+ write_insn<big_endian>(p + 20, add_0_11_11);
+ if (ha(g_o_t + 4) == ha(g_o_t + 8))
+ write_insn<big_endian>(p + 24, lwz_12_12 + l(g_o_t + 8));
+ else
+ write_insn<big_endian>(p + 24, lwz_12_12 + 4);
+ write_insn<big_endian>(p + 28, add_11_0_11);
+ write_insn<big_endian>(p + 32, bctr);
+ write_insn<big_endian>(p + 36, nop);
+ write_insn<big_endian>(p + 40, nop);
+ write_insn<big_endian>(p + 44, nop);
+ write_insn<big_endian>(p + 48, nop);
+ write_insn<big_endian>(p + 52, nop);
+ write_insn<big_endian>(p + 56, nop);
+ write_insn<big_endian>(p + 60, nop);
+ }
+ p += 64;
+ }
+
+ of->write_output_view(off, oview_size, oview);
+}
+
+
+// A class to handle linker generated save/restore functions.
+
+template<int size, bool big_endian>
+class Output_data_save_res : public Output_section_data_build
+{
+ public:
+ Output_data_save_res(Symbol_table* symtab);
+
+ protected:
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** save/restore")); }
+
+ void
+ do_write(Output_file*);
+
+ private:
+ // The maximum size of save/restore contents.
+ static const unsigned int savres_max = 218*4;
+
+ void
+ savres_define(Symbol_table* symtab,
+ const char *name,
+ unsigned int lo, unsigned int hi,
+ unsigned char* write_ent(unsigned char*, int),
+ unsigned char* write_tail(unsigned char*, int));
+
+ unsigned char *contents_;
+};
+
+template<bool big_endian>
+static unsigned char*
+savegpr0(unsigned char* p, int r)
+{
+ uint32_t insn = std_0_1 + (r << 21) + (1 << 16) - (32 - r) * 8;
+ write_insn<big_endian>(p, insn);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+savegpr0_tail(unsigned char* p, int r)
+{
+ p = savegpr0<big_endian>(p, r);
+ uint32_t insn = std_0_1 + 16;
+ write_insn<big_endian>(p, insn);
+ p = p + 4;
+ write_insn<big_endian>(p, blr);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+restgpr0(unsigned char* p, int r)
+{
+ uint32_t insn = ld_0_1 + (r << 21) + (1 << 16) - (32 - r) * 8;
+ write_insn<big_endian>(p, insn);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+restgpr0_tail(unsigned char* p, int r)
+{
+ uint32_t insn = ld_0_1 + 16;
+ write_insn<big_endian>(p, insn);
+ p = p + 4;
+ p = restgpr0<big_endian>(p, r);
+ write_insn<big_endian>(p, mtlr_0);
+ p = p + 4;
+ if (r == 29)
+ {
+ p = restgpr0<big_endian>(p, 30);
+ p = restgpr0<big_endian>(p, 31);
+ }
+ write_insn<big_endian>(p, blr);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+savegpr1(unsigned char* p, int r)
+{
+ uint32_t insn = std_0_12 + (r << 21) + (1 << 16) - (32 - r) * 8;
+ write_insn<big_endian>(p, insn);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+savegpr1_tail(unsigned char* p, int r)
+{
+ p = savegpr1<big_endian>(p, r);
+ write_insn<big_endian>(p, blr);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+restgpr1(unsigned char* p, int r)
+{
+ uint32_t insn = ld_0_12 + (r << 21) + (1 << 16) - (32 - r) * 8;
+ write_insn<big_endian>(p, insn);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+restgpr1_tail(unsigned char* p, int r)
+{
+ p = restgpr1<big_endian>(p, r);
+ write_insn<big_endian>(p, blr);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+savefpr(unsigned char* p, int r)
+{
+ uint32_t insn = stfd_0_1 + (r << 21) + (1 << 16) - (32 - r) * 8;
+ write_insn<big_endian>(p, insn);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+savefpr0_tail(unsigned char* p, int r)
+{
+ p = savefpr<big_endian>(p, r);
+ write_insn<big_endian>(p, std_0_1 + 16);
+ p = p + 4;
+ write_insn<big_endian>(p, blr);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+restfpr(unsigned char* p, int r)
+{
+ uint32_t insn = lfd_0_1 + (r << 21) + (1 << 16) - (32 - r) * 8;
+ write_insn<big_endian>(p, insn);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+restfpr0_tail(unsigned char* p, int r)
+{
+ write_insn<big_endian>(p, ld_0_1 + 16);
+ p = p + 4;
+ p = restfpr<big_endian>(p, r);
+ write_insn<big_endian>(p, mtlr_0);
+ p = p + 4;
+ if (r == 29)
+ {
+ p = restfpr<big_endian>(p, 30);
+ p = restfpr<big_endian>(p, 31);
+ }
+ write_insn<big_endian>(p, blr);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+savefpr1_tail(unsigned char* p, int r)
+{
+ p = savefpr<big_endian>(p, r);
+ write_insn<big_endian>(p, blr);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+restfpr1_tail(unsigned char* p, int r)
+{
+ p = restfpr<big_endian>(p, r);
+ write_insn<big_endian>(p, blr);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+savevr(unsigned char* p, int r)
+{
+ uint32_t insn = li_12_0 + (1 << 16) - (32 - r) * 16;
+ write_insn<big_endian>(p, insn);
+ p = p + 4;
+ insn = stvx_0_12_0 + (r << 21);
+ write_insn<big_endian>(p, insn);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+savevr_tail(unsigned char* p, int r)
+{
+ p = savevr<big_endian>(p, r);
+ write_insn<big_endian>(p, blr);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+restvr(unsigned char* p, int r)
+{
+ uint32_t insn = li_12_0 + (1 << 16) - (32 - r) * 16;
+ write_insn<big_endian>(p, insn);
+ p = p + 4;
+ insn = lvx_0_12_0 + (r << 21);
+ write_insn<big_endian>(p, insn);
+ return p + 4;
+}
+
+template<bool big_endian>
+static unsigned char*
+restvr_tail(unsigned char* p, int r)
+{
+ p = restvr<big_endian>(p, r);
+ write_insn<big_endian>(p, blr);
+ return p + 4;
+}
+
+
+template<int size, bool big_endian>
+Output_data_save_res<size, big_endian>::Output_data_save_res(
+ Symbol_table* symtab)
+ : Output_section_data_build(4),
+ contents_(NULL)
+{
+ this->savres_define(symtab,
+ "_savegpr0_", 14, 31,
+ savegpr0<big_endian>, savegpr0_tail<big_endian>);
+ this->savres_define(symtab,
+ "_restgpr0_", 14, 29,
+ restgpr0<big_endian>, restgpr0_tail<big_endian>);
+ this->savres_define(symtab,
+ "_restgpr0_", 30, 31,
+ restgpr0<big_endian>, restgpr0_tail<big_endian>);
+ this->savres_define(symtab,
+ "_savegpr1_", 14, 31,
+ savegpr1<big_endian>, savegpr1_tail<big_endian>);
+ this->savres_define(symtab,
+ "_restgpr1_", 14, 31,
+ restgpr1<big_endian>, restgpr1_tail<big_endian>);
+ this->savres_define(symtab,
+ "_savefpr_", 14, 31,
+ savefpr<big_endian>, savefpr0_tail<big_endian>);
+ this->savres_define(symtab,
+ "_restfpr_", 14, 29,
+ restfpr<big_endian>, restfpr0_tail<big_endian>);
+ this->savres_define(symtab,
+ "_restfpr_", 30, 31,
+ restfpr<big_endian>, restfpr0_tail<big_endian>);
+ this->savres_define(symtab,
+ "._savef", 14, 31,
+ savefpr<big_endian>, savefpr1_tail<big_endian>);
+ this->savres_define(symtab,
+ "._restf", 14, 31,
+ restfpr<big_endian>, restfpr1_tail<big_endian>);
+ this->savres_define(symtab,
+ "_savevr_", 20, 31,
+ savevr<big_endian>, savevr_tail<big_endian>);
+ this->savres_define(symtab,
+ "_restvr_", 20, 31,
+ restvr<big_endian>, restvr_tail<big_endian>);
+}
+
+template<int size, bool big_endian>
+void
+Output_data_save_res<size, big_endian>::savres_define(
+ Symbol_table* symtab,
+ const char *name,
+ unsigned int lo, unsigned int hi,
+ unsigned char* write_ent(unsigned char*, int),
+ unsigned char* write_tail(unsigned char*, int))
+{
+ size_t len = strlen(name);
+ bool writing = false;
+ char sym[16];
+
+ memcpy(sym, name, len);
+ sym[len + 2] = 0;
+
+ for (unsigned int i = lo; i <= hi; i++)
+ {
+ sym[len + 0] = i / 10 + '0';
+ sym[len + 1] = i % 10 + '0';
+ Symbol* gsym = symtab->lookup(sym);
+ bool refd = gsym != NULL && gsym->is_undefined();
+ writing = writing || refd;
+ if (writing)
+ {
+ if (this->contents_ == NULL)
+ this->contents_ = new unsigned char[this->savres_max];
+
+ section_size_type value = this->current_data_size();
+ unsigned char* p = this->contents_ + value;
+ if (i != hi)
+ p = write_ent(p, i);
+ else
+ p = write_tail(p, i);
+ section_size_type cur_size = p - this->contents_;
+ this->set_current_data_size(cur_size);
+ if (refd)
+ symtab->define_in_output_data(sym, NULL, Symbol_table::PREDEFINED,
+ this, value, cur_size - value,
+ elfcpp::STT_FUNC, elfcpp::STB_GLOBAL,
+ elfcpp::STV_HIDDEN, 0, false, false);
+ }
+ }
+}
+
+// Write out save/restore.
+
+template<int size, bool big_endian>
+void
+Output_data_save_res<size, big_endian>::do_write(Output_file* of)
+{
+ const section_size_type off = this->offset();
+ const section_size_type oview_size =
+ convert_to_section_size_type(this->data_size());
+ unsigned char* const oview = of->get_output_view(off, oview_size);
+ memcpy(oview, this->contents_, oview_size);
+ of->write_output_view(off, oview_size, oview);
+}
+
+
+// Create the glink section.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::make_glink_section(Layout* layout)
+{
+ if (this->glink_ == NULL)
+ {
+ this->glink_ = new Output_data_glink<size, big_endian>(this);
+ this->glink_->add_eh_frame(layout);
+ layout->add_output_section_data(".text", elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR,
+ this->glink_, ORDER_TEXT, false);
+ }
+}
+
+// Create a PLT entry for a global symbol.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::make_plt_entry(Symbol_table* symtab,
+ Layout* layout,
+ Symbol* gsym)
+{
+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
+ && gsym->can_use_relative_reloc(false))
+ {
+ if (this->iplt_ == NULL)
+ this->make_iplt_section(symtab, layout);
+ this->iplt_->add_ifunc_entry(gsym);
+ }
+ else
+ {
+ if (this->plt_ == NULL)
+ this->make_plt_section(symtab, layout);
+ this->plt_->add_entry(gsym);
+ }
+}
+
+// Make a PLT entry for a local STT_GNU_IFUNC symbol.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::make_local_ifunc_plt_entry(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* relobj,
+ unsigned int r_sym)
+{
+ if (this->iplt_ == NULL)
+ this->make_iplt_section(symtab, layout);
+ this->iplt_->add_local_ifunc_entry(relobj, r_sym);
+}
+
+// Return the number of entries in the PLT.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::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<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::first_plt_entry_offset() const
+{
+ return this->plt_->first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::plt_entry_size() const
+{
+ return Output_data_plt_powerpc<size, big_endian>::get_plt_entry_size();
+}
+
+// Create a GOT entry for local dynamic __tls_get_addr calls.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::tlsld_got_offset(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object)
+{
+ if (this->tlsld_got_offset_ == -1U)
+ {
+ gold_assert(symtab != NULL && layout != NULL && object != NULL);
+ Reloc_section* rela_dyn = this->rela_dyn_section(layout);
+ Output_data_got_powerpc<size, big_endian>* got
+ = this->got_section(symtab, layout);
+ unsigned int got_offset = got->add_constant_pair(0, 0);
+ rela_dyn->add_local(object, 0, elfcpp::R_POWERPC_DTPMOD, got,
+ got_offset, 0);
+ this->tlsld_got_offset_ = got_offset;
+ }
+ return this->tlsld_got_offset_;
+}
+
+// Get the Reference_flags for a particular relocation.
+
+template<int size, bool big_endian>
+int
+Target_powerpc<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
+{
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_NONE:
+ case elfcpp::R_POWERPC_GNU_VTINHERIT:
+ case elfcpp::R_POWERPC_GNU_VTENTRY:
+ case elfcpp::R_PPC64_TOC:
+ // No symbol reference.
+ return 0;
+
+ case elfcpp::R_PPC64_ADDR64:
+ case elfcpp::R_PPC64_UADDR64:
+ case elfcpp::R_POWERPC_ADDR32:
+ case elfcpp::R_POWERPC_UADDR32:
+ case elfcpp::R_POWERPC_ADDR16:
+ case elfcpp::R_POWERPC_UADDR16:
+ case elfcpp::R_POWERPC_ADDR16_LO:
+ case elfcpp::R_POWERPC_ADDR16_HI:
+ case elfcpp::R_POWERPC_ADDR16_HA:
+ return Symbol::ABSOLUTE_REF;
+
+ case elfcpp::R_POWERPC_ADDR24:
+ case elfcpp::R_POWERPC_ADDR14:
+ case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
+ case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
+ return Symbol::FUNCTION_CALL | Symbol::ABSOLUTE_REF;
+
+ case elfcpp::R_PPC64_REL64:
+ case elfcpp::R_POWERPC_REL32:
+ case elfcpp::R_PPC_LOCAL24PC:
+ case elfcpp::R_POWERPC_REL16:
+ case elfcpp::R_POWERPC_REL16_LO:
+ case elfcpp::R_POWERPC_REL16_HI:
+ case elfcpp::R_POWERPC_REL16_HA:
+ return Symbol::RELATIVE_REF;
+
+ case elfcpp::R_POWERPC_REL24:
+ case elfcpp::R_PPC_PLTREL24:
+ case elfcpp::R_POWERPC_REL14:
+ case elfcpp::R_POWERPC_REL14_BRTAKEN:
+ case elfcpp::R_POWERPC_REL14_BRNTAKEN:
+ return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+
+ case elfcpp::R_POWERPC_GOT16:
+ case elfcpp::R_POWERPC_GOT16_LO:
+ case elfcpp::R_POWERPC_GOT16_HI:
+ case elfcpp::R_POWERPC_GOT16_HA:
+ case elfcpp::R_PPC64_GOT16_DS:
+ case elfcpp::R_PPC64_GOT16_LO_DS:
+ case elfcpp::R_PPC64_TOC16:
+ case elfcpp::R_PPC64_TOC16_LO:
+ case elfcpp::R_PPC64_TOC16_HI:
+ case elfcpp::R_PPC64_TOC16_HA:
+ case elfcpp::R_PPC64_TOC16_DS:
+ case elfcpp::R_PPC64_TOC16_LO_DS:
+ // Absolute in GOT.
+ return Symbol::ABSOLUTE_REF;
+
+ case elfcpp::R_POWERPC_GOT_TPREL16:
+ case elfcpp::R_POWERPC_TLS:
+ return Symbol::TLS_REF;
+
+ case elfcpp::R_POWERPC_COPY:
+ case elfcpp::R_POWERPC_GLOB_DAT:
+ case elfcpp::R_POWERPC_JMP_SLOT:
+ case elfcpp::R_POWERPC_RELATIVE:
+ case elfcpp::R_POWERPC_DTPMOD:
+ default:
+ // Not expected. We will give an error later.
+ return 0;
+ }
+}
+
+// Report an unsupported relocation against a local symbol.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::Scan::unsupported_reloc_local(
+ Sized_relobj_file<size, 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.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::Scan::check_non_pic(Relobj* object,
+ unsigned int r_type)
+{
+ gold_assert(r_type != elfcpp::R_POWERPC_NONE);
+
+ // These are the relocation types supported by glibc for both 32-bit
+ // and 64-bit powerpc.
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_NONE:
+ case elfcpp::R_POWERPC_RELATIVE:
+ case elfcpp::R_POWERPC_GLOB_DAT:
+ case elfcpp::R_POWERPC_DTPMOD:
+ case elfcpp::R_POWERPC_DTPREL:
+ case elfcpp::R_POWERPC_TPREL:
+ case elfcpp::R_POWERPC_JMP_SLOT:
+ case elfcpp::R_POWERPC_COPY:
+ case elfcpp::R_POWERPC_IRELATIVE:
+ case elfcpp::R_POWERPC_ADDR32:
+ case elfcpp::R_POWERPC_UADDR32:
+ case elfcpp::R_POWERPC_ADDR24:
+ case elfcpp::R_POWERPC_ADDR16:
+ case elfcpp::R_POWERPC_UADDR16:
+ case elfcpp::R_POWERPC_ADDR16_LO:
+ case elfcpp::R_POWERPC_ADDR16_HI:
+ case elfcpp::R_POWERPC_ADDR16_HA:
+ case elfcpp::R_POWERPC_ADDR14:
+ case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
+ case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
+ case elfcpp::R_POWERPC_REL32:
+ case elfcpp::R_POWERPC_REL24:
+ case elfcpp::R_POWERPC_TPREL16:
+ case elfcpp::R_POWERPC_TPREL16_LO:
+ case elfcpp::R_POWERPC_TPREL16_HI:
+ case elfcpp::R_POWERPC_TPREL16_HA:
+ return;
+
+ default:
+ break;
+ }
+
+ if (size == 64)
+ {
+ switch (r_type)
+ {
+ // These are the relocation types supported only on 64-bit.
+ case elfcpp::R_PPC64_ADDR64:
+ case elfcpp::R_PPC64_UADDR64:
+ case elfcpp::R_PPC64_JMP_IREL:
+ case elfcpp::R_PPC64_ADDR16_DS:
+ case elfcpp::R_PPC64_ADDR16_LO_DS:
+ case elfcpp::R_PPC64_ADDR16_HIGHER:
+ case elfcpp::R_PPC64_ADDR16_HIGHEST:
+ case elfcpp::R_PPC64_ADDR16_HIGHERA:
+ case elfcpp::R_PPC64_ADDR16_HIGHESTA:
+ case elfcpp::R_PPC64_REL64:
+ case elfcpp::R_POWERPC_ADDR30:
+ case elfcpp::R_PPC64_TPREL16_DS:
+ case elfcpp::R_PPC64_TPREL16_LO_DS:
+ case elfcpp::R_PPC64_TPREL16_HIGHER:
+ case elfcpp::R_PPC64_TPREL16_HIGHEST:
+ case elfcpp::R_PPC64_TPREL16_HIGHERA:
+ case elfcpp::R_PPC64_TPREL16_HIGHESTA:
+ return;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (r_type)
+ {
+ // These are the relocation types supported only on 32-bit.
+ // ??? glibc ld.so doesn't need to support these.
+ case elfcpp::R_POWERPC_DTPREL16:
+ case elfcpp::R_POWERPC_DTPREL16_LO:
+ case elfcpp::R_POWERPC_DTPREL16_HI:
+ case elfcpp::R_POWERPC_DTPREL16_HA:
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ // 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;
+ gold_assert(parameters->options().output_is_position_independent());
+ object->error(_("requires unsupported dynamic reloc; "
+ "recompile with -fPIC"));
+ this->issued_non_pic_error_ = true;
+ return;
+}
+
+// Return whether we need to make a PLT entry for a relocation of the
+// given type against a STT_GNU_IFUNC symbol.
+
+template<int size, bool big_endian>
+bool
+Target_powerpc<size, big_endian>::Scan::reloc_needs_plt_for_ifunc(
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int r_type,
+ bool report_err)
+{
+ // In non-pic code any reference will resolve to the plt call stub
+ // for the ifunc symbol.
+ if (size == 32 && !parameters->options().output_is_position_independent())
+ return true;
+
+ switch (r_type)
+ {
+ // Word size refs from data sections are OK, but don't need a PLT entry.
+ case elfcpp::R_POWERPC_ADDR32:
+ case elfcpp::R_POWERPC_UADDR32:
+ if (size == 32)
+ return false;
+ break;
+
+ case elfcpp::R_PPC64_ADDR64:
+ case elfcpp::R_PPC64_UADDR64:
+ if (size == 64)
+ return false;
+ break;
+
+ // GOT refs are good, but also don't need a PLT entry.
+ case elfcpp::R_POWERPC_GOT16:
+ case elfcpp::R_POWERPC_GOT16_LO:
+ case elfcpp::R_POWERPC_GOT16_HI:
+ case elfcpp::R_POWERPC_GOT16_HA:
+ case elfcpp::R_PPC64_GOT16_DS:
+ case elfcpp::R_PPC64_GOT16_LO_DS:
+ return false;
+
+ // Function calls are good, and these do need a PLT entry.
+ case elfcpp::R_POWERPC_ADDR24:
+ case elfcpp::R_POWERPC_ADDR14:
+ case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
+ case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
+ case elfcpp::R_POWERPC_REL24:
+ case elfcpp::R_PPC_PLTREL24:
+ case elfcpp::R_POWERPC_REL14:
+ case elfcpp::R_POWERPC_REL14_BRTAKEN:
+ case elfcpp::R_POWERPC_REL14_BRNTAKEN:
+ return true;
+
+ default:
+ break;
+ }
+
+ // Anything else is a problem.
+ // If we are building a static executable, the libc startup function
+ // responsible for applying indirect function relocations is going
+ // to complain about the reloc type.
+ // If we are building a dynamic executable, we will have a text
+ // relocation. The dynamic loader will set the text segment
+ // writable and non-executable to apply text relocations. So we'll
+ // segfault when trying to run the indirection function to resolve
+ // the reloc.
+ if (report_err)
+ gold_error(_("%s: unsupported reloc %u for IFUNC symbol"),
+ object->name().c_str(), r_type);
+ return false;
+}
+
+// Scan a relocation for a local symbol.
+
+template<int size, bool big_endian>
+inline void
+Target_powerpc<size, big_endian>::Scan::local(
+ Symbol_table* symtab,
+ Layout* layout,
+ Target_powerpc<size, big_endian>* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, big_endian>& reloc,
+ unsigned int r_type,
+ const elfcpp::Sym<size, big_endian>& lsym,
+ bool is_discarded)
+{
+ this->maybe_skip_tls_get_addr_call(r_type, NULL);
+
+ if ((size == 64 && r_type == elfcpp::R_PPC64_TLSGD)
+ || (size == 32 && r_type == elfcpp::R_PPC_TLSGD))
+ {
+ this->expect_tls_get_addr_call();
+ const tls::Tls_optimization tls_type = target->optimize_tls_gd(true);
+ if (tls_type != tls::TLSOPT_NONE)
+ this->skip_next_tls_get_addr_call();
+ }
+ else if ((size == 64 && r_type == elfcpp::R_PPC64_TLSLD)
+ || (size == 32 && r_type == elfcpp::R_PPC_TLSLD))
+ {
+ this->expect_tls_get_addr_call();
+ const tls::Tls_optimization tls_type = target->optimize_tls_ld();
+ if (tls_type != tls::TLSOPT_NONE)
+ this->skip_next_tls_get_addr_call();
+ }
+
+ Powerpc_relobj<size, big_endian>* ppc_object
+ = static_cast<Powerpc_relobj<size, big_endian>*>(object);
+
+ if (is_discarded)
+ {
+ if (size == 64
+ && data_shndx == ppc_object->opd_shndx()
+ && r_type == elfcpp::R_PPC64_ADDR64)
+ ppc_object->set_opd_discard(reloc.get_r_offset());
+ return;
+ }
+
+ // A local STT_GNU_IFUNC symbol may require a PLT entry.
+ bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
+ if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type, true))
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ target->push_branch(ppc_object, data_shndx, reloc.get_r_offset(),
+ r_type, r_sym, reloc.get_r_addend());
+ target->make_local_ifunc_plt_entry(symtab, layout, object, r_sym);
+ }
+
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_NONE:
+ case elfcpp::R_POWERPC_GNU_VTINHERIT:
+ case elfcpp::R_POWERPC_GNU_VTENTRY:
+ case elfcpp::R_PPC64_TOCSAVE:
+ case elfcpp::R_PPC_EMB_MRKREF:
+ case elfcpp::R_POWERPC_TLS:
+ break;
+
+ case elfcpp::R_PPC64_TOC:
+ {
+ Output_data_got_powerpc<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ if (parameters->options().output_is_position_independent())
+ {
+ Address off = reloc.get_r_offset();
+ if (size == 64
+ && data_shndx == ppc_object->opd_shndx()
+ && ppc_object->get_opd_discard(off - 8))
+ break;
+
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ Powerpc_relobj<size, big_endian>* symobj = ppc_object;
+ rela_dyn->add_output_section_relative(got->output_section(),
+ elfcpp::R_POWERPC_RELATIVE,
+ output_section,
+ object, data_shndx, off,
+ symobj->toc_base_offset());
+ }
+ }
+ break;
+
+ case elfcpp::R_PPC64_ADDR64:
+ case elfcpp::R_PPC64_UADDR64:
+ case elfcpp::R_POWERPC_ADDR32:
+ case elfcpp::R_POWERPC_UADDR32:
+ case elfcpp::R_POWERPC_ADDR24:
+ case elfcpp::R_POWERPC_ADDR16:
+ case elfcpp::R_POWERPC_ADDR16_LO:
+ case elfcpp::R_POWERPC_ADDR16_HI:
+ case elfcpp::R_POWERPC_ADDR16_HA:
+ case elfcpp::R_POWERPC_UADDR16:
+ case elfcpp::R_PPC64_ADDR16_HIGHER:
+ case elfcpp::R_PPC64_ADDR16_HIGHERA:
+ case elfcpp::R_PPC64_ADDR16_HIGHEST:
+ case elfcpp::R_PPC64_ADDR16_HIGHESTA:
+ case elfcpp::R_PPC64_ADDR16_DS:
+ case elfcpp::R_PPC64_ADDR16_LO_DS:
+ case elfcpp::R_POWERPC_ADDR14:
+ case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
+ case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
+ // If building a shared library (or a position-independent
+ // executable), we need to create a dynamic relocation for
+ // this location.
+ if (parameters->options().output_is_position_independent()
+ || (size == 64 && is_ifunc))
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(symtab, layout,
+ is_ifunc);
+ if ((size == 32 && r_type == elfcpp::R_POWERPC_ADDR32)
+ || (size == 64 && r_type == elfcpp::R_PPC64_ADDR64))
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ unsigned int dynrel = (is_ifunc ? elfcpp::R_POWERPC_IRELATIVE
+ : elfcpp::R_POWERPC_RELATIVE);
+ rela_dyn->add_local_relative(object, r_sym, dynrel,
+ output_section, data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend(), false);
+ }
+ else
+ {
+ check_non_pic(object, r_type);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ rela_dyn->add_local(object, r_sym, r_type, output_section,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ }
+ break;
+
+ case elfcpp::R_POWERPC_REL24:
+ case elfcpp::R_PPC_PLTREL24:
+ case elfcpp::R_PPC_LOCAL24PC:
+ case elfcpp::R_POWERPC_REL14:
+ case elfcpp::R_POWERPC_REL14_BRTAKEN:
+ case elfcpp::R_POWERPC_REL14_BRNTAKEN:
+ if (!is_ifunc)
+ target->push_branch(ppc_object, data_shndx, reloc.get_r_offset(),
+ r_type, elfcpp::elf_r_sym<size>(reloc.get_r_info()),
+ reloc.get_r_addend());
+ break;
+
+ case elfcpp::R_PPC64_REL64:
+ case elfcpp::R_POWERPC_REL32:
+ case elfcpp::R_POWERPC_REL16:
+ case elfcpp::R_POWERPC_REL16_LO:
+ case elfcpp::R_POWERPC_REL16_HI:
+ case elfcpp::R_POWERPC_REL16_HA:
+ case elfcpp::R_POWERPC_SECTOFF:
+ case elfcpp::R_POWERPC_TPREL16:
+ case elfcpp::R_POWERPC_DTPREL16:
+ case elfcpp::R_POWERPC_SECTOFF_LO:
+ case elfcpp::R_POWERPC_TPREL16_LO:
+ case elfcpp::R_POWERPC_DTPREL16_LO:
+ case elfcpp::R_POWERPC_SECTOFF_HI:
+ case elfcpp::R_POWERPC_TPREL16_HI:
+ case elfcpp::R_POWERPC_DTPREL16_HI:
+ case elfcpp::R_POWERPC_SECTOFF_HA:
+ case elfcpp::R_POWERPC_TPREL16_HA:
+ case elfcpp::R_POWERPC_DTPREL16_HA:
+ case elfcpp::R_PPC64_DTPREL16_HIGHER:
+ case elfcpp::R_PPC64_TPREL16_HIGHER:
+ case elfcpp::R_PPC64_DTPREL16_HIGHERA:
+ case elfcpp::R_PPC64_TPREL16_HIGHERA:
+ case elfcpp::R_PPC64_DTPREL16_HIGHEST:
+ case elfcpp::R_PPC64_TPREL16_HIGHEST:
+ case elfcpp::R_PPC64_DTPREL16_HIGHESTA:
+ case elfcpp::R_PPC64_TPREL16_HIGHESTA:
+ case elfcpp::R_PPC64_TPREL16_DS:
+ case elfcpp::R_PPC64_TPREL16_LO_DS:
+ case elfcpp::R_PPC64_DTPREL16_DS:
+ case elfcpp::R_PPC64_DTPREL16_LO_DS:
+ case elfcpp::R_PPC64_SECTOFF_DS:
+ case elfcpp::R_PPC64_SECTOFF_LO_DS:
+ case elfcpp::R_PPC64_TLSGD:
+ case elfcpp::R_PPC64_TLSLD:
+ break;
+
+ case elfcpp::R_POWERPC_GOT16:
+ case elfcpp::R_POWERPC_GOT16_LO:
+ case elfcpp::R_POWERPC_GOT16_HI:
+ case elfcpp::R_POWERPC_GOT16_HA:
+ case elfcpp::R_PPC64_GOT16_DS:
+ case elfcpp::R_PPC64_GOT16_LO_DS:
+ {
+ // The symbol requires a GOT entry.
+ Output_data_got_powerpc<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+
+ if (!parameters->options().output_is_position_independent())
+ {
+ if (size == 32 && is_ifunc)
+ got->add_local_plt(object, r_sym, GOT_TYPE_STANDARD);
+ else
+ got->add_local(object, r_sym, GOT_TYPE_STANDARD);
+ }
+ else if (!object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD))
+ {
+ // If we are generating a shared object or a pie, this
+ // symbol's GOT entry will be set by a dynamic relocation.
+ unsigned int off;
+ off = got->add_constant(0);
+ object->set_local_got_offset(r_sym, GOT_TYPE_STANDARD, off);
+
+ Reloc_section* rela_dyn = target->rela_dyn_section(symtab, layout,
+ is_ifunc);
+ unsigned int dynrel = (is_ifunc ? elfcpp::R_POWERPC_IRELATIVE
+ : elfcpp::R_POWERPC_RELATIVE);
+ rela_dyn->add_local_relative(object, r_sym, dynrel,
+ got, off, 0, false);
+ }
+ }
+ break;
+
+ case elfcpp::R_PPC64_TOC16:
+ case elfcpp::R_PPC64_TOC16_LO:
+ case elfcpp::R_PPC64_TOC16_HI:
+ case elfcpp::R_PPC64_TOC16_HA:
+ case elfcpp::R_PPC64_TOC16_DS:
+ case elfcpp::R_PPC64_TOC16_LO_DS:
+ // We need a GOT section.
+ target->got_section(symtab, layout);
+ break;
+
+ case elfcpp::R_POWERPC_GOT_TLSGD16:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_LO:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_HI:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_HA:
+ {
+ const tls::Tls_optimization tls_type = target->optimize_tls_gd(true);
+ if (tls_type == tls::TLSOPT_NONE)
+ {
+ Output_data_got_powerpc<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ got->add_local_tls_pair(object, r_sym, GOT_TYPE_TLSGD,
+ rela_dyn, elfcpp::R_POWERPC_DTPMOD);
+ }
+ else if (tls_type == tls::TLSOPT_TO_LE)
+ {
+ // no GOT relocs needed for Local Exec.
+ }
+ else
+ gold_unreachable();
+ }
+ break;
+
+ case elfcpp::R_POWERPC_GOT_TLSLD16:
+ case elfcpp::R_POWERPC_GOT_TLSLD16_LO:
+ case elfcpp::R_POWERPC_GOT_TLSLD16_HI:
+ case elfcpp::R_POWERPC_GOT_TLSLD16_HA:
+ {
+ const tls::Tls_optimization tls_type = target->optimize_tls_ld();
+ if (tls_type == tls::TLSOPT_NONE)
+ target->tlsld_got_offset(symtab, layout, object);
+ else if (tls_type == tls::TLSOPT_TO_LE)
+ {
+ // no GOT relocs needed for Local Exec.
+ if (parameters->options().emit_relocs())
+ {
+ Output_section* os = layout->tls_segment()->first_section();
+ gold_assert(os != NULL);
+ os->set_needs_symtab_index();
+ }
+ }
+ else
+ gold_unreachable();
+ }
+ break;
+
+ case elfcpp::R_POWERPC_GOT_DTPREL16:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_LO:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_HI:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_HA:
+ {
+ Output_data_got_powerpc<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ got->add_local_tls(object, r_sym, GOT_TYPE_DTPREL);
+ }
+ break;
+
+ case elfcpp::R_POWERPC_GOT_TPREL16:
+ case elfcpp::R_POWERPC_GOT_TPREL16_LO:
+ case elfcpp::R_POWERPC_GOT_TPREL16_HI:
+ case elfcpp::R_POWERPC_GOT_TPREL16_HA:
+ {
+ const tls::Tls_optimization tls_type = target->optimize_tls_ie(true);
+ if (tls_type == tls::TLSOPT_NONE)
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ if (!object->local_has_got_offset(r_sym, GOT_TYPE_TPREL))
+ {
+ Output_data_got_powerpc<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ unsigned int off = got->add_constant(0);
+ object->set_local_got_offset(r_sym, GOT_TYPE_TPREL, off);
+
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_symbolless_local_addend(object, r_sym,
+ elfcpp::R_POWERPC_TPREL,
+ got, off, 0);
+ }
+ }
+ else if (tls_type == tls::TLSOPT_TO_LE)
+ {
+ // no GOT relocs needed for Local Exec.
+ }
+ else
+ gold_unreachable();
+ }
+ break;
+
+ default:
+ unsupported_reloc_local(object, r_type);
+ break;
+ }
+
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_GOT_TLSLD16:
+ case elfcpp::R_POWERPC_GOT_TLSGD16:
+ case elfcpp::R_POWERPC_GOT_TPREL16:
+ case elfcpp::R_POWERPC_GOT_DTPREL16:
+ case elfcpp::R_POWERPC_GOT16:
+ case elfcpp::R_PPC64_GOT16_DS:
+ case elfcpp::R_PPC64_TOC16:
+ case elfcpp::R_PPC64_TOC16_DS:
+ ppc_object->set_has_small_toc_reloc();
+ default:
+ break;
+ }
+}
+
+// Report an unsupported relocation against a global symbol.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::Scan::unsupported_reloc_global(
+ Sized_relobj_file<size, 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());
+}
+
+// Scan a relocation for a global symbol.
+
+template<int size, bool big_endian>
+inline void
+Target_powerpc<size, big_endian>::Scan::global(
+ Symbol_table* symtab,
+ Layout* layout,
+ Target_powerpc<size, big_endian>* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, big_endian>& reloc,
+ unsigned int r_type,
+ Symbol* gsym)
+{
+ if (this->maybe_skip_tls_get_addr_call(r_type, gsym) == Track_tls::SKIP)
+ return;
+
+ if ((size == 64 && r_type == elfcpp::R_PPC64_TLSGD)
+ || (size == 32 && r_type == elfcpp::R_PPC_TLSGD))
+ {
+ this->expect_tls_get_addr_call();
+ const bool final = gsym->final_value_is_known();
+ const tls::Tls_optimization tls_type = target->optimize_tls_gd(final);
+ if (tls_type != tls::TLSOPT_NONE)
+ this->skip_next_tls_get_addr_call();
+ }
+ else if ((size == 64 && r_type == elfcpp::R_PPC64_TLSLD)
+ || (size == 32 && r_type == elfcpp::R_PPC_TLSLD))
+ {
+ this->expect_tls_get_addr_call();
+ const tls::Tls_optimization tls_type = target->optimize_tls_ld();
+ if (tls_type != tls::TLSOPT_NONE)
+ this->skip_next_tls_get_addr_call();
+ }
+
+ Powerpc_relobj<size, big_endian>* ppc_object
+ = static_cast<Powerpc_relobj<size, big_endian>*>(object);
+
+ // A STT_GNU_IFUNC symbol may require a PLT entry.
+ bool is_ifunc = gsym->type() == elfcpp::STT_GNU_IFUNC;
+ if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type, true))
+ {
+ target->push_branch(ppc_object, data_shndx, reloc.get_r_offset(),
+ r_type, elfcpp::elf_r_sym<size>(reloc.get_r_info()),
+ reloc.get_r_addend());
+ target->make_plt_entry(symtab, layout, gsym);
+ }
+
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_NONE:
+ case elfcpp::R_POWERPC_GNU_VTINHERIT:
+ case elfcpp::R_POWERPC_GNU_VTENTRY:
+ case elfcpp::R_PPC_LOCAL24PC:
+ case elfcpp::R_PPC_EMB_MRKREF:
+ case elfcpp::R_POWERPC_TLS:
+ break;
+
+ case elfcpp::R_PPC64_TOC:
+ {
+ Output_data_got_powerpc<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ if (parameters->options().output_is_position_independent())
+ {
+ Address off = reloc.get_r_offset();
+ if (size == 64
+ && data_shndx == ppc_object->opd_shndx()
+ && ppc_object->get_opd_discard(off - 8))
+ break;
+
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ Powerpc_relobj<size, big_endian>* symobj = ppc_object;
+ if (data_shndx != ppc_object->opd_shndx())
+ symobj = static_cast
+ <Powerpc_relobj<size, big_endian>*>(gsym->object());
+ rela_dyn->add_output_section_relative(got->output_section(),
+ elfcpp::R_POWERPC_RELATIVE,
+ output_section,
+ object, data_shndx, off,
+ symobj->toc_base_offset());
+ }
+ }
+ break;
+
+ case elfcpp::R_PPC64_ADDR64:
+ if (size == 64
+ && data_shndx == ppc_object->opd_shndx()
+ && (gsym->is_defined_in_discarded_section()
+ || gsym->object() != object))
+ {
+ ppc_object->set_opd_discard(reloc.get_r_offset());
+ break;
+ }
+ // Fall thru
+ case elfcpp::R_PPC64_UADDR64:
+ case elfcpp::R_POWERPC_ADDR32:
+ case elfcpp::R_POWERPC_UADDR32:
+ case elfcpp::R_POWERPC_ADDR24:
+ case elfcpp::R_POWERPC_ADDR16:
+ case elfcpp::R_POWERPC_ADDR16_LO:
+ case elfcpp::R_POWERPC_ADDR16_HI:
+ case elfcpp::R_POWERPC_ADDR16_HA:
+ case elfcpp::R_POWERPC_UADDR16:
+ case elfcpp::R_PPC64_ADDR16_HIGHER:
+ case elfcpp::R_PPC64_ADDR16_HIGHERA:
+ case elfcpp::R_PPC64_ADDR16_HIGHEST:
+ case elfcpp::R_PPC64_ADDR16_HIGHESTA:
+ case elfcpp::R_PPC64_ADDR16_DS:
+ case elfcpp::R_PPC64_ADDR16_LO_DS:
+ case elfcpp::R_POWERPC_ADDR14:
+ case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
+ case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
+ {
+ // Make a PLT entry if necessary.
+ if (gsym->needs_plt_entry())
+ {
+ if (!is_ifunc)
+ {
+ target->push_branch(ppc_object, data_shndx,
+ reloc.get_r_offset(), r_type,
+ elfcpp::elf_r_sym<size>(reloc.get_r_info()),
+ reloc.get_r_addend());
+ 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 call stub.
+ if (size == 32
+ && gsym->is_from_dynobj()
+ && !parameters->options().output_is_position_independent())
+ gsym->set_needs_dynsym_value();
+ }
+ // Make a dynamic relocation if necessary.
+ if (needs_dynamic_reloc<size>(gsym, Scan::get_reference_flags(r_type))
+ || (size == 64 && is_ifunc))
+ {
+ if (gsym->may_need_copy_reloc())
+ {
+ target->copy_reloc(symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
+ }
+ else if ((size == 32
+ && r_type == elfcpp::R_POWERPC_ADDR32
+ && gsym->can_use_relative_reloc(false)
+ && !(gsym->visibility() == elfcpp::STV_PROTECTED
+ && parameters->options().shared()))
+ || (size == 64
+ && r_type == elfcpp::R_PPC64_ADDR64
+ && (gsym->can_use_relative_reloc(false)
+ || data_shndx == ppc_object->opd_shndx())))
+ {
+ Reloc_section* rela_dyn
+ = target->rela_dyn_section(symtab, layout, is_ifunc);
+ unsigned int dynrel = (is_ifunc ? elfcpp::R_POWERPC_IRELATIVE
+ : elfcpp::R_POWERPC_RELATIVE);
+ rela_dyn->add_symbolless_global_addend(
+ gsym, dynrel, output_section, object, data_shndx,
+ reloc.get_r_offset(), reloc.get_r_addend());
+ }
+ else
+ {
+ Reloc_section* rela_dyn
+ = target->rela_dyn_section(symtab, layout, is_ifunc);
+ check_non_pic(object, r_type);
+ rela_dyn->add_global(gsym, r_type, output_section,
+ object, data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ }
+ }
+ break;
+
+ case elfcpp::R_PPC_PLTREL24:
+ case elfcpp::R_POWERPC_REL24:
+ if (!is_ifunc)
+ {
+ target->push_branch(ppc_object, data_shndx, reloc.get_r_offset(),
+ r_type,
+ elfcpp::elf_r_sym<size>(reloc.get_r_info()),
+ reloc.get_r_addend());
+ if (gsym->needs_plt_entry()
+ || (!gsym->final_value_is_known()
+ && (gsym->is_undefined()
+ || gsym->is_from_dynobj()
+ || gsym->is_preemptible())))
+ target->make_plt_entry(symtab, layout, gsym);
+ }
+ // Fall thru
+
+ case elfcpp::R_PPC64_REL64:
+ case elfcpp::R_POWERPC_REL32:
+ // Make a dynamic relocation if necessary.
+ if (needs_dynamic_reloc<size>(gsym, 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* rela_dyn
+ = target->rela_dyn_section(symtab, layout, is_ifunc);
+ check_non_pic(object, r_type);
+ rela_dyn->add_global(gsym, r_type, output_section, object,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ }
+ break;
+
+ case elfcpp::R_POWERPC_REL14:
+ case elfcpp::R_POWERPC_REL14_BRTAKEN:
+ case elfcpp::R_POWERPC_REL14_BRNTAKEN:
+ if (!is_ifunc)
+ target->push_branch(ppc_object, data_shndx, reloc.get_r_offset(),
+ r_type, elfcpp::elf_r_sym<size>(reloc.get_r_info()),
+ reloc.get_r_addend());
+ break;
+
+ case elfcpp::R_POWERPC_REL16:
+ case elfcpp::R_POWERPC_REL16_LO:
+ case elfcpp::R_POWERPC_REL16_HI:
+ case elfcpp::R_POWERPC_REL16_HA:
+ case elfcpp::R_POWERPC_SECTOFF:
+ case elfcpp::R_POWERPC_TPREL16:
+ case elfcpp::R_POWERPC_DTPREL16:
+ case elfcpp::R_POWERPC_SECTOFF_LO:
+ case elfcpp::R_POWERPC_TPREL16_LO:
+ case elfcpp::R_POWERPC_DTPREL16_LO:
+ case elfcpp::R_POWERPC_SECTOFF_HI:
+ case elfcpp::R_POWERPC_TPREL16_HI:
+ case elfcpp::R_POWERPC_DTPREL16_HI:
+ case elfcpp::R_POWERPC_SECTOFF_HA:
+ case elfcpp::R_POWERPC_TPREL16_HA:
+ case elfcpp::R_POWERPC_DTPREL16_HA:
+ case elfcpp::R_PPC64_DTPREL16_HIGHER:
+ case elfcpp::R_PPC64_TPREL16_HIGHER:
+ case elfcpp::R_PPC64_DTPREL16_HIGHERA:
+ case elfcpp::R_PPC64_TPREL16_HIGHERA:
+ case elfcpp::R_PPC64_DTPREL16_HIGHEST:
+ case elfcpp::R_PPC64_TPREL16_HIGHEST:
+ case elfcpp::R_PPC64_DTPREL16_HIGHESTA:
+ case elfcpp::R_PPC64_TPREL16_HIGHESTA:
+ case elfcpp::R_PPC64_TPREL16_DS:
+ case elfcpp::R_PPC64_TPREL16_LO_DS:
+ case elfcpp::R_PPC64_DTPREL16_DS:
+ case elfcpp::R_PPC64_DTPREL16_LO_DS:
+ case elfcpp::R_PPC64_SECTOFF_DS:
+ case elfcpp::R_PPC64_SECTOFF_LO_DS:
+ case elfcpp::R_PPC64_TLSGD:
+ case elfcpp::R_PPC64_TLSLD:
+ break;
+
+ case elfcpp::R_POWERPC_GOT16:
+ case elfcpp::R_POWERPC_GOT16_LO:
+ case elfcpp::R_POWERPC_GOT16_HI:
+ case elfcpp::R_POWERPC_GOT16_HA:
+ case elfcpp::R_PPC64_GOT16_DS:
+ case elfcpp::R_PPC64_GOT16_LO_DS:
+ {
+ // The symbol requires a GOT entry.
+ Output_data_got_powerpc<size, big_endian>* got;
+
+ got = target->got_section(symtab, layout);
+ if (gsym->final_value_is_known())
+ {
+ if (size == 32 && is_ifunc)
+ got->add_global_plt(gsym, GOT_TYPE_STANDARD);
+ else
+ got->add_global(gsym, GOT_TYPE_STANDARD);
+ }
+ else if (!gsym->has_got_offset(GOT_TYPE_STANDARD))
+ {
+ // If we are generating a shared object or a pie, this
+ // symbol's GOT entry will be set by a dynamic relocation.
+ unsigned int off = got->add_constant(0);
+ gsym->set_got_offset(GOT_TYPE_STANDARD, off);
+
+ Reloc_section* rela_dyn
+ = target->rela_dyn_section(symtab, layout, is_ifunc);
+
+ if (gsym->can_use_relative_reloc(false)
+ && !(size == 32
+ && gsym->visibility() == elfcpp::STV_PROTECTED
+ && parameters->options().shared()))
+ {
+ unsigned int dynrel = (is_ifunc ? elfcpp::R_POWERPC_IRELATIVE
+ : elfcpp::R_POWERPC_RELATIVE);
+ rela_dyn->add_global_relative(gsym, dynrel, got, off, 0, false);
+ }
+ else
+ {
+ unsigned int dynrel = elfcpp::R_POWERPC_GLOB_DAT;
+ rela_dyn->add_global(gsym, dynrel, got, off, 0);
+ }
+ }
+ }
+ break;
+
+ case elfcpp::R_PPC64_TOC16:
+ case elfcpp::R_PPC64_TOC16_LO:
+ case elfcpp::R_PPC64_TOC16_HI:
+ case elfcpp::R_PPC64_TOC16_HA:
+ case elfcpp::R_PPC64_TOC16_DS:
+ case elfcpp::R_PPC64_TOC16_LO_DS:
+ // We need a GOT section.
+ target->got_section(symtab, layout);
+ break;
+
+ case elfcpp::R_POWERPC_GOT_TLSGD16:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_LO:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_HI:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_HA:
+ {
+ const bool final = gsym->final_value_is_known();
+ const tls::Tls_optimization tls_type = target->optimize_tls_gd(final);
+ if (tls_type == tls::TLSOPT_NONE)
+ {
+ Output_data_got_powerpc<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ got->add_global_pair_with_rel(gsym, GOT_TYPE_TLSGD, rela_dyn,
+ elfcpp::R_POWERPC_DTPMOD,
+ elfcpp::R_POWERPC_DTPREL);
+ }
+ else if (tls_type == tls::TLSOPT_TO_IE)
+ {
+ if (!gsym->has_got_offset(GOT_TYPE_TPREL))
+ {
+ Output_data_got_powerpc<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ if (gsym->is_undefined()
+ || gsym->is_from_dynobj())
+ {
+ got->add_global_with_rel(gsym, GOT_TYPE_TPREL, rela_dyn,
+ elfcpp::R_POWERPC_TPREL);
+ }
+ else
+ {
+ unsigned int off = got->add_constant(0);
+ gsym->set_got_offset(GOT_TYPE_TPREL, off);
+ unsigned int dynrel = elfcpp::R_POWERPC_TPREL;
+ rela_dyn->add_symbolless_global_addend(gsym, dynrel,
+ got, off, 0);
+ }
+ }
+ }
+ else if (tls_type == tls::TLSOPT_TO_LE)
+ {
+ // no GOT relocs needed for Local Exec.
+ }
+ else
+ gold_unreachable();
+ }
+ break;
+
+ case elfcpp::R_POWERPC_GOT_TLSLD16:
+ case elfcpp::R_POWERPC_GOT_TLSLD16_LO:
+ case elfcpp::R_POWERPC_GOT_TLSLD16_HI:
+ case elfcpp::R_POWERPC_GOT_TLSLD16_HA:
+ {
+ const tls::Tls_optimization tls_type = target->optimize_tls_ld();
+ if (tls_type == tls::TLSOPT_NONE)
+ target->tlsld_got_offset(symtab, layout, object);
+ else if (tls_type == tls::TLSOPT_TO_LE)
+ {
+ // no GOT relocs needed for Local Exec.
+ if (parameters->options().emit_relocs())
+ {
+ Output_section* os = layout->tls_segment()->first_section();
+ gold_assert(os != NULL);
+ os->set_needs_symtab_index();
+ }
+ }
+ else
+ gold_unreachable();
+ }
+ break;
+
+ case elfcpp::R_POWERPC_GOT_DTPREL16:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_LO:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_HI:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_HA:
+ {
+ Output_data_got_powerpc<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ if (!gsym->final_value_is_known()
+ && (gsym->is_from_dynobj()
+ || gsym->is_undefined()
+ || gsym->is_preemptible()))
+ got->add_global_with_rel(gsym, GOT_TYPE_DTPREL,
+ target->rela_dyn_section(layout),
+ elfcpp::R_POWERPC_DTPREL);
+ else
+ got->add_global_tls(gsym, GOT_TYPE_DTPREL);
+ }
+ break;
+
+ case elfcpp::R_POWERPC_GOT_TPREL16:
+ case elfcpp::R_POWERPC_GOT_TPREL16_LO:
+ case elfcpp::R_POWERPC_GOT_TPREL16_HI:
+ case elfcpp::R_POWERPC_GOT_TPREL16_HA:
+ {
+ const bool final = gsym->final_value_is_known();
+ const tls::Tls_optimization tls_type = target->optimize_tls_ie(final);
+ if (tls_type == tls::TLSOPT_NONE)
+ {
+ if (!gsym->has_got_offset(GOT_TYPE_TPREL))
+ {
+ Output_data_got_powerpc<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ if (gsym->is_undefined()
+ || gsym->is_from_dynobj())
+ {
+ got->add_global_with_rel(gsym, GOT_TYPE_TPREL, rela_dyn,
+ elfcpp::R_POWERPC_TPREL);
+ }
+ else
+ {
+ unsigned int off = got->add_constant(0);
+ gsym->set_got_offset(GOT_TYPE_TPREL, off);
+ unsigned int dynrel = elfcpp::R_POWERPC_TPREL;
+ rela_dyn->add_symbolless_global_addend(gsym, dynrel,
+ got, off, 0);
+ }
+ }
+ }
+ else if (tls_type == tls::TLSOPT_TO_LE)
+ {
+ // no GOT relocs needed for Local Exec.
+ }
+ else
+ gold_unreachable();
+ }
+ break;
+
+ default:
+ unsupported_reloc_global(object, r_type, gsym);
+ break;
+ }
+
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_GOT_TLSLD16:
+ case elfcpp::R_POWERPC_GOT_TLSGD16:
+ case elfcpp::R_POWERPC_GOT_TPREL16:
+ case elfcpp::R_POWERPC_GOT_DTPREL16:
+ case elfcpp::R_POWERPC_GOT16:
+ case elfcpp::R_PPC64_GOT16_DS:
+ case elfcpp::R_PPC64_TOC16:
+ case elfcpp::R_PPC64_TOC16_DS:
+ ppc_object->set_has_small_toc_reloc();
+ default:
+ break;
+ }
+}
+
+// Process relocations for gc.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::gc_process_relocs(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, 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_powerpc<size, big_endian> Powerpc;
+ typedef typename Target_powerpc<size, big_endian>::Scan Scan;
+ Powerpc_relobj<size, big_endian>* ppc_object
+ = static_cast<Powerpc_relobj<size, big_endian>*>(object);
+ if (size == 64)
+ ppc_object->set_opd_valid();
+ if (size == 64 && data_shndx == ppc_object->opd_shndx())
+ {
+ typename Powerpc_relobj<size, big_endian>::Access_from::iterator p;
+ for (p = ppc_object->access_from_map()->begin();
+ p != ppc_object->access_from_map()->end();
+ ++p)
+ {
+ Address dst_off = p->first;
+ unsigned int dst_indx = ppc_object->get_opd_ent(dst_off);
+ typename Powerpc_relobj<size, big_endian>::Section_refs::iterator s;
+ for (s = p->second.begin(); s != p->second.end(); ++s)
+ {
+ Object* src_obj = s->first;
+ unsigned int src_indx = s->second;
+ symtab->gc()->add_reference(src_obj, src_indx,
+ ppc_object, dst_indx);
+ }
+ p->second.clear();
+ }
+ ppc_object->access_from_map()->clear();
+ ppc_object->process_gc_mark(symtab);
+ // Don't look at .opd relocs as .opd will reference everything.
+ return;
+ }
+
+ gold::gc_process_relocs<size, big_endian, Powerpc, elfcpp::SHT_RELA, Scan,
+ typename Target_powerpc::Relocatable_size_for_reloc>(
+ symtab,
+ layout,
+ this,
+ object,
+ data_shndx,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ local_symbol_count,
+ plocal_symbols);
+}
+
+// Handle target specific gc actions when adding a gc reference from
+// SRC_OBJ, SRC_SHNDX to a location specified by DST_OBJ, DST_SHNDX
+// and DST_OFF. For powerpc64, this adds a referenc to the code
+// section of a function descriptor.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::do_gc_add_reference(
+ Symbol_table* symtab,
+ Object* src_obj,
+ unsigned int src_shndx,
+ Object* dst_obj,
+ unsigned int dst_shndx,
+ Address dst_off) const
+{
+ if (size != 64 || dst_obj->is_dynamic())
+ return;
+
+ Powerpc_relobj<size, big_endian>* ppc_object
+ = static_cast<Powerpc_relobj<size, big_endian>*>(dst_obj);
+ if (dst_shndx != 0 && dst_shndx == ppc_object->opd_shndx())
+ {
+ if (ppc_object->opd_valid())
+ {
+ dst_shndx = ppc_object->get_opd_ent(dst_off);
+ symtab->gc()->add_reference(src_obj, src_shndx, dst_obj, dst_shndx);
+ }
+ else
+ {
+ // If we haven't run scan_opd_relocs, we must delay
+ // processing this function descriptor reference.
+ ppc_object->add_reference(src_obj, src_shndx, dst_off);
+ }
+ }
+}
+
+// Add any special sections for this symbol to the gc work list.
+// For powerpc64, this adds the code section of a function
+// descriptor.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::do_gc_mark_symbol(
+ Symbol_table* symtab,
+ Symbol* sym) const
+{
+ if (size == 64)
+ {
+ Powerpc_relobj<size, big_endian>* ppc_object
+ = static_cast<Powerpc_relobj<size, big_endian>*>(sym->object());
+ bool is_ordinary;
+ unsigned int shndx = sym->shndx(&is_ordinary);
+ if (is_ordinary && shndx != 0 && shndx == ppc_object->opd_shndx())
+ {
+ Sized_symbol<size>* gsym = symtab->get_sized_symbol<size>(sym);
+ Address dst_off = gsym->value();
+ if (ppc_object->opd_valid())
+ {
+ unsigned int dst_indx = ppc_object->get_opd_ent(dst_off);
+ symtab->gc()->worklist().push(Section_id(ppc_object, dst_indx));
+ }
+ else
+ ppc_object->add_gc_mark(dst_off);
+ }
+ }
+}
+
+// For a symbol location in .opd, set LOC to the location of the
+// function entry.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::do_function_location(
+ Symbol_location* loc) const
+{
+ if (size == 64 && loc->shndx != 0)
+ {
+ if (loc->object->is_dynamic())
+ {
+ Powerpc_dynobj<size, big_endian>* ppc_object
+ = static_cast<Powerpc_dynobj<size, big_endian>*>(loc->object);
+ if (loc->shndx == ppc_object->opd_shndx())
+ {
+ Address dest_off;
+ Address off = loc->offset - ppc_object->opd_address();
+ loc->shndx = ppc_object->get_opd_ent(off, &dest_off);
+ loc->offset = dest_off;
+ }
+ }
+ else
+ {
+ const Powerpc_relobj<size, big_endian>* ppc_object
+ = static_cast<const Powerpc_relobj<size, big_endian>*>(loc->object);
+ if (loc->shndx == ppc_object->opd_shndx())
+ {
+ Address dest_off;
+ loc->shndx = ppc_object->get_opd_ent(loc->offset, &dest_off);
+ loc->offset = dest_off;
+ }
+ }
+ }
+}
+
+// Scan relocations for a section.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::scan_relocs(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols)
+{
+ typedef Target_powerpc<size, big_endian> Powerpc;
+ typedef typename Target_powerpc<size, big_endian>::Scan Scan;
+
+ if (sh_type == elfcpp::SHT_REL)
+ {
+ gold_error(_("%s: unsupported REL reloc section"),
+ object->name().c_str());
+ return;
+ }
+
+ gold::scan_relocs<size, big_endian, Powerpc, elfcpp::SHT_RELA, Scan>(
+ symtab,
+ layout,
+ this,
+ object,
+ data_shndx,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ local_symbol_count,
+ plocal_symbols);
+}
+
+// Functor class for processing the global symbol table.
+// Removes symbols defined on discarded opd entries.
+
+template<bool big_endian>
+class Global_symbol_visitor_opd
+{
+ public:
+ Global_symbol_visitor_opd()
+ { }
+
+ void
+ operator()(Sized_symbol<64>* sym)
+ {
+ if (sym->has_symtab_index()
+ || sym->source() != Symbol::FROM_OBJECT
+ || !sym->in_real_elf())
+ return;
+
+ if (sym->object()->is_dynamic())
+ return;
+
+ Powerpc_relobj<64, big_endian>* symobj
+ = static_cast<Powerpc_relobj<64, big_endian>*>(sym->object());
+ if (symobj->opd_shndx() == 0)
+ return;
+
+ bool is_ordinary;
+ unsigned int shndx = sym->shndx(&is_ordinary);
+ if (shndx == symobj->opd_shndx()
+ && symobj->get_opd_discard(sym->value()))
+ sym->set_symtab_index(-1U);
+ }
+};
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::define_save_restore_funcs(
+ Layout* layout,
+ Symbol_table* symtab)
+{
+ if (size == 64)
+ {
+ Output_data_save_res<64, big_endian>* savres
+ = new Output_data_save_res<64, big_endian>(symtab);
+ layout->add_output_section_data(".text", elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR,
+ savres, ORDER_TEXT, false);
+ }
+}
+
+// Sort linker created .got section first (for the header), then input
+// sections belonging to files using small model code.
+
+template<bool big_endian>
+class Sort_toc_sections
+{
+ public:
+ bool
+ operator()(const Output_section::Input_section& is1,
+ const Output_section::Input_section& is2) const
+ {
+ if (!is1.is_input_section() && is2.is_input_section())
+ return true;
+ bool small1
+ = (is1.is_input_section()
+ && (static_cast<const Powerpc_relobj<64, big_endian>*>(is1.relobj())
+ ->has_small_toc_reloc()));
+ bool small2
+ = (is2.is_input_section()
+ && (static_cast<const Powerpc_relobj<64, big_endian>*>(is2.relobj())
+ ->has_small_toc_reloc()));
+ return small1 && !small2;
+ }
+};
+
+// Finalize the sections.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::do_finalize_sections(
+ Layout* layout,
+ const Input_objects*,
+ Symbol_table* symtab)
+{
+ if (parameters->doing_static_link())
+ {
+ // At least some versions of glibc elf-init.o have a strong
+ // reference to __rela_iplt marker syms. A weak ref would be
+ // better..
+ if (this->iplt_ != NULL)
+ {
+ Reloc_section* rel = this->iplt_->rel_plt();
+ symtab->define_in_output_data("__rela_iplt_start", NULL,
+ Symbol_table::PREDEFINED, rel, 0, 0,
+ elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
+ elfcpp::STV_HIDDEN, 0, false, true);
+ symtab->define_in_output_data("__rela_iplt_end", NULL,
+ Symbol_table::PREDEFINED, rel, 0, 0,
+ elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
+ elfcpp::STV_HIDDEN, 0, true, true);
+ }
+ else
+ {
+ symtab->define_as_constant("__rela_iplt_start", NULL,
+ Symbol_table::PREDEFINED, 0, 0,
+ elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
+ elfcpp::STV_HIDDEN, 0, true, false);
+ symtab->define_as_constant("__rela_iplt_end", NULL,
+ Symbol_table::PREDEFINED, 0, 0,
+ elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
+ elfcpp::STV_HIDDEN, 0, true, false);
+ }
+ }
+
+ if (size == 64)
+ {
+ typedef Global_symbol_visitor_opd<big_endian> Symbol_visitor;
+ symtab->for_all_symbols<64, Symbol_visitor>(Symbol_visitor());
+
+ if (!parameters->options().relocatable())
+ {
+ this->define_save_restore_funcs(layout, symtab);
+
+ // Annoyingly, we need to make these sections now whether or
+ // not we need them. If we delay until do_relax then we
+ // need to mess with the relaxation machinery checkpointing.
+ this->got_section(symtab, layout);
+ this->make_brlt_section(layout);
+
+ if (parameters->options().toc_sort())
+ {
+ Output_section* os = this->got_->output_section();
+ if (os != NULL && os->input_sections().size() > 1)
+ std::stable_sort(os->input_sections().begin(),
+ os->input_sections().end(),
+ Sort_toc_sections<big_endian>());
+ }
+ }
+ }
+
+ // Fill in some more dynamic tags.
+ Output_data_dynamic* odyn = layout->dynamic_data();
+ if (odyn != NULL)
+ {
+ const Reloc_section* rel_plt = (this->plt_ == NULL
+ ? NULL
+ : this->plt_->rel_plt());
+ layout->add_target_dynamic_tags(false, this->plt_, rel_plt,
+ this->rela_dyn_, true, size == 32);
+
+ if (size == 32)
+ {
+ if (this->got_ != NULL)
+ {
+ this->got_->finalize_data_size();
+ odyn->add_section_plus_offset(elfcpp::DT_PPC_GOT,
+ this->got_, this->got_->g_o_t());
+ }
+ }
+ else
+ {
+ if (this->glink_ != NULL)
+ {
+ this->glink_->finalize_data_size();
+ odyn->add_section_plus_offset(elfcpp::DT_PPC64_GLINK,
+ this->glink_,
+ (this->glink_->pltresolve_size
+ - 32));
+ }
+ }
+ }
+
+ // 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->rela_dyn_section(layout));
+}
+
+// Return TRUE iff INSN is one we expect on a _LO variety toc/got
+// reloc.
+
+static bool
+ok_lo_toc_insn(uint32_t insn)
+{
+ return ((insn & (0x3f << 26)) == 14u << 26 /* addi */
+ || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
+ || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
+ || (insn & (0x3f << 26)) == 36u << 26 /* stw */
+ || (insn & (0x3f << 26)) == 38u << 26 /* stb */
+ || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
+ || (insn & (0x3f << 26)) == 42u << 26 /* lha */
+ || (insn & (0x3f << 26)) == 44u << 26 /* sth */
+ || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
+ || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
+ || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
+ || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
+ || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
+ || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
+ || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
+ && (insn & 3) != 1)
+ || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
+ && ((insn & 3) == 0 || (insn & 3) == 3))
+ || (insn & (0x3f << 26)) == 12u << 26 /* addic */);
+}
+
+// Return the value to use for a branch relocation.
+
+template<int size, bool big_endian>
+typename Target_powerpc<size, big_endian>::Address
+Target_powerpc<size, big_endian>::symval_for_branch(
+ const Symbol_table* symtab,
+ Address value,
+ const Sized_symbol<size>* gsym,
+ Powerpc_relobj<size, big_endian>* object,
+ unsigned int *dest_shndx)
+{
+ *dest_shndx = 0;
+ if (size == 32)
+ return value;
+
+ // If the symbol is defined in an opd section, ie. is a function
+ // descriptor, use the function descriptor code entry address
+ Powerpc_relobj<size, big_endian>* symobj = object;
+ if (gsym != NULL
+ && gsym->source() != Symbol::FROM_OBJECT)
+ return value;
+ if (gsym != NULL)
+ symobj = static_cast<Powerpc_relobj<size, big_endian>*>(gsym->object());
+ unsigned int shndx = symobj->opd_shndx();
+ if (shndx == 0)
+ return value;
+ Address opd_addr = symobj->get_output_section_offset(shndx);
+ if (opd_addr == invalid_address)
+ return value;
+ opd_addr += symobj->output_section_address(shndx);
+ if (value >= opd_addr && value < opd_addr + symobj->section_size(shndx))
+ {
+ Address sec_off;
+ *dest_shndx = symobj->get_opd_ent(value - opd_addr, &sec_off);
+ if (symtab->is_section_folded(symobj, *dest_shndx))
+ {
+ Section_id folded
+ = symtab->icf()->get_folded_section(symobj, *dest_shndx);
+ symobj = static_cast<Powerpc_relobj<size, big_endian>*>(folded.first);
+ *dest_shndx = folded.second;
+ }
+ Address sec_addr = symobj->get_output_section_offset(*dest_shndx);
+ gold_assert(sec_addr != invalid_address);
+ sec_addr += symobj->output_section(*dest_shndx)->address();
+ value = sec_addr + sec_off;
+ }
+ return value;
+}
+
+// Perform a relocation.
+
+template<int size, bool big_endian>
+inline bool
+Target_powerpc<size, big_endian>::Relocate::relocate(
+ const Relocate_info<size, big_endian>* relinfo,
+ Target_powerpc* target,
+ Output_section* os,
+ size_t relnum,
+ const elfcpp::Rela<size, big_endian>& rela,
+ unsigned int r_type,
+ const Sized_symbol<size>* gsym,
+ const Symbol_value<size>* psymval,
+ unsigned char* view,
+ Address address,
+ section_size_type view_size)
+{
+ if (view == NULL)
+ return true;
+
+ switch (this->maybe_skip_tls_get_addr_call(r_type, gsym))
+ {
+ case Track_tls::NOT_EXPECTED:
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("__tls_get_addr call lacks marker reloc"));
+ break;
+ case Track_tls::EXPECTED:
+ // We have already complained.
+ break;
+ case Track_tls::SKIP:
+ return true;
+ case Track_tls::NORMAL:
+ break;
+ }
+
+ typedef Powerpc_relocate_functions<size, big_endian> Reloc;
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Insn;
+ Powerpc_relobj<size, big_endian>* const object
+ = static_cast<Powerpc_relobj<size, big_endian>*>(relinfo->object);
+ Address value = 0;
+ bool has_plt_value = false;
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ if ((gsym != NULL
+ ? use_plt_offset<size>(gsym, Scan::get_reference_flags(r_type))
+ : object->local_has_plt_offset(r_sym))
+ && (!psymval->is_ifunc_symbol()
+ || Scan::reloc_needs_plt_for_ifunc(object, r_type, false)))
+ {
+ Stub_table<size, big_endian>* stub_table
+ = object->stub_table(relinfo->data_shndx);
+ if (stub_table == NULL)
+ {
+ // This is a ref from a data section to an ifunc symbol.
+ if (target->stub_tables().size() != 0)
+ stub_table = target->stub_tables()[0];
+ }
+ gold_assert(stub_table != NULL);
+ Address off;
+ if (gsym != NULL)
+ off = stub_table->find_plt_call_entry(object, gsym, r_type,
+ rela.get_r_addend());
+ else
+ off = stub_table->find_plt_call_entry(object, r_sym, r_type,
+ rela.get_r_addend());
+ gold_assert(off != invalid_address);
+ value = stub_table->stub_address() + off;
+ has_plt_value = true;
+ }
+
+ if (r_type == elfcpp::R_POWERPC_GOT16
+ || r_type == elfcpp::R_POWERPC_GOT16_LO
+ || r_type == elfcpp::R_POWERPC_GOT16_HI
+ || r_type == elfcpp::R_POWERPC_GOT16_HA
+ || r_type == elfcpp::R_PPC64_GOT16_DS
+ || r_type == elfcpp::R_PPC64_GOT16_LO_DS)
+ {
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+ value = gsym->got_offset(GOT_TYPE_STANDARD);
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+ value = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
+ }
+ value -= target->got_section()->got_base_offset(object);
+ }
+ else if (r_type == elfcpp::R_PPC64_TOC)
+ {
+ value = (target->got_section()->output_section()->address()
+ + object->toc_base_offset());
+ }
+ else if (gsym != NULL
+ && (r_type == elfcpp::R_POWERPC_REL24
+ || r_type == elfcpp::R_PPC_PLTREL24)
+ && has_plt_value)
+ {
+ if (size == 64)
+ {
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ bool can_plt_call = false;
+ if (rela.get_r_offset() + 8 <= view_size)
+ {
+ Valtype insn = elfcpp::Swap<32, big_endian>::readval(wv);
+ Valtype insn2 = elfcpp::Swap<32, big_endian>::readval(wv + 1);
+ if ((insn & 1) != 0
+ && (insn2 == nop
+ || insn2 == cror_15_15_15 || insn2 == cror_31_31_31))
+ {
+ elfcpp::Swap<32, big_endian>::writeval(wv + 1, ld_2_1 + 40);
+ can_plt_call = true;
+ }
+ }
+ if (!can_plt_call)
+ {
+ // If we don't have a branch and link followed by a nop,
+ // we can't go via the plt because there is no place to
+ // put a toc restoring instruction.
+ // Unless we know we won't be returning.
+ if (strcmp(gsym->name(), "__libc_start_main") == 0)
+ can_plt_call = true;
+ }
+ if (!can_plt_call)
+ {
+ // g++ as of 20130507 emits self-calls without a
+ // following nop. This is arguably wrong since we have
+ // conflicting information. On the one hand a global
+ // symbol and on the other a local call sequence, but
+ // don't error for this special case.
+ // It isn't possible to cheaply verify we have exactly
+ // such a call. Allow all calls to the same section.
+ bool ok = false;
+ Address code = value;
+ if (gsym->source() == Symbol::FROM_OBJECT
+ && gsym->object() == object)
+ {
+ Address addend = rela.get_r_addend();
+ unsigned int dest_shndx;
+ Address opdent = psymval->value(object, addend);
+ code = target->symval_for_branch(relinfo->symtab, opdent,
+ gsym, object, &dest_shndx);
+ bool is_ordinary;
+ if (dest_shndx == 0)
+ dest_shndx = gsym->shndx(&is_ordinary);
+ ok = dest_shndx == relinfo->data_shndx;
+ }
+ if (!ok)
+ {
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("call lacks nop, can't restore toc; "
+ "recompile with -fPIC"));
+ value = code;
+ }
+ }
+ }
+ }
+ else if (r_type == elfcpp::R_POWERPC_GOT_TLSGD16
+ || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_LO
+ || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_HI
+ || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_HA)
+ {
+ // First instruction of a global dynamic sequence, arg setup insn.
+ const bool final = gsym == NULL || gsym->final_value_is_known();
+ const tls::Tls_optimization tls_type = target->optimize_tls_gd(final);
+ enum Got_type got_type = GOT_TYPE_STANDARD;
+ if (tls_type == tls::TLSOPT_NONE)
+ got_type = GOT_TYPE_TLSGD;
+ else if (tls_type == tls::TLSOPT_TO_IE)
+ got_type = GOT_TYPE_TPREL;
+ if (got_type != GOT_TYPE_STANDARD)
+ {
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(got_type));
+ value = gsym->got_offset(got_type);
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ value = object->local_got_offset(r_sym, got_type);
+ }
+ value -= target->got_section()->got_base_offset(object);
+ }
+ if (tls_type == tls::TLSOPT_TO_IE)
+ {
+ if (r_type == elfcpp::R_POWERPC_GOT_TLSGD16
+ || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_LO)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
+ Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
+ insn &= (1 << 26) - (1 << 16); // extract rt,ra from addi
+ if (size == 32)
+ insn |= 32 << 26; // lwz
+ else
+ insn |= 58 << 26; // ld
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ }
+ r_type += (elfcpp::R_POWERPC_GOT_TPREL16
+ - elfcpp::R_POWERPC_GOT_TLSGD16);
+ }
+ else if (tls_type == tls::TLSOPT_TO_LE)
+ {
+ if (r_type == elfcpp::R_POWERPC_GOT_TLSGD16
+ || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_LO)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
+ Insn insn = addis_3_13;
+ if (size == 32)
+ insn = addis_3_2;
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ r_type = elfcpp::R_POWERPC_TPREL16_HA;
+ value = psymval->value(object, rela.get_r_addend());
+ }
+ else
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
+ Insn insn = nop;
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ r_type = elfcpp::R_POWERPC_NONE;
+ }
+ }
+ }
+ else if (r_type == elfcpp::R_POWERPC_GOT_TLSLD16
+ || r_type == elfcpp::R_POWERPC_GOT_TLSLD16_LO
+ || r_type == elfcpp::R_POWERPC_GOT_TLSLD16_HI
+ || r_type == elfcpp::R_POWERPC_GOT_TLSLD16_HA)
+ {
+ // First instruction of a local dynamic sequence, arg setup insn.
+ const tls::Tls_optimization tls_type = target->optimize_tls_ld();
+ if (tls_type == tls::TLSOPT_NONE)
+ {
+ value = target->tlsld_got_offset();
+ value -= target->got_section()->got_base_offset(object);
+ }
+ else
+ {
+ gold_assert(tls_type == tls::TLSOPT_TO_LE);
+ if (r_type == elfcpp::R_POWERPC_GOT_TLSLD16
+ || r_type == elfcpp::R_POWERPC_GOT_TLSLD16_LO)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
+ Insn insn = addis_3_13;
+ if (size == 32)
+ insn = addis_3_2;
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ r_type = elfcpp::R_POWERPC_TPREL16_HA;
+ value = dtp_offset;
+ }
+ else
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
+ Insn insn = nop;
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ r_type = elfcpp::R_POWERPC_NONE;
+ }
+ }
+ }
+ else if (r_type == elfcpp::R_POWERPC_GOT_DTPREL16
+ || r_type == elfcpp::R_POWERPC_GOT_DTPREL16_LO
+ || r_type == elfcpp::R_POWERPC_GOT_DTPREL16_HI
+ || r_type == elfcpp::R_POWERPC_GOT_DTPREL16_HA)
+ {
+ // Accesses relative to a local dynamic sequence address,
+ // no optimisation here.
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_DTPREL));
+ value = gsym->got_offset(GOT_TYPE_DTPREL);
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_DTPREL));
+ value = object->local_got_offset(r_sym, GOT_TYPE_DTPREL);
+ }
+ value -= target->got_section()->got_base_offset(object);
+ }
+ else if (r_type == elfcpp::R_POWERPC_GOT_TPREL16
+ || r_type == elfcpp::R_POWERPC_GOT_TPREL16_LO
+ || r_type == elfcpp::R_POWERPC_GOT_TPREL16_HI
+ || r_type == elfcpp::R_POWERPC_GOT_TPREL16_HA)
+ {
+ // First instruction of initial exec sequence.
+ const bool final = gsym == NULL || gsym->final_value_is_known();
+ const tls::Tls_optimization tls_type = target->optimize_tls_ie(final);
+ if (tls_type == tls::TLSOPT_NONE)
+ {
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_TPREL));
+ value = gsym->got_offset(GOT_TYPE_TPREL);
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_TPREL));
+ value = object->local_got_offset(r_sym, GOT_TYPE_TPREL);
+ }
+ value -= target->got_section()->got_base_offset(object);
+ }
+ else
+ {
+ gold_assert(tls_type == tls::TLSOPT_TO_LE);
+ if (r_type == elfcpp::R_POWERPC_GOT_TPREL16
+ || r_type == elfcpp::R_POWERPC_GOT_TPREL16_LO)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
+ Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
+ insn &= (1 << 26) - (1 << 21); // extract rt from ld
+ if (size == 32)
+ insn |= addis_0_2;
+ else
+ insn |= addis_0_13;
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ r_type = elfcpp::R_POWERPC_TPREL16_HA;
+ value = psymval->value(object, rela.get_r_addend());
+ }
+ else
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
+ Insn insn = nop;
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ r_type = elfcpp::R_POWERPC_NONE;
+ }
+ }
+ }
+ else if ((size == 64 && r_type == elfcpp::R_PPC64_TLSGD)
+ || (size == 32 && r_type == elfcpp::R_PPC_TLSGD))
+ {
+ // Second instruction of a global dynamic sequence,
+ // the __tls_get_addr call
+ this->expect_tls_get_addr_call(relinfo, relnum, rela.get_r_offset());
+ const bool final = gsym == NULL || gsym->final_value_is_known();
+ const tls::Tls_optimization tls_type = target->optimize_tls_gd(final);
+ if (tls_type != tls::TLSOPT_NONE)
+ {
+ if (tls_type == tls::TLSOPT_TO_IE)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ Insn insn = add_3_3_13;
+ if (size == 32)
+ insn = add_3_3_2;
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ r_type = elfcpp::R_POWERPC_NONE;
+ }
+ else
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ Insn insn = addi_3_3;
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ r_type = elfcpp::R_POWERPC_TPREL16_LO;
+ view += 2 * big_endian;
+ value = psymval->value(object, rela.get_r_addend());
+ }
+ this->skip_next_tls_get_addr_call();
+ }
+ }
+ else if ((size == 64 && r_type == elfcpp::R_PPC64_TLSLD)
+ || (size == 32 && r_type == elfcpp::R_PPC_TLSLD))
+ {
+ // Second instruction of a local dynamic sequence,
+ // the __tls_get_addr call
+ this->expect_tls_get_addr_call(relinfo, relnum, rela.get_r_offset());
+ const tls::Tls_optimization tls_type = target->optimize_tls_ld();
+ if (tls_type == tls::TLSOPT_TO_LE)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ Insn insn = addi_3_3;
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ this->skip_next_tls_get_addr_call();
+ r_type = elfcpp::R_POWERPC_TPREL16_LO;
+ view += 2 * big_endian;
+ value = dtp_offset;
+ }
+ }
+ else if (r_type == elfcpp::R_POWERPC_TLS)
+ {
+ // Second instruction of an initial exec sequence
+ const bool final = gsym == NULL || gsym->final_value_is_known();
+ const tls::Tls_optimization tls_type = target->optimize_tls_ie(final);
+ if (tls_type == tls::TLSOPT_TO_LE)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
+ unsigned int reg = size == 32 ? 2 : 13;
+ insn = at_tls_transform(insn, reg);
+ gold_assert(insn != 0);
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ r_type = elfcpp::R_POWERPC_TPREL16_LO;
+ view += 2 * big_endian;
+ value = psymval->value(object, rela.get_r_addend());
+ }
+ }
+ else if (!has_plt_value)
+ {
+ Address addend = 0;
+ unsigned int dest_shndx;
+ if (r_type != elfcpp::R_PPC_PLTREL24)
+ addend = rela.get_r_addend();
+ value = psymval->value(object, addend);
+ if (size == 64 && is_branch_reloc(r_type))
+ value = target->symval_for_branch(relinfo->symtab, value,
+ gsym, object, &dest_shndx);
+ unsigned int max_branch_offset = 0;
+ if (r_type == elfcpp::R_POWERPC_REL24
+ || r_type == elfcpp::R_PPC_PLTREL24
+ || r_type == elfcpp::R_PPC_LOCAL24PC)
+ max_branch_offset = 1 << 25;
+ else if (r_type == elfcpp::R_POWERPC_REL14
+ || r_type == elfcpp::R_POWERPC_REL14_BRTAKEN
+ || r_type == elfcpp::R_POWERPC_REL14_BRNTAKEN)
+ max_branch_offset = 1 << 15;
+ if (max_branch_offset != 0
+ && value - address + max_branch_offset >= 2 * max_branch_offset)
+ {
+ Stub_table<size, big_endian>* stub_table
+ = object->stub_table(relinfo->data_shndx);
+ if (stub_table != NULL)
+ {
+ Address off = stub_table->find_long_branch_entry(object, value);
+ if (off != invalid_address)
+ value = (stub_table->stub_address() + stub_table->plt_size()
+ + off);
+ }
+ }
+ }
+
+ switch (r_type)
+ {
+ case elfcpp::R_PPC64_REL64:
+ case elfcpp::R_POWERPC_REL32:
+ case elfcpp::R_POWERPC_REL24:
+ case elfcpp::R_PPC_PLTREL24:
+ case elfcpp::R_PPC_LOCAL24PC:
+ case elfcpp::R_POWERPC_REL16:
+ case elfcpp::R_POWERPC_REL16_LO:
+ case elfcpp::R_POWERPC_REL16_HI:
+ case elfcpp::R_POWERPC_REL16_HA:
+ case elfcpp::R_POWERPC_REL14:
+ case elfcpp::R_POWERPC_REL14_BRTAKEN:
+ case elfcpp::R_POWERPC_REL14_BRNTAKEN:
+ value -= address;
+ break;
+
+ case elfcpp::R_PPC64_TOC16:
+ case elfcpp::R_PPC64_TOC16_LO:
+ case elfcpp::R_PPC64_TOC16_HI:
+ case elfcpp::R_PPC64_TOC16_HA:
+ case elfcpp::R_PPC64_TOC16_DS:
+ case elfcpp::R_PPC64_TOC16_LO_DS:
+ // Subtract the TOC base address.
+ value -= (target->got_section()->output_section()->address()
+ + object->toc_base_offset());
+ break;
+
+ case elfcpp::R_POWERPC_SECTOFF:
+ case elfcpp::R_POWERPC_SECTOFF_LO:
+ case elfcpp::R_POWERPC_SECTOFF_HI:
+ case elfcpp::R_POWERPC_SECTOFF_HA:
+ case elfcpp::R_PPC64_SECTOFF_DS:
+ case elfcpp::R_PPC64_SECTOFF_LO_DS:
+ if (os != NULL)
+ value -= os->address();
+ break;
+
+ case elfcpp::R_PPC64_TPREL16_DS:
+ case elfcpp::R_PPC64_TPREL16_LO_DS:
+ if (size != 64)
+ // R_PPC_TLSGD and R_PPC_TLSLD
+ break;
+ case elfcpp::R_POWERPC_TPREL16:
+ case elfcpp::R_POWERPC_TPREL16_LO:
+ case elfcpp::R_POWERPC_TPREL16_HI:
+ case elfcpp::R_POWERPC_TPREL16_HA:
+ case elfcpp::R_POWERPC_TPREL:
+ case elfcpp::R_PPC64_TPREL16_HIGHER:
+ case elfcpp::R_PPC64_TPREL16_HIGHERA:
+ case elfcpp::R_PPC64_TPREL16_HIGHEST:
+ case elfcpp::R_PPC64_TPREL16_HIGHESTA:
+ // tls symbol values are relative to tls_segment()->vaddr()
+ value -= tp_offset;
+ break;
+
+ case elfcpp::R_PPC64_DTPREL16_DS:
+ case elfcpp::R_PPC64_DTPREL16_LO_DS:
+ case elfcpp::R_PPC64_DTPREL16_HIGHER:
+ case elfcpp::R_PPC64_DTPREL16_HIGHERA:
+ case elfcpp::R_PPC64_DTPREL16_HIGHEST:
+ case elfcpp::R_PPC64_DTPREL16_HIGHESTA:
+ if (size != 64)
+ // R_PPC_EMB_NADDR32, R_PPC_EMB_NADDR16, R_PPC_EMB_NADDR16_LO
+ // R_PPC_EMB_NADDR16_HI, R_PPC_EMB_NADDR16_HA, R_PPC_EMB_SDAI16
+ break;
+ case elfcpp::R_POWERPC_DTPREL16:
+ case elfcpp::R_POWERPC_DTPREL16_LO:
+ case elfcpp::R_POWERPC_DTPREL16_HI:
+ case elfcpp::R_POWERPC_DTPREL16_HA:
+ case elfcpp::R_POWERPC_DTPREL:
+ // tls symbol values are relative to tls_segment()->vaddr()
+ value -= dtp_offset;
+ break;
+
+ default:
+ break;
+ }
+
+ Insn branch_bit = 0;
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
+ case elfcpp::R_POWERPC_REL14_BRTAKEN:
+ branch_bit = 1 << 21;
+ case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
+ case elfcpp::R_POWERPC_REL14_BRNTAKEN:
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
+ insn &= ~(1 << 21);
+ insn |= branch_bit;
+ if (this->is_isa_v2)
+ {
+ // Set 'a' bit. This is 0b00010 in BO field for branch
+ // on CR(BI) insns (BO == 001at or 011at), and 0b01000
+ // for branch on CTR insns (BO == 1a00t or 1a01t).
+ if ((insn & (0x14 << 21)) == (0x04 << 21))
+ insn |= 0x02 << 21;
+ else if ((insn & (0x14 << 21)) == (0x10 << 21))
+ insn |= 0x08 << 21;
+ else
+ break;
+ }
+ else
+ {
+ // Invert 'y' bit if not the default.
+ if (static_cast<Signed_address>(value) < 0)
+ insn ^= 1 << 21;
+ }
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (size == 64)
+ {
+ // Multi-instruction sequences that access the TOC can be
+ // optimized, eg. addis ra,r2,0; addi rb,ra,x;
+ // to nop; addi rb,r2,x;
+ switch (r_type)
+ {
+ default:
+ break;
+
+ case elfcpp::R_POWERPC_GOT_TLSLD16_HA:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_HA:
+ case elfcpp::R_POWERPC_GOT_TPREL16_HA:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_HA:
+ case elfcpp::R_POWERPC_GOT16_HA:
+ case elfcpp::R_PPC64_TOC16_HA:
+ if (parameters->options().toc_optimize())
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
+ Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
+ if ((insn & ((0x3f << 26) | 0x1f << 16))
+ != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("toc optimization is not supported "
+ "for %#08x instruction"), insn);
+ else if (value + 0x8000 < 0x10000)
+ {
+ elfcpp::Swap<32, big_endian>::writeval(iview, nop);
+ return true;
+ }
+ }
+ break;
+
+ case elfcpp::R_POWERPC_GOT_TLSLD16_LO:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_LO:
+ case elfcpp::R_POWERPC_GOT_TPREL16_LO:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_LO:
+ case elfcpp::R_POWERPC_GOT16_LO:
+ case elfcpp::R_PPC64_GOT16_LO_DS:
+ case elfcpp::R_PPC64_TOC16_LO:
+ case elfcpp::R_PPC64_TOC16_LO_DS:
+ if (parameters->options().toc_optimize())
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
+ Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
+ if (!ok_lo_toc_insn(insn))
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("toc optimization is not supported "
+ "for %#08x instruction"), insn);
+ else if (value + 0x8000 < 0x10000)
+ {
+ if ((insn & (0x3f << 26)) == 12u << 26 /* addic */)
+ {
+ // Transform addic to addi when we change reg.
+ insn &= ~((0x3f << 26) | (0x1f << 16));
+ insn |= (14u << 26) | (2 << 16);
+ }
+ else
+ {
+ insn &= ~(0x1f << 16);
+ insn |= 2 << 16;
+ }
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ }
+ }
+ break;
+ }
+ }
+
+ typename Reloc::Overflow_check overflow = Reloc::CHECK_NONE;
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_ADDR32:
+ case elfcpp::R_POWERPC_UADDR32:
+ if (size == 64)
+ overflow = Reloc::CHECK_BITFIELD;
+ break;
+
+ case elfcpp::R_POWERPC_REL32:
+ if (size == 64)
+ overflow = Reloc::CHECK_SIGNED;
+ break;
+
+ case elfcpp::R_POWERPC_ADDR24:
+ case elfcpp::R_POWERPC_ADDR16:
+ case elfcpp::R_POWERPC_UADDR16:
+ case elfcpp::R_PPC64_ADDR16_DS:
+ case elfcpp::R_POWERPC_ADDR14:
+ case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
+ case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
+ overflow = Reloc::CHECK_BITFIELD;
+ break;
+
+ case elfcpp::R_POWERPC_REL24:
+ case elfcpp::R_PPC_PLTREL24:
+ case elfcpp::R_PPC_LOCAL24PC:
+ case elfcpp::R_POWERPC_REL16:
+ case elfcpp::R_PPC64_TOC16:
+ case elfcpp::R_POWERPC_GOT16:
+ case elfcpp::R_POWERPC_SECTOFF:
+ case elfcpp::R_POWERPC_TPREL16:
+ case elfcpp::R_POWERPC_DTPREL16:
+ case elfcpp::R_PPC64_TPREL16_DS:
+ case elfcpp::R_PPC64_DTPREL16_DS:
+ case elfcpp::R_PPC64_TOC16_DS:
+ case elfcpp::R_PPC64_GOT16_DS:
+ case elfcpp::R_PPC64_SECTOFF_DS:
+ case elfcpp::R_POWERPC_REL14:
+ case elfcpp::R_POWERPC_REL14_BRTAKEN:
+ case elfcpp::R_POWERPC_REL14_BRNTAKEN:
+ case elfcpp::R_POWERPC_GOT_TLSGD16:
+ case elfcpp::R_POWERPC_GOT_TLSLD16:
+ case elfcpp::R_POWERPC_GOT_TPREL16:
+ case elfcpp::R_POWERPC_GOT_DTPREL16:
+ overflow = Reloc::CHECK_SIGNED;
+ break;
+ }
+
+ typename Powerpc_relocate_functions<size, big_endian>::Status status
+ = Powerpc_relocate_functions<size, big_endian>::STATUS_OK;
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_NONE:
+ case elfcpp::R_POWERPC_TLS:
+ case elfcpp::R_POWERPC_GNU_VTINHERIT:
+ case elfcpp::R_POWERPC_GNU_VTENTRY:
+ case elfcpp::R_PPC_EMB_MRKREF:
+ break;
+
+ case elfcpp::R_PPC64_ADDR64:
+ case elfcpp::R_PPC64_REL64:
+ case elfcpp::R_PPC64_TOC:
+ Reloc::addr64(view, value);
+ break;
+
+ case elfcpp::R_POWERPC_TPREL:
+ case elfcpp::R_POWERPC_DTPREL:
+ if (size == 64)
+ Reloc::addr64(view, value);
+ else
+ status = Reloc::addr32(view, value, overflow);
+ break;
+
+ case elfcpp::R_PPC64_UADDR64:
+ Reloc::addr64_u(view, value);
+ break;
+
+ case elfcpp::R_POWERPC_ADDR32:
+ status = Reloc::addr32(view, value, overflow);
+ break;
+
+ case elfcpp::R_POWERPC_REL32:
+ case elfcpp::R_POWERPC_UADDR32:
+ status = Reloc::addr32_u(view, value, overflow);
+ break;
+
+ case elfcpp::R_POWERPC_ADDR24:
+ case elfcpp::R_POWERPC_REL24:
+ case elfcpp::R_PPC_PLTREL24:
+ case elfcpp::R_PPC_LOCAL24PC:
+ status = Reloc::addr24(view, value, overflow);
+ break;
+
+ case elfcpp::R_POWERPC_GOT_DTPREL16:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_LO:
+ if (size == 64)
+ {
+ status = Reloc::addr16_ds(view, value, overflow);
+ break;
+ }
+ case elfcpp::R_POWERPC_ADDR16:
+ case elfcpp::R_POWERPC_REL16:
+ case elfcpp::R_PPC64_TOC16:
+ case elfcpp::R_POWERPC_GOT16:
+ case elfcpp::R_POWERPC_SECTOFF:
+ case elfcpp::R_POWERPC_TPREL16:
+ case elfcpp::R_POWERPC_DTPREL16:
+ case elfcpp::R_POWERPC_GOT_TLSGD16:
+ case elfcpp::R_POWERPC_GOT_TLSLD16:
+ case elfcpp::R_POWERPC_GOT_TPREL16:
+ case elfcpp::R_POWERPC_ADDR16_LO:
+ case elfcpp::R_POWERPC_REL16_LO:
+ case elfcpp::R_PPC64_TOC16_LO:
+ case elfcpp::R_POWERPC_GOT16_LO:
+ case elfcpp::R_POWERPC_SECTOFF_LO:
+ case elfcpp::R_POWERPC_TPREL16_LO:
+ case elfcpp::R_POWERPC_DTPREL16_LO:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_LO:
+ case elfcpp::R_POWERPC_GOT_TLSLD16_LO:
+ case elfcpp::R_POWERPC_GOT_TPREL16_LO:
+ status = Reloc::addr16(view, value, overflow);
+ break;
+
+ case elfcpp::R_POWERPC_UADDR16:
+ status = Reloc::addr16_u(view, value, overflow);
+ break;
+
+ case elfcpp::R_POWERPC_ADDR16_HI:
+ case elfcpp::R_POWERPC_REL16_HI:
+ case elfcpp::R_PPC64_TOC16_HI:
+ case elfcpp::R_POWERPC_GOT16_HI:
+ case elfcpp::R_POWERPC_SECTOFF_HI:
+ case elfcpp::R_POWERPC_TPREL16_HI:
+ case elfcpp::R_POWERPC_DTPREL16_HI:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_HI:
+ case elfcpp::R_POWERPC_GOT_TLSLD16_HI:
+ case elfcpp::R_POWERPC_GOT_TPREL16_HI:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_HI:
+ Reloc::addr16_hi(view, value);
+ break;
+
+ case elfcpp::R_POWERPC_ADDR16_HA:
+ case elfcpp::R_POWERPC_REL16_HA:
+ case elfcpp::R_PPC64_TOC16_HA:
+ case elfcpp::R_POWERPC_GOT16_HA:
+ case elfcpp::R_POWERPC_SECTOFF_HA:
+ case elfcpp::R_POWERPC_TPREL16_HA:
+ case elfcpp::R_POWERPC_DTPREL16_HA:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_HA:
+ case elfcpp::R_POWERPC_GOT_TLSLD16_HA:
+ case elfcpp::R_POWERPC_GOT_TPREL16_HA:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_HA:
+ Reloc::addr16_ha(view, value);
+ break;
+
+ case elfcpp::R_PPC64_DTPREL16_HIGHER:
+ if (size == 32)
+ // R_PPC_EMB_NADDR16_LO
+ goto unsupp;
+ case elfcpp::R_PPC64_ADDR16_HIGHER:
+ case elfcpp::R_PPC64_TPREL16_HIGHER:
+ Reloc::addr16_hi2(view, value);
+ break;
+
+ case elfcpp::R_PPC64_DTPREL16_HIGHERA:
+ if (size == 32)
+ // R_PPC_EMB_NADDR16_HI
+ goto unsupp;
+ case elfcpp::R_PPC64_ADDR16_HIGHERA:
+ case elfcpp::R_PPC64_TPREL16_HIGHERA:
+ Reloc::addr16_ha2(view, value);
+ break;
+
+ case elfcpp::R_PPC64_DTPREL16_HIGHEST:
+ if (size == 32)
+ // R_PPC_EMB_NADDR16_HA
+ goto unsupp;
+ case elfcpp::R_PPC64_ADDR16_HIGHEST:
+ case elfcpp::R_PPC64_TPREL16_HIGHEST:
+ Reloc::addr16_hi3(view, value);
+ break;
+
+ case elfcpp::R_PPC64_DTPREL16_HIGHESTA:
+ if (size == 32)
+ // R_PPC_EMB_SDAI16
+ goto unsupp;
+ case elfcpp::R_PPC64_ADDR16_HIGHESTA:
+ case elfcpp::R_PPC64_TPREL16_HIGHESTA:
+ Reloc::addr16_ha3(view, value);
+ break;
+
+ case elfcpp::R_PPC64_DTPREL16_DS:
+ case elfcpp::R_PPC64_DTPREL16_LO_DS:
+ if (size == 32)
+ // R_PPC_EMB_NADDR32, R_PPC_EMB_NADDR16
+ goto unsupp;
+ case elfcpp::R_PPC64_TPREL16_DS:
+ case elfcpp::R_PPC64_TPREL16_LO_DS:
+ if (size == 32)
+ // R_PPC_TLSGD, R_PPC_TLSLD
+ break;
+ case elfcpp::R_PPC64_ADDR16_DS:
+ case elfcpp::R_PPC64_ADDR16_LO_DS:
+ case elfcpp::R_PPC64_TOC16_DS:
+ case elfcpp::R_PPC64_TOC16_LO_DS:
+ case elfcpp::R_PPC64_GOT16_DS:
+ case elfcpp::R_PPC64_GOT16_LO_DS:
+ case elfcpp::R_PPC64_SECTOFF_DS:
+ case elfcpp::R_PPC64_SECTOFF_LO_DS:
+ status = Reloc::addr16_ds(view, value, overflow);
+ break;
+
+ case elfcpp::R_POWERPC_ADDR14:
+ case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
+ case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
+ case elfcpp::R_POWERPC_REL14:
+ case elfcpp::R_POWERPC_REL14_BRTAKEN:
+ case elfcpp::R_POWERPC_REL14_BRNTAKEN:
+ status = Reloc::addr14(view, value, overflow);
+ break;
+
+ case elfcpp::R_POWERPC_COPY:
+ case elfcpp::R_POWERPC_GLOB_DAT:
+ case elfcpp::R_POWERPC_JMP_SLOT:
+ case elfcpp::R_POWERPC_RELATIVE:
+ case elfcpp::R_POWERPC_DTPMOD:
+ case elfcpp::R_PPC64_JMP_IREL:
+ case elfcpp::R_POWERPC_IRELATIVE:
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unexpected reloc %u in object file"),
+ r_type);
+ break;
+
+ case elfcpp::R_PPC_EMB_SDA21:
+ if (size == 32)
+ goto unsupp;
+ else
+ {
+ // R_PPC64_TOCSAVE. For the time being this can be ignored.
+ }
+ break;
+
+ case elfcpp::R_PPC_EMB_SDA2I16:
+ case elfcpp::R_PPC_EMB_SDA2REL:
+ if (size == 32)
+ goto unsupp;
+ // R_PPC64_TLSGD, R_PPC64_TLSLD
+ break;
+
+ case elfcpp::R_POWERPC_PLT32:
+ case elfcpp::R_POWERPC_PLTREL32:
+ case elfcpp::R_POWERPC_PLT16_LO:
+ case elfcpp::R_POWERPC_PLT16_HI:
+ case elfcpp::R_POWERPC_PLT16_HA:
+ case elfcpp::R_PPC_SDAREL16:
+ case elfcpp::R_POWERPC_ADDR30:
+ case elfcpp::R_PPC64_PLT64:
+ case elfcpp::R_PPC64_PLTREL64:
+ case elfcpp::R_PPC64_PLTGOT16:
+ case elfcpp::R_PPC64_PLTGOT16_LO:
+ case elfcpp::R_PPC64_PLTGOT16_HI:
+ case elfcpp::R_PPC64_PLTGOT16_HA:
+ case elfcpp::R_PPC64_PLT16_LO_DS:
+ case elfcpp::R_PPC64_PLTGOT16_DS:
+ case elfcpp::R_PPC64_PLTGOT16_LO_DS:
+ case elfcpp::R_PPC_EMB_RELSEC16:
+ case elfcpp::R_PPC_EMB_RELST_LO:
+ case elfcpp::R_PPC_EMB_RELST_HI:
+ case elfcpp::R_PPC_EMB_RELST_HA:
+ case elfcpp::R_PPC_EMB_BIT_FLD:
+ case elfcpp::R_PPC_EMB_RELSDA:
+ case elfcpp::R_PPC_TOC16:
+ default:
+ unsupp:
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unsupported reloc %u"),
+ r_type);
+ break;
+ }
+ if (status != Powerpc_relocate_functions<size, big_endian>::STATUS_OK)
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("relocation overflow"));
+
+ return true;
+}
+
+// Relocate section data.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::relocate_section(
+ const Relocate_info<size, 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,
+ Address address,
+ section_size_type view_size,
+ const Reloc_symbol_changes* reloc_symbol_changes)
+{
+ typedef Target_powerpc<size, big_endian> Powerpc;
+ typedef typename Target_powerpc<size, big_endian>::Relocate Powerpc_relocate;
+ typedef typename Target_powerpc<size, big_endian>::Relocate_comdat_behavior
+ Powerpc_comdat_behavior;
+
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+
+ gold::relocate_section<size, big_endian, Powerpc, elfcpp::SHT_RELA,
+ Powerpc_relocate, Powerpc_comdat_behavior>(
+ relinfo,
+ this,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ view,
+ address,
+ view_size,
+ reloc_symbol_changes);
+}
+
+class Powerpc_scan_relocatable_reloc
+{
+public:
+ // Return the strategy to use for a local symbol which is not a
+ // section symbol, given the relocation type.
+ inline Relocatable_relocs::Reloc_strategy
+ local_non_section_strategy(unsigned int r_type, Relobj*, unsigned int r_sym)
+ {
+ if (r_type == 0 && r_sym == 0)
+ return Relocatable_relocs::RELOC_DISCARD;
+ return Relocatable_relocs::RELOC_COPY;
+ }
+
+ // 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, Relobj*)
+ {
+ return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA;
+ }
+
+ // Return the strategy to use for a global symbol, given the
+ // relocation type, the object, and the symbol index.
+ inline Relocatable_relocs::Reloc_strategy
+ global_strategy(unsigned int r_type, Relobj*, unsigned int)
+ {
+ if (r_type == elfcpp::R_PPC_PLTREL24)
+ return Relocatable_relocs::RELOC_SPECIAL;
+ return Relocatable_relocs::RELOC_COPY;
+ }
+};
+
+// Scan the relocs during a relocatable link.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::scan_relocatable_relocs(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols,
+ Relocatable_relocs* rr)
+{
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+
+ gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
+ Powerpc_scan_relocatable_reloc>(
+ 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.
+// This is a modified version of the function by the same name in
+// target-reloc.h. Using relocate_special_relocatable for
+// R_PPC_PLTREL24 would require duplication of the entire body of the
+// loop, so we may as well duplicate the whole thing.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::relocate_relocs(
+ const Relocate_info<size, big_endian>* relinfo,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
+ const Relocatable_relocs* rr,
+ unsigned char*,
+ Address view_address,
+ section_size_type,
+ unsigned char* reloc_view,
+ section_size_type reloc_view_size)
+{
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+
+ typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
+ Reltype;
+ typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc_write
+ Reltype_write;
+ const int reloc_size
+ = Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+
+ Powerpc_relobj<size, big_endian>* const object
+ = static_cast<Powerpc_relobj<size, big_endian>*>(relinfo->object);
+ const unsigned int local_count = object->local_symbol_count();
+ unsigned int got2_shndx = object->got2_shndx();
+ Address got2_addend = 0;
+ if (got2_shndx != 0)
+ {
+ got2_addend = object->get_output_section_offset(got2_shndx);
+ gold_assert(got2_addend != invalid_address);
+ }
+
+ unsigned char* pwrite = reloc_view;
+ bool zap_next = false;
+ for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+ Relocatable_relocs::Reloc_strategy strategy = rr->strategy(i);
+ if (strategy == Relocatable_relocs::RELOC_DISCARD)
+ continue;
+
+ Reltype reloc(prelocs);
+ Reltype_write reloc_write(pwrite);
+
+ Address offset = reloc.get_r_offset();
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+ const unsigned int orig_r_sym = r_sym;
+ typename elfcpp::Elf_types<size>::Elf_Swxword addend
+ = reloc.get_r_addend();
+ const Symbol* gsym = NULL;
+
+ if (zap_next)
+ {
+ // We could arrange to discard these and other relocs for
+ // tls optimised sequences in the strategy methods, but for
+ // now do as BFD ld does.
+ r_type = elfcpp::R_POWERPC_NONE;
+ zap_next = false;
+ }
+
+ // Get the new symbol index.
+ if (r_sym < local_count)
+ {
+ switch (strategy)
+ {
+ case Relocatable_relocs::RELOC_COPY:
+ case Relocatable_relocs::RELOC_SPECIAL:
+ if (r_sym != 0)
+ {
+ r_sym = object->symtab_index(r_sym);
+ gold_assert(r_sym != -1U);
+ }
+ break;
+
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA:
+ {
+ // 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.
+ gold_assert(r_sym < local_count);
+ 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());
+ r_sym = os->symtab_index();
+ }
+ break;
+
+ default:
+ gold_unreachable();
+ }
+ }
+ else
+ {
+ gsym = object->global_symbol(r_sym);
+ gold_assert(gsym != NULL);
+ if (gsym->is_forwarder())
+ gsym = relinfo->symtab->resolve_forwards(gsym);
+
+ gold_assert(gsym->has_symtab_index());
+ r_sym = gsym->symtab_index();
+ }
+
+ // Get the new offset--the location in the output section where
+ // this relocation should be applied.
+ if (static_cast<Address>(offset_in_output_section) != invalid_address)
+ offset += offset_in_output_section;
+ else
+ {
+ section_offset_type sot_offset =
+ convert_types<section_offset_type, Address>(offset);
+ section_offset_type new_sot_offset =
+ output_section->output_offset(object, relinfo->data_shndx,
+ sot_offset);
+ gold_assert(new_sot_offset != -1);
+ 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())
+ {
+ offset += view_address;
+ if (static_cast<Address>(offset_in_output_section) != invalid_address)
+ offset -= offset_in_output_section;
+ }
+
+ // Handle the reloc addend based on the strategy.
+ if (strategy == Relocatable_relocs::RELOC_COPY)
+ ;
+ else if (strategy == Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA)
+ {
+ const Symbol_value<size>* psymval = object->local_symbol(orig_r_sym);
+ addend = psymval->value(object, addend);
+ }
+ else if (strategy == Relocatable_relocs::RELOC_SPECIAL)
+ {
+ if (addend >= 32768)
+ addend += got2_addend;
+ }
+ else
+ gold_unreachable();
+
+ if (!parameters->options().relocatable())
+ {
+ if (r_type == elfcpp::R_POWERPC_GOT_TLSGD16
+ || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_LO
+ || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_HI
+ || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_HA)
+ {
+ // First instruction of a global dynamic sequence,
+ // arg setup insn.
+ const bool final = gsym == NULL || gsym->final_value_is_known();
+ switch (this->optimize_tls_gd(final))
+ {
+ case tls::TLSOPT_TO_IE:
+ r_type += (elfcpp::R_POWERPC_GOT_TPREL16
+ - elfcpp::R_POWERPC_GOT_TLSGD16);
+ break;
+ case tls::TLSOPT_TO_LE:
+ if (r_type == elfcpp::R_POWERPC_GOT_TLSGD16
+ || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_LO)
+ r_type = elfcpp::R_POWERPC_TPREL16_HA;
+ else
+ {
+ r_type = elfcpp::R_POWERPC_NONE;
+ offset -= 2 * big_endian;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else if (r_type == elfcpp::R_POWERPC_GOT_TLSLD16
+ || r_type == elfcpp::R_POWERPC_GOT_TLSLD16_LO
+ || r_type == elfcpp::R_POWERPC_GOT_TLSLD16_HI
+ || r_type == elfcpp::R_POWERPC_GOT_TLSLD16_HA)
+ {
+ // First instruction of a local dynamic sequence,
+ // arg setup insn.
+ if (this->optimize_tls_ld() == tls::TLSOPT_TO_LE)
+ {
+ if (r_type == elfcpp::R_POWERPC_GOT_TLSLD16
+ || r_type == elfcpp::R_POWERPC_GOT_TLSLD16_LO)
+ {
+ r_type = elfcpp::R_POWERPC_TPREL16_HA;
+ const Output_section* os = relinfo->layout->tls_segment()
+ ->first_section();
+ gold_assert(os != NULL);
+ gold_assert(os->needs_symtab_index());
+ r_sym = os->symtab_index();
+ addend = dtp_offset;
+ }
+ else
+ {
+ r_type = elfcpp::R_POWERPC_NONE;
+ offset -= 2 * big_endian;
+ }
+ }
+ }
+ else if (r_type == elfcpp::R_POWERPC_GOT_TPREL16
+ || r_type == elfcpp::R_POWERPC_GOT_TPREL16_LO
+ || r_type == elfcpp::R_POWERPC_GOT_TPREL16_HI
+ || r_type == elfcpp::R_POWERPC_GOT_TPREL16_HA)
+ {
+ // First instruction of initial exec sequence.
+ const bool final = gsym == NULL || gsym->final_value_is_known();
+ if (this->optimize_tls_ie(final) == tls::TLSOPT_TO_LE)
+ {
+ if (r_type == elfcpp::R_POWERPC_GOT_TPREL16
+ || r_type == elfcpp::R_POWERPC_GOT_TPREL16_LO)
+ r_type = elfcpp::R_POWERPC_TPREL16_HA;
+ else
+ {
+ r_type = elfcpp::R_POWERPC_NONE;
+ offset -= 2 * big_endian;
+ }
+ }
+ }
+ else if ((size == 64 && r_type == elfcpp::R_PPC64_TLSGD)
+ || (size == 32 && r_type == elfcpp::R_PPC_TLSGD))
+ {
+ // Second instruction of a global dynamic sequence,
+ // the __tls_get_addr call
+ const bool final = gsym == NULL || gsym->final_value_is_known();
+ switch (this->optimize_tls_gd(final))
+ {
+ case tls::TLSOPT_TO_IE:
+ r_type = elfcpp::R_POWERPC_NONE;
+ zap_next = true;
+ break;
+ case tls::TLSOPT_TO_LE:
+ r_type = elfcpp::R_POWERPC_TPREL16_LO;
+ offset += 2 * big_endian;
+ zap_next = true;
+ break;
+ default:
+ break;
+ }
+ }
+ else if ((size == 64 && r_type == elfcpp::R_PPC64_TLSLD)
+ || (size == 32 && r_type == elfcpp::R_PPC_TLSLD))
+ {
+ // Second instruction of a local dynamic sequence,
+ // the __tls_get_addr call
+ if (this->optimize_tls_ld() == tls::TLSOPT_TO_LE)
+ {
+ const Output_section* os = relinfo->layout->tls_segment()
+ ->first_section();
+ gold_assert(os != NULL);
+ gold_assert(os->needs_symtab_index());
+ r_sym = os->symtab_index();
+ addend = dtp_offset;
+ r_type = elfcpp::R_POWERPC_TPREL16_LO;
+ offset += 2 * big_endian;
+ zap_next = true;
+ }
+ }
+ else if (r_type == elfcpp::R_POWERPC_TLS)
+ {
+ // Second instruction of an initial exec sequence
+ const bool final = gsym == NULL || gsym->final_value_is_known();
+ if (this->optimize_tls_ie(final) == tls::TLSOPT_TO_LE)
+ {
+ r_type = elfcpp::R_POWERPC_TPREL16_LO;
+ offset += 2 * big_endian;
+ }
+ }
+ }
+
+ reloc_write.put_r_offset(offset);
+ reloc_write.put_r_info(elfcpp::elf_r_info<size>(r_sym, r_type));
+ reloc_write.put_r_addend(addend);
+
+ pwrite += reloc_size;
+ }
+
+ gold_assert(static_cast<section_size_type>(pwrite - reloc_view)
+ == reloc_view_size);
+}
+
+// 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<int size, bool big_endian>
+uint64_t
+Target_powerpc<size, big_endian>::do_dynsym_value(const Symbol* gsym) const
+{
+ if (size == 32)
+ {
+ gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset());
+ for (typename Stub_tables::const_iterator p = this->stub_tables_.begin();
+ p != this->stub_tables_.end();
+ ++p)
+ {
+ Address off = (*p)->find_plt_call_entry(gsym);
+ if (off != invalid_address)
+ return (*p)->stub_address() + off;
+ }
+ }
+ gold_unreachable();
+}
+
+// Return the PLT address to use for a local symbol.
+template<int size, bool big_endian>
+uint64_t
+Target_powerpc<size, big_endian>::do_plt_address_for_local(
+ const Relobj* object,
+ unsigned int symndx) const
+{
+ if (size == 32)
+ {
+ const Sized_relobj<size, big_endian>* relobj
+ = static_cast<const Sized_relobj<size, big_endian>*>(object);
+ for (typename Stub_tables::const_iterator p = this->stub_tables_.begin();
+ p != this->stub_tables_.end();
+ ++p)
+ {
+ Address off = (*p)->find_plt_call_entry(relobj->sized_relobj(),
+ symndx);
+ if (off != invalid_address)
+ return (*p)->stub_address() + off;
+ }
+ }
+ gold_unreachable();
+}
+
+// Return the PLT address to use for a global symbol.
+template<int size, bool big_endian>
+uint64_t
+Target_powerpc<size, big_endian>::do_plt_address_for_global(
+ const Symbol* gsym) const
+{
+ if (size == 32)
+ {
+ for (typename Stub_tables::const_iterator p = this->stub_tables_.begin();
+ p != this->stub_tables_.end();
+ ++p)
+ {
+ Address off = (*p)->find_plt_call_entry(gsym);
+ if (off != invalid_address)
+ return (*p)->stub_address() + off;
+ }
+ }
+ gold_unreachable();
+}
+
+// Return the offset to use for the GOT_INDX'th got entry which is
+// for a local tls symbol specified by OBJECT, SYMNDX.
+template<int size, bool big_endian>
+int64_t
+Target_powerpc<size, big_endian>::do_tls_offset_for_local(
+ const Relobj* object,
+ unsigned int symndx,
+ unsigned int got_indx) const
+{
+ const Powerpc_relobj<size, big_endian>* ppc_object
+ = static_cast<const Powerpc_relobj<size, big_endian>*>(object);
+ if (ppc_object->local_symbol(symndx)->is_tls_symbol())
+ {
+ for (Got_type got_type = GOT_TYPE_TLSGD;
+ got_type <= GOT_TYPE_TPREL;
+ got_type = Got_type(got_type + 1))
+ if (ppc_object->local_has_got_offset(symndx, got_type))
+ {
+ unsigned int off = ppc_object->local_got_offset(symndx, got_type);
+ if (got_type == GOT_TYPE_TLSGD)
+ off += size / 8;
+ if (off == got_indx * (size / 8))
+ {
+ if (got_type == GOT_TYPE_TPREL)
+ return -tp_offset;
+ else
+ return -dtp_offset;
+ }
+ }
+ }
+ gold_unreachable();
+}
+
+// Return the offset to use for the GOT_INDX'th got entry which is
+// for global tls symbol GSYM.
+template<int size, bool big_endian>
+int64_t
+Target_powerpc<size, big_endian>::do_tls_offset_for_global(
+ Symbol* gsym,
+ unsigned int got_indx) const
+{
+ if (gsym->type() == elfcpp::STT_TLS)
+ {
+ for (Got_type got_type = GOT_TYPE_TLSGD;
+ got_type <= GOT_TYPE_TPREL;
+ got_type = Got_type(got_type + 1))
+ if (gsym->has_got_offset(got_type))
+ {
+ unsigned int off = gsym->got_offset(got_type);
+ if (got_type == GOT_TYPE_TLSGD)
+ off += size / 8;
+ if (off == got_indx * (size / 8))
+ {
+ if (got_type == GOT_TYPE_TPREL)
+ return -tp_offset;
+ else
+ return -dtp_offset;
+ }
+ }
+ }
+ gold_unreachable();
+}
+
+// The selector for powerpc object files.
+
+template<int size, bool big_endian>
+class Target_selector_powerpc : public Target_selector
+{
+public:
+ Target_selector_powerpc()
+ : Target_selector(size == 64 ? elfcpp::EM_PPC64 : elfcpp::EM_PPC,
+ size, big_endian,
+ (size == 64
+ ? (big_endian ? "elf64-powerpc" : "elf64-powerpcle")
+ : (big_endian ? "elf32-powerpc" : "elf32-powerpcle")),
+ (size == 64
+ ? (big_endian ? "elf64ppc" : "elf64lppc")
+ : (big_endian ? "elf32ppc" : "elf32lppc")))
+ { }
+
+ virtual Target*
+ do_instantiate_target()
+ { return new Target_powerpc<size, big_endian>(); }
+};
+
+Target_selector_powerpc<32, true> target_selector_ppc32;
+Target_selector_powerpc<32, false> target_selector_ppc32le;
+Target_selector_powerpc<64, true> target_selector_ppc64;
+Target_selector_powerpc<64, false> target_selector_ppc64le;
+
+// Instantiate these constants for -O0
+template<int size, bool big_endian>
+const int Output_data_glink<size, big_endian>::pltresolve_size;
+template<int size, bool big_endian>
+const typename Stub_table<size, big_endian>::Address
+ Stub_table<size, big_endian>::invalid_address;
+template<int size, bool big_endian>
+const typename Target_powerpc<size, big_endian>::Address
+ Target_powerpc<size, big_endian>::invalid_address;
+
+} // End anonymous namespace.
diff --git a/binutils-2.25/gold/pread.c b/binutils-2.25/gold/pread.c
new file mode 100644
index 00000000..2f47565e
--- /dev/null
+++ b/binutils-2.25/gold/pread.c
@@ -0,0 +1,42 @@
+/* pread.c -- version of pread for gold. */
+
+/* Copyright 2006, 2007, 2009 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>.
+
+ 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 implements pread for systems which don't have it. This
+ file is only compiled if pread is not present on the system. This
+ is not an exact version of pread, as it does not preserve the
+ current file offset. */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+extern ssize_t pread (int, void *, size_t, off_t);
+
+ssize_t
+pread (int fd, void *buf, size_t count, off_t offset)
+{
+ if (lseek(fd, offset, SEEK_SET) != offset)
+ return -1;
+ return read(fd, buf, count);
+}
diff --git a/binutils-2.25/gold/readsyms.cc b/binutils-2.25/gold/readsyms.cc
new file mode 100644
index 00000000..8e52ccb7
--- /dev/null
+++ b/binutils-2.25/gold/readsyms.cc
@@ -0,0 +1,946 @@
+// readsyms.cc -- read input file symbols for gold
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cstring>
+
+#include "elfcpp.h"
+#include "options.h"
+#include "dirsearch.h"
+#include "symtab.h"
+#include "object.h"
+#include "archive.h"
+#include "script.h"
+#include "readsyms.h"
+#include "plugin.h"
+#include "layout.h"
+#include "incremental.h"
+
+namespace gold
+{
+
+// If we fail to open the object, then we won't create an Add_symbols
+// task. However, we still need to unblock the token, or else the
+// link won't proceed to generate more error messages. We can only
+// unblock tokens when the workqueue lock is held, so we need a dummy
+// task to do that. The dummy task has to maintain the right sequence
+// of blocks, so we need both this_blocker and next_blocker.
+
+class Unblock_token : public Task
+{
+ public:
+ Unblock_token(Task_token* this_blocker, Task_token* next_blocker)
+ : this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Unblock_token()
+ {
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ }
+
+ Task_token*
+ is_runnable()
+ {
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ return NULL;
+ }
+
+ void
+ locks(Task_locker* tl)
+ { tl->add(this, this->next_blocker_); }
+
+ void
+ run(Workqueue*)
+ { }
+
+ std::string
+ get_name() const
+ { return "Unblock_token"; }
+
+ private:
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// Class read_symbols.
+
+Read_symbols::~Read_symbols()
+{
+ // The this_blocker_ and next_blocker_ pointers are passed on to the
+ // Add_symbols task.
+}
+
+// If appropriate, issue a warning about skipping an incompatible
+// file.
+
+void
+Read_symbols::incompatible_warning(const Input_argument* input_argument,
+ const Input_file* input_file)
+{
+ if (parameters->options().warn_search_mismatch())
+ gold_warning("skipping incompatible %s while searching for %s",
+ input_file->filename().c_str(),
+ input_argument->file().name());
+}
+
+// Requeue a Read_symbols task to search for the next object with the
+// same name.
+
+void
+Read_symbols::requeue(Workqueue* workqueue, Input_objects* input_objects,
+ Symbol_table* symtab, Layout* layout, Dirsearch* dirpath,
+ int dirindex, Mapfile* mapfile,
+ const Input_argument* input_argument,
+ Input_group* input_group, Task_token* next_blocker)
+{
+ // Bump the directory search index.
+ ++dirindex;
+
+ // We don't need to worry about this_blocker, since we already
+ // reached it. However, we are removing the blocker on next_blocker
+ // because the calling task is completing. So we need to add a new
+ // blocker. Since next_blocker may be shared by several tasks, we
+ // need to increment the count with the workqueue lock held.
+ workqueue->add_blocker(next_blocker);
+
+ workqueue->queue(new Read_symbols(input_objects, symtab, layout, dirpath,
+ dirindex, mapfile, input_argument,
+ input_group, NULL, NULL, next_blocker));
+}
+
+// Return whether a Read_symbols task is runnable. We can read an
+// ordinary input file immediately. For an archive specified using
+// -l, we have to wait until the search path is complete.
+
+Task_token*
+Read_symbols::is_runnable()
+{
+ if (this->input_argument_->is_file()
+ && this->input_argument_->file().may_need_search()
+ && this->dirpath_->token()->is_blocked())
+ return this->dirpath_->token();
+
+ return NULL;
+}
+
+// Return a Task_locker for a Read_symbols task. We don't need any
+// locks here.
+
+void
+Read_symbols::locks(Task_locker* tl)
+{
+ if (this->member_ != NULL)
+ tl->add(this, this->next_blocker_);
+}
+
+// Run a Read_symbols task.
+
+void
+Read_symbols::run(Workqueue* workqueue)
+{
+ // If we didn't queue a new task, then we need to explicitly unblock
+ // the token. If the object is a member of a lib group, however,
+ // the token was already added to the list of locks for the task,
+ // and it will be unblocked automatically at the end of the task.
+ if (!this->do_read_symbols(workqueue) && this->member_ == NULL)
+ workqueue->queue_soon(new Unblock_token(this->this_blocker_,
+ this->next_blocker_));
+}
+
+// Handle a whole lib group. Other than collecting statistics, this just
+// mimics what we do for regular object files in the command line.
+
+bool
+Read_symbols::do_whole_lib_group(Workqueue* workqueue)
+{
+ const Input_file_lib* lib_group = this->input_argument_->lib();
+
+ ++Lib_group::total_lib_groups;
+
+ Task_token* this_blocker = this->this_blocker_;
+ for (Input_file_lib::const_iterator i = lib_group->begin();
+ i != lib_group->end();
+ ++i)
+ {
+ ++Lib_group::total_members;
+ ++Lib_group::total_members_loaded;
+
+ const Input_argument* arg = &*i;
+
+ Task_token* next_blocker;
+ if (i != lib_group->end() - 1)
+ {
+ next_blocker = new Task_token(true);
+ next_blocker->add_blocker();
+ }
+ else
+ next_blocker = this->next_blocker_;
+
+ workqueue->queue_soon(new Read_symbols(this->input_objects_,
+ this->symtab_, this->layout_,
+ this->dirpath_, this->dirindex_,
+ this->mapfile_, arg, NULL,
+ NULL, this_blocker, next_blocker));
+ this_blocker = next_blocker;
+ }
+
+ return true;
+}
+
+// Handle a lib group. We set Read_symbols Tasks as usual, but have them
+// just record the symbol data instead of adding the objects. We also start
+// a Add_lib_group_symbols Task which runs after we've read all the symbols.
+// In that task we process the members in a loop until we are done.
+
+bool
+Read_symbols::do_lib_group(Workqueue* workqueue)
+{
+ const Input_file_lib* lib_group = this->input_argument_->lib();
+
+ if (lib_group->options().whole_archive())
+ return this->do_whole_lib_group(workqueue);
+
+ Lib_group* lib = new Lib_group(lib_group, this);
+
+ Add_lib_group_symbols* add_lib_group_symbols =
+ new Add_lib_group_symbols(this->symtab_, this->layout_,
+ this->input_objects_,
+ lib, this->next_blocker_);
+
+
+ Task_token* next_blocker = new Task_token(true);
+ int j = 0;
+ for (Input_file_lib::const_iterator i = lib_group->begin();
+ i != lib_group->end();
+ ++i, ++j)
+ {
+ const Input_argument* arg = &*i;
+ Archive_member* m = lib->get_member(j);
+
+ next_blocker->add_blocker();
+
+ // Since this Read_symbols will not create an Add_symbols,
+ // just pass NULL as this_blocker.
+ workqueue->queue_soon(new Read_symbols(this->input_objects_,
+ this->symtab_, this->layout_,
+ this->dirpath_, this->dirindex_,
+ this->mapfile_, arg, NULL,
+ m, NULL, next_blocker));
+ }
+
+ add_lib_group_symbols->set_blocker(next_blocker, this->this_blocker_);
+ workqueue->queue_soon(add_lib_group_symbols);
+
+ return true;
+}
+
+// Open the file and read the symbols. Return true if a new task was
+// queued, false if that could not happen due to some error.
+
+bool
+Read_symbols::do_read_symbols(Workqueue* workqueue)
+{
+ if (this->input_argument_->is_group())
+ {
+ gold_assert(this->input_group_ == NULL);
+ this->do_group(workqueue);
+ return true;
+ }
+
+ if (this->input_argument_->is_lib())
+ return this->do_lib_group(workqueue);
+
+ Input_file* input_file = new Input_file(&this->input_argument_->file());
+ if (!input_file->open(*this->dirpath_, this, &this->dirindex_))
+ return false;
+
+ // Read enough of the file to pick up the entire ELF header.
+
+ off_t filesize = input_file->file().filesize();
+
+ if (filesize == 0)
+ {
+ gold_error(_("%s: file is empty"),
+ input_file->file().filename().c_str());
+ return false;
+ }
+
+ const unsigned char* ehdr;
+ int read_size;
+ bool is_elf = is_elf_object(input_file, 0, &ehdr, &read_size);
+
+ if (read_size >= Archive::sarmag)
+ {
+ bool is_thin_archive
+ = memcmp(ehdr, Archive::armagt, Archive::sarmag) == 0;
+ if (is_thin_archive
+ || memcmp(ehdr, Archive::armag, Archive::sarmag) == 0)
+ {
+ // This is an archive.
+ Archive* arch = new Archive(this->input_argument_->file().name(),
+ input_file, is_thin_archive,
+ this->dirpath_, this);
+ arch->setup();
+
+ // Unlock the archive so it can be used in the next task.
+ arch->unlock(this);
+
+ workqueue->queue_next(new Add_archive_symbols(this->symtab_,
+ this->layout_,
+ this->input_objects_,
+ this->dirpath_,
+ this->dirindex_,
+ this->mapfile_,
+ this->input_argument_,
+ arch,
+ this->input_group_,
+ this->this_blocker_,
+ this->next_blocker_));
+ return true;
+ }
+ }
+
+ Object* elf_obj = NULL;
+ bool unconfigured;
+ bool* punconfigured = NULL;
+ if (is_elf)
+ {
+ // This is an ELF object.
+
+ unconfigured = false;
+ punconfigured = (input_file->will_search_for()
+ ? &unconfigured
+ : NULL);
+ elf_obj = make_elf_object(input_file->filename(),
+ input_file, 0, ehdr, read_size,
+ punconfigured);
+ }
+
+ if (parameters->options().has_plugins())
+ {
+ Pluginobj* obj = parameters->options().plugins()->claim_file(input_file,
+ 0, filesize,
+ elf_obj);
+ if (obj != NULL)
+ {
+ // Delete the elf_obj, this file has been claimed.
+ if (elf_obj != NULL)
+ delete elf_obj;
+
+ // The input file was claimed by a plugin, and its symbols
+ // have been provided by the plugin.
+
+ // We are done with the file at this point, so unlock it.
+ obj->unlock(this);
+
+ if (this->member_ != NULL)
+ {
+ this->member_->sd_ = NULL;
+ this->member_->obj_ = obj;
+ return true;
+ }
+
+ workqueue->queue_next(new Add_symbols(this->input_objects_,
+ this->symtab_,
+ this->layout_,
+ this->dirpath_,
+ this->dirindex_,
+ this->mapfile_,
+ this->input_argument_,
+ obj,
+ NULL,
+ NULL,
+ this->this_blocker_,
+ this->next_blocker_));
+ return true;
+ }
+ }
+
+ if (is_elf)
+ {
+ // This is an ELF object.
+
+ if (elf_obj == NULL)
+ {
+ if (unconfigured)
+ {
+ Read_symbols::incompatible_warning(this->input_argument_,
+ input_file);
+ input_file->file().release();
+ input_file->file().unlock(this);
+ delete input_file;
+ ++this->dirindex_;
+ return this->do_read_symbols(workqueue);
+ }
+ return false;
+ }
+
+ Read_symbols_data* sd = new Read_symbols_data;
+ elf_obj->read_symbols(sd);
+
+ // Opening the file locked it, so now we need to unlock it. We
+ // need to unlock it before queuing the Add_symbols task,
+ // because the workqueue doesn't know about our lock on the
+ // file. If we queue the Add_symbols task first, it will be
+ // stuck on the end of the file lock, but since the workqueue
+ // doesn't know about that lock, it will never release the
+ // Add_symbols task.
+
+ input_file->file().unlock(this);
+
+ if (this->member_ != NULL)
+ {
+ this->member_->sd_ = sd;
+ this->member_->obj_ = elf_obj;
+ this->member_->arg_serial_ =
+ this->input_argument_->file().arg_serial();
+ return true;
+ }
+
+ // We use queue_next because everything is cached for this
+ // task to run right away if possible.
+
+ workqueue->queue_next(new Add_symbols(this->input_objects_,
+ this->symtab_, this->layout_,
+ this->dirpath_,
+ this->dirindex_,
+ this->mapfile_,
+ this->input_argument_,
+ elf_obj,
+ NULL,
+ sd,
+ this->this_blocker_,
+ this->next_blocker_));
+
+ return true;
+ }
+
+ // Queue up a task to try to parse this file as a script. We use a
+ // separate task so that the script will be read in order with other
+ // objects named on the command line. Also so that we don't try to
+ // read multiple scripts simultaneously, which could lead to
+ // unpredictable changes to the General_options structure.
+
+ workqueue->queue_soon(new Read_script(this->symtab_,
+ this->layout_,
+ this->dirpath_,
+ this->dirindex_,
+ this->input_objects_,
+ this->mapfile_,
+ this->input_group_,
+ this->input_argument_,
+ input_file,
+ this->this_blocker_,
+ this->next_blocker_));
+ return true;
+}
+
+// Handle a group. We need to walk through the arguments over and
+// over until we don't see any new undefined symbols. We do this by
+// setting off Read_symbols Tasks as usual, but recording the archive
+// entries instead of deleting them. We also start a Finish_group
+// Task which runs after we've read all the symbols. In that task we
+// process the archives in a loop until we are done.
+
+void
+Read_symbols::do_group(Workqueue* workqueue)
+{
+ Input_group* input_group = new Input_group();
+
+ const Input_file_group* group = this->input_argument_->group();
+ Task_token* this_blocker = this->this_blocker_;
+
+ Finish_group* finish_group = new Finish_group(this->input_objects_,
+ this->symtab_,
+ this->layout_,
+ this->mapfile_,
+ input_group,
+ this->next_blocker_);
+
+ Task_token* next_blocker = new Task_token(true);
+ next_blocker->add_blocker();
+ workqueue->queue_soon(new Start_group(this->symtab_, finish_group,
+ this_blocker, next_blocker));
+ this_blocker = next_blocker;
+
+ for (Input_file_group::const_iterator p = group->begin();
+ p != group->end();
+ ++p)
+ {
+ const Input_argument* arg = &*p;
+ gold_assert(arg->is_file());
+
+ next_blocker = new Task_token(true);
+ next_blocker->add_blocker();
+ workqueue->queue_soon(new Read_symbols(this->input_objects_,
+ this->symtab_, this->layout_,
+ this->dirpath_, this->dirindex_,
+ this->mapfile_, arg, input_group,
+ NULL, this_blocker, next_blocker));
+ this_blocker = next_blocker;
+ }
+
+ finish_group->set_blocker(this_blocker);
+
+ workqueue->queue_soon(finish_group);
+}
+
+// Return a debugging name for a Read_symbols task.
+
+std::string
+Read_symbols::get_name() const
+{
+ if (this->input_argument_->is_group())
+ {
+ std::string ret("Read_symbols group (");
+ bool add_space = false;
+ const Input_file_group* group = this->input_argument_->group();
+ for (Input_file_group::const_iterator p = group->begin();
+ p != group->end();
+ ++p)
+ {
+ if (add_space)
+ ret += ' ';
+ ret += p->file().name();
+ add_space = true;
+ }
+ return ret + ')';
+ }
+ else if (this->input_argument_->is_lib())
+ {
+ std::string ret("Read_symbols lib (");
+ bool add_space = false;
+ const Input_file_lib* lib = this->input_argument_->lib();
+ for (Input_file_lib::const_iterator p = lib->begin();
+ p != lib->end();
+ ++p)
+ {
+ if (add_space)
+ ret += ' ';
+ ret += p->file().name();
+ add_space = true;
+ }
+ return ret + ')';
+ }
+ else
+ {
+ std::string ret("Read_symbols ");
+ if (this->input_argument_->file().is_lib())
+ ret += "-l";
+ else if (this->input_argument_->file().is_searched_file())
+ ret += "-l:";
+ ret += this->input_argument_->file().name();
+ return ret;
+ }
+}
+
+// Class Add_symbols.
+
+Add_symbols::~Add_symbols()
+{
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ // next_blocker_ is deleted by the task associated with the next
+ // input file.
+}
+
+// We are blocked by this_blocker_. We block next_blocker_. We also
+// lock the file.
+
+Task_token*
+Add_symbols::is_runnable()
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ if (this->object_->is_locked())
+ return this->object_->token();
+ return NULL;
+}
+
+void
+Add_symbols::locks(Task_locker* tl)
+{
+ tl->add(this, this->next_blocker_);
+ Task_token* token = this->object_->token();
+ if (token != NULL)
+ tl->add(this, token);
+}
+
+// Add the symbols in the object to the symbol table.
+
+void
+Add_symbols::run(Workqueue*)
+{
+ Pluginobj* pluginobj = this->object_->pluginobj();
+ if (pluginobj != NULL)
+ {
+ this->object_->add_symbols(this->symtab_, this->sd_, this->layout_);
+ return;
+ }
+
+ if (!this->input_objects_->add_object(this->object_))
+ {
+ this->object_->discard_decompressed_sections();
+ gold_assert(this->sd_ != NULL);
+ delete this->sd_;
+ this->sd_ = NULL;
+ this->object_->release();
+ delete this->object_;
+ }
+ else
+ {
+ Incremental_inputs* incremental_inputs =
+ this->layout_->incremental_inputs();
+ if (incremental_inputs != NULL)
+ {
+ if (this->library_ != NULL && !this->library_->is_reported())
+ {
+ Incremental_binary* ibase = this->layout_->incremental_base();
+ gold_assert(ibase != NULL);
+ unsigned int lib_serial = this->library_->arg_serial();
+ unsigned int lib_index = this->library_->input_file_index();
+ Script_info* lib_script_info = ibase->get_script_info(lib_index);
+ incremental_inputs->report_archive_begin(this->library_,
+ lib_serial,
+ lib_script_info);
+ }
+ unsigned int arg_serial = this->input_argument_->file().arg_serial();
+ Script_info* script_info = this->input_argument_->script_info();
+ incremental_inputs->report_object(this->object_, arg_serial,
+ this->library_, script_info);
+ }
+ this->object_->layout(this->symtab_, this->layout_, this->sd_);
+ this->object_->add_symbols(this->symtab_, this->sd_, this->layout_);
+ this->object_->discard_decompressed_sections();
+ delete this->sd_;
+ this->sd_ = NULL;
+ this->object_->release();
+ }
+}
+
+// Class Read_member.
+
+Read_member::~Read_member()
+{
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ // next_blocker_ is deleted by the task associated with the next
+ // input file.
+}
+
+// Return whether a Read_member task is runnable.
+
+Task_token*
+Read_member::is_runnable()
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ return NULL;
+}
+
+void
+Read_member::locks(Task_locker* tl)
+{
+ tl->add(this, this->next_blocker_);
+}
+
+// Run a Read_member task.
+
+void
+Read_member::run(Workqueue*)
+{
+ // This task doesn't need to do anything for now. The Read_symbols task
+ // that is queued for the archive library will cause the archive to be
+ // processed from scratch.
+}
+
+// Class Check_script.
+
+Check_script::~Check_script()
+{
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ // next_blocker_ is deleted by the task associated with the next
+ // input file.
+}
+
+// Return whether a Check_script task is runnable.
+
+Task_token*
+Check_script::is_runnable()
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ return NULL;
+}
+
+void
+Check_script::locks(Task_locker* tl)
+{
+ tl->add(this, this->next_blocker_);
+}
+
+// Run a Check_script task.
+
+void
+Check_script::run(Workqueue*)
+{
+ Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
+ gold_assert(incremental_inputs != NULL);
+ unsigned int arg_serial = this->input_reader_->arg_serial();
+ Script_info* script_info =
+ this->ibase_->get_script_info(this->input_file_index_);
+ Timespec mtime = this->input_reader_->get_mtime();
+ incremental_inputs->report_script(script_info, arg_serial, mtime);
+}
+
+// Class Check_library.
+
+Check_library::~Check_library()
+{
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ // next_blocker_ is deleted by the task associated with the next
+ // input file.
+}
+
+// Return whether a Check_library task is runnable.
+
+Task_token*
+Check_library::is_runnable()
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ return NULL;
+}
+
+void
+Check_library::locks(Task_locker* tl)
+{
+ tl->add(this, this->next_blocker_);
+}
+
+// Run a Check_library task.
+
+void
+Check_library::run(Workqueue*)
+{
+ Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
+ gold_assert(incremental_inputs != NULL);
+ Incremental_library* lib = this->ibase_->get_library(this->input_file_index_);
+ gold_assert(lib != NULL);
+ lib->copy_unused_symbols();
+ // FIXME: Check that unused symbols remain unused.
+ if (!lib->is_reported())
+ {
+ unsigned int lib_serial = lib->arg_serial();
+ unsigned int lib_index = lib->input_file_index();
+ Script_info* script_info = this->ibase_->get_script_info(lib_index);
+ incremental_inputs->report_archive_begin(lib, lib_serial, script_info);
+ }
+ incremental_inputs->report_archive_end(lib);
+}
+
+// Class Input_group.
+
+// When we delete an Input_group we can delete the archive
+// information.
+
+Input_group::~Input_group()
+{
+ for (Input_group::const_iterator p = this->begin();
+ p != this->end();
+ ++p)
+ delete *p;
+}
+
+// Class Start_group.
+
+Start_group::~Start_group()
+{
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ // next_blocker_ is deleted by the task associated with the first
+ // file in the group.
+}
+
+// We need to wait for THIS_BLOCKER_ and unblock NEXT_BLOCKER_.
+
+Task_token*
+Start_group::is_runnable()
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ return NULL;
+}
+
+void
+Start_group::locks(Task_locker* tl)
+{
+ tl->add(this, this->next_blocker_);
+}
+
+// Store the number of undefined symbols we see now.
+
+void
+Start_group::run(Workqueue*)
+{
+ this->finish_group_->set_saw_undefined(this->symtab_->saw_undefined());
+}
+
+// Class Finish_group.
+
+Finish_group::~Finish_group()
+{
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ // next_blocker_ is deleted by the task associated with the next
+ // input file following the group.
+}
+
+// We need to wait for THIS_BLOCKER_ and unblock NEXT_BLOCKER_.
+
+Task_token*
+Finish_group::is_runnable()
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ return NULL;
+}
+
+void
+Finish_group::locks(Task_locker* tl)
+{
+ tl->add(this, this->next_blocker_);
+}
+
+// Loop over the archives until there are no new undefined symbols.
+
+void
+Finish_group::run(Workqueue*)
+{
+ size_t saw_undefined = this->saw_undefined_;
+ while (saw_undefined != this->symtab_->saw_undefined())
+ {
+ saw_undefined = this->symtab_->saw_undefined();
+
+ for (Input_group::const_iterator p = this->input_group_->begin();
+ p != this->input_group_->end();
+ ++p)
+ {
+ Task_lock_obj<Archive> tl(this, *p);
+
+ (*p)->add_symbols(this->symtab_, this->layout_,
+ this->input_objects_, this->mapfile_);
+ }
+ }
+
+ // Now that we're done with the archives, record the incremental
+ // layout information.
+ for (Input_group::const_iterator p = this->input_group_->begin();
+ p != this->input_group_->end();
+ ++p)
+ {
+ // For an incremental link, finish recording the layout information.
+ Incremental_inputs* incremental_inputs =
+ this->layout_->incremental_inputs();
+ if (incremental_inputs != NULL)
+ incremental_inputs->report_archive_end(*p);
+ }
+
+ if (parameters->options().has_plugins())
+ parameters->options().plugins()->save_input_group(this->input_group_);
+ else
+ delete this->input_group_;
+}
+
+// Class Read_script
+
+Read_script::~Read_script()
+{
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ // next_blocker_ is deleted by the task associated with the next
+ // input file.
+}
+
+// We are blocked by this_blocker_.
+
+Task_token*
+Read_script::is_runnable()
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ return NULL;
+}
+
+// We don't unlock next_blocker_ here. If the script names any input
+// files, then the last file will be responsible for unlocking it.
+
+void
+Read_script::locks(Task_locker*)
+{
+}
+
+// Read the script, if it is a script.
+
+void
+Read_script::run(Workqueue* workqueue)
+{
+ bool used_next_blocker;
+ if (!read_input_script(workqueue, this->symtab_, this->layout_,
+ this->dirpath_, this->dirindex_, this->input_objects_,
+ this->mapfile_, this->input_group_,
+ this->input_argument_, this->input_file_,
+ this->next_blocker_, &used_next_blocker))
+ {
+ // Here we have to handle any other input file types we need.
+ gold_error(_("%s: not an object or archive"),
+ this->input_file_->file().filename().c_str());
+ }
+
+ if (!used_next_blocker)
+ {
+ // Queue up a task to unlock next_blocker. We can't just unlock
+ // it here, as we don't hold the workqueue lock.
+ workqueue->queue_soon(new Unblock_token(NULL, this->next_blocker_));
+ }
+}
+
+// Return a debugging name for a Read_script task.
+
+std::string
+Read_script::get_name() const
+{
+ std::string ret("Read_script ");
+ if (this->input_argument_->file().is_lib())
+ ret += "-l";
+ else if (this->input_argument_->file().is_searched_file())
+ ret += "-l:";
+ ret += this->input_argument_->file().name();
+ return ret;
+}
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/readsyms.h b/binutils-2.25/gold/readsyms.h
new file mode 100644
index 00000000..99b2b164
--- /dev/null
+++ b/binutils-2.25/gold/readsyms.h
@@ -0,0 +1,492 @@
+// readsyms.h -- read input file symbols for gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2013
+// Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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_READSYMS_H
+#define GOLD_READSYMS_H
+
+#include <vector>
+
+#include "workqueue.h"
+#include "object.h"
+#include "incremental.h"
+
+namespace gold
+{
+
+class Input_objects;
+class Symbol_table;
+class Input_group;
+class Archive;
+class Finish_group;
+
+// This Task is responsible for reading the symbols from an input
+// file. This also includes reading the relocations so that we can
+// check for any that require a PLT and/or a GOT. After the data has
+// been read, this queues up another task to actually add the symbols
+// to the symbol table. The tasks are separated because the file
+// reading can occur in parallel but adding the symbols must be done
+// in the order of the input files.
+
+class Read_symbols : public Task
+{
+ public:
+ // DIRPATH is the list of directories to search for libraries.
+ // INPUT is the file to read. INPUT_GROUP is not NULL if we are in
+ // the middle of an input group. THIS_BLOCKER is used to prevent
+ // the associated Add_symbols task from running before the previous
+ // one has completed; it will be NULL for the first task.
+ // NEXT_BLOCKER is used to block the next input file from adding
+ // symbols.
+ Read_symbols(Input_objects* input_objects, Symbol_table* symtab,
+ Layout* layout, Dirsearch* dirpath, int dirindex,
+ Mapfile* mapfile, const Input_argument* input_argument,
+ Input_group* input_group, Archive_member* member,
+ Task_token* this_blocker, Task_token* next_blocker)
+ : input_objects_(input_objects), symtab_(symtab), layout_(layout),
+ dirpath_(dirpath), dirindex_(dirindex), mapfile_(mapfile),
+ input_argument_(input_argument), input_group_(input_group),
+ member_(member), this_blocker_(this_blocker),
+ next_blocker_(next_blocker)
+ { }
+
+ ~Read_symbols();
+
+ // If appropriate, issue a warning about skipping an incompatible
+ // object.
+ static void
+ incompatible_warning(const Input_argument*, const Input_file*);
+
+ // Requeue a Read_symbols task to search for the next object with
+ // the same name.
+ static void
+ requeue(Workqueue*, Input_objects*, Symbol_table*, Layout*, Dirsearch*,
+ int dirindex, Mapfile*, const Input_argument*, Input_group*,
+ Task_token* next_blocker);
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const;
+
+ private:
+ // Handle an archive group.
+ void
+ do_group(Workqueue*);
+
+ // Handle --start-lib ... --end-lib
+ bool
+ do_lib_group(Workqueue*);
+
+ // Handle --whole-archive --start-lib ... --end-lib --no-whole-archive
+ bool
+ do_whole_lib_group(Workqueue*);
+
+ // Open and identify the file.
+ bool
+ do_read_symbols(Workqueue*);
+
+ Input_objects* input_objects_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Dirsearch* dirpath_;
+ int dirindex_;
+ Mapfile* mapfile_;
+ const Input_argument* input_argument_;
+ Input_group* input_group_;
+ Archive_member* member_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// This Task handles adding the symbols to the symbol table. These
+// tasks must be run in the same order as the arguments appear on the
+// command line.
+
+class Add_symbols : public Task
+{
+ public:
+ // THIS_BLOCKER is used to prevent this task from running before the
+ // one for the previous input file. NEXT_BLOCKER is used to prevent
+ // the next task from running.
+ Add_symbols(Input_objects* input_objects, Symbol_table* symtab,
+ Layout* layout, Dirsearch* /*dirpath*/, int /*dirindex*/,
+ Mapfile* /*mapfile*/, const Input_argument* input_argument,
+ Object* object, Incremental_library* library,
+ Read_symbols_data* sd, Task_token* this_blocker,
+ Task_token* next_blocker)
+ : input_objects_(input_objects), symtab_(symtab), layout_(layout),
+ input_argument_(input_argument), object_(object), library_(library),
+ sd_(sd), this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Add_symbols();
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const
+ { return "Add_symbols " + this->object_->name(); }
+
+private:
+ Input_objects* input_objects_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+ const Input_argument* input_argument_;
+ Object* object_;
+ Incremental_library* library_;
+ Read_symbols_data* sd_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// This Task is responsible for reading the symbols from an archive
+// member that has changed since the last incremental link.
+
+class Read_member : public Task
+{
+ public:
+ // INPUT is the file to read. INPUT_GROUP is not NULL if we are in
+ // the middle of an input group. THIS_BLOCKER is used to prevent
+ // the associated Add_symbols task from running before the previous
+ // one has completed; it will be NULL for the first task.
+ // NEXT_BLOCKER is used to block the next input file from adding
+ // symbols.
+ Read_member(Input_objects* /*input_objects*/, Symbol_table* /*symtab*/,
+ Layout* /*layout*/, Mapfile* /*mapfile*/,
+ const Incremental_binary::Input_reader* input_reader,
+ Task_token* this_blocker, Task_token* next_blocker)
+ : input_reader_(input_reader),
+ this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Read_member();
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const
+ {
+ return (std::string("Read_member ") + this->input_reader_->filename());
+ }
+
+ private:
+ const Incremental_binary::Input_reader* input_reader_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// This Task is responsible for processing an input script file that has
+// not changed since the last incremental link.
+
+class Check_script : public Task
+{
+ public:
+ Check_script(Layout* layout, Incremental_binary* ibase,
+ unsigned int input_file_index,
+ const Incremental_binary::Input_reader* input_reader,
+ Task_token* this_blocker, Task_token* next_blocker)
+ : layout_(layout), ibase_(ibase), input_file_index_(input_file_index),
+ input_reader_(input_reader), this_blocker_(this_blocker),
+ next_blocker_(next_blocker)
+ {
+ this->filename_ = std::string(this->input_reader_->filename());
+ }
+
+ ~Check_script();
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const
+ {
+ return (std::string("Check_script ") + this->input_reader_->filename());
+ }
+
+ private:
+ std::string filename_;
+ Layout* layout_;
+ Incremental_binary* ibase_;
+ unsigned int input_file_index_;
+ const Incremental_binary::Input_reader* input_reader_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// This Task is responsible for processing an archive library that has
+// not changed since the last incremental link.
+
+class Check_library : public Task
+{
+ public:
+ Check_library(Symbol_table* /*symtab*/, Layout* layout,
+ Incremental_binary* ibase,
+ unsigned int input_file_index,
+ const Incremental_binary::Input_reader* input_reader,
+ Task_token* this_blocker, Task_token* next_blocker)
+ : layout_(layout), ibase_(ibase),
+ input_file_index_(input_file_index), input_reader_(input_reader),
+ this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Check_library();
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const
+ {
+ return (std::string("Check_library ") + this->input_reader_->filename());
+ }
+
+ private:
+ Layout* layout_;
+ Incremental_binary* ibase_;
+ unsigned int input_file_index_;
+ const Incremental_binary::Input_reader* input_reader_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// This class is used to track the archives in a group.
+
+class Input_group
+{
+ public:
+ typedef std::vector<Archive*> Archives;
+ typedef Archives::const_iterator const_iterator;
+
+ Input_group()
+ : archives_()
+ { }
+
+ ~Input_group();
+
+ // Add an archive to the group.
+ void
+ add_archive(Archive* arch)
+ { this->archives_.push_back(arch); }
+
+ // Loop over the archives in the group.
+
+ const_iterator
+ begin() const
+ { return this->archives_.begin(); }
+
+ const_iterator
+ end() const
+ { return this->archives_.end(); }
+
+ private:
+ Archives archives_;
+};
+
+// This class starts the handling of a group. It exists only to pick
+// up the number of undefined symbols at that point, so that we only
+// run back through the group if we saw a new undefined symbol.
+
+class Start_group : public Task
+{
+ public:
+ Start_group(Symbol_table* symtab, Finish_group* finish_group,
+ Task_token* this_blocker, Task_token* next_blocker)
+ : symtab_(symtab), finish_group_(finish_group),
+ this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Start_group();
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const
+ { return "Start_group"; }
+
+ private:
+ Symbol_table* symtab_;
+ Finish_group* finish_group_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// This class is used to finish up handling a group. It is just a
+// closure.
+
+class Finish_group : public Task
+{
+ public:
+ Finish_group(Input_objects* input_objects, Symbol_table* symtab,
+ Layout* layout, Mapfile* mapfile, Input_group* input_group,
+ Task_token* next_blocker)
+ : input_objects_(input_objects), symtab_(symtab),
+ layout_(layout), mapfile_(mapfile), input_group_(input_group),
+ saw_undefined_(0), this_blocker_(NULL), next_blocker_(next_blocker)
+ { }
+
+ ~Finish_group();
+
+ // Set the number of undefined symbols when we start processing the
+ // group. This is called by the Start_group task.
+ void
+ set_saw_undefined(size_t saw_undefined)
+ { this->saw_undefined_ = saw_undefined; }
+
+ // Set the blocker to use for this task.
+ void
+ set_blocker(Task_token* this_blocker)
+ {
+ gold_assert(this->this_blocker_ == NULL);
+ this->this_blocker_ = this_blocker;
+ }
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const
+ { return "Finish_group"; }
+
+ private:
+ Input_objects* input_objects_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Mapfile* mapfile_;
+ Input_group* input_group_;
+ size_t saw_undefined_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// This class is used to read a file which was not recognized as an
+// object or archive. It tries to read it as a linker script, using
+// the tokens to serialize with the calls to Add_symbols.
+
+class Read_script : public Task
+{
+ public:
+ Read_script(Symbol_table* symtab, Layout* layout, Dirsearch* dirpath,
+ int dirindex, Input_objects* input_objects, Mapfile* mapfile,
+ Input_group* input_group, const Input_argument* input_argument,
+ Input_file* input_file, Task_token* this_blocker,
+ Task_token* next_blocker)
+ : symtab_(symtab), layout_(layout), dirpath_(dirpath), dirindex_(dirindex),
+ input_objects_(input_objects), mapfile_(mapfile),
+ input_group_(input_group), input_argument_(input_argument),
+ input_file_(input_file), this_blocker_(this_blocker),
+ next_blocker_(next_blocker)
+ { }
+
+ ~Read_script();
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const;
+
+ private:
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Dirsearch* dirpath_;
+ int dirindex_;
+ Input_objects* input_objects_;
+ Mapfile* mapfile_;
+ Input_group* input_group_;
+ const Input_argument* input_argument_;
+ Input_file* input_file_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+} // end namespace gold
+
+#endif // !defined(GOLD_READSYMS_H)
diff --git a/binutils-2.25/gold/reduced_debug_output.cc b/binutils-2.25/gold/reduced_debug_output.cc
new file mode 100644
index 00000000..a6158fcc
--- /dev/null
+++ b/binutils-2.25/gold/reduced_debug_output.cc
@@ -0,0 +1,376 @@
+// reduced_debug_output.cc -- output reduced debugging information to save space
+
+// Copyright 2008, 2010, 2012 Free Software Foundation, Inc.
+// Written by Caleb Howe <cshowe@google.com>.
+
+// 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 "parameters.h"
+#include "options.h"
+#include "dwarf.h"
+#include "dwarf_reader.h"
+#include "reduced_debug_output.h"
+#include "int_encoding.h"
+
+#include <vector>
+
+namespace gold
+{
+
+// Given a pointer to the beginning of a die and the beginning of the associated
+// abbreviation fills in die_end with the end of the information entry. If
+// successful returns true. Get_die_end also takes a pointer to the end of the
+// buffer containing the die. If die_end would be beyond the end of the
+// buffer, or if an unsupported dwarf form is encountered returns false.
+bool
+Output_reduced_debug_info_section::get_die_end(
+ unsigned char* die, unsigned char* abbrev, unsigned char** die_end,
+ unsigned char* buffer_end, int address_size, bool is64)
+{
+ size_t LEB_size;
+ uint64_t LEB_decoded;
+ for(;;)
+ {
+ uint64_t attribute = read_unsigned_LEB_128(abbrev, &LEB_size);
+ abbrev += LEB_size;
+ elfcpp::DW_FORM form =
+ static_cast<elfcpp::DW_FORM>(read_unsigned_LEB_128(abbrev,
+ &LEB_size));
+ abbrev += LEB_size;
+ if (!(attribute || form))
+ break;
+ if (die >= buffer_end)
+ return false;
+ switch(form)
+ {
+ case elfcpp::DW_FORM_flag_present:
+ break;
+ case elfcpp::DW_FORM_strp:
+ case elfcpp::DW_FORM_sec_offset:
+ die += is64 ? 8 : 4;
+ break;
+ case elfcpp::DW_FORM_addr:
+ case elfcpp::DW_FORM_ref_addr:
+ die += address_size;
+ break;
+ case elfcpp::DW_FORM_block1:
+ die += *die;
+ die += 1;
+ break;
+ case elfcpp::DW_FORM_block2:
+ {
+ uint16_t block_size;
+ block_size = read_from_pointer<16>(&die);
+ die += block_size;
+ break;
+ }
+ case elfcpp::DW_FORM_block4:
+ {
+ uint32_t block_size;
+ block_size = read_from_pointer<32>(&die);
+ die += block_size;
+ break;
+ }
+ case elfcpp::DW_FORM_block:
+ case elfcpp::DW_FORM_exprloc:
+ LEB_decoded = read_unsigned_LEB_128(die, &LEB_size);
+ die += (LEB_decoded + LEB_size);
+ break;
+ case elfcpp::DW_FORM_data1:
+ case elfcpp::DW_FORM_ref1:
+ case elfcpp::DW_FORM_flag:
+ die += 1;
+ break;
+ case elfcpp::DW_FORM_data2:
+ case elfcpp::DW_FORM_ref2:
+ die += 2;
+ break;
+ case elfcpp::DW_FORM_data4:
+ case elfcpp::DW_FORM_ref4:
+ die += 4;
+ break;
+ case elfcpp::DW_FORM_data8:
+ case elfcpp::DW_FORM_ref8:
+ case elfcpp::DW_FORM_ref_sig8:
+ die += 8;
+ break;
+ case elfcpp::DW_FORM_ref_udata:
+ case elfcpp::DW_FORM_udata:
+ read_unsigned_LEB_128(die, &LEB_size);
+ die += LEB_size;
+ break;
+ case elfcpp::DW_FORM_sdata:
+ read_signed_LEB_128(die, &LEB_size);
+ die += LEB_size;
+ break;
+ case elfcpp::DW_FORM_string:
+ {
+ size_t length = strlen(reinterpret_cast<char*>(die));
+ die += length + 1;
+ break;
+ }
+ case elfcpp::DW_FORM_indirect:
+ case elfcpp::DW_FORM_GNU_addr_index:
+ case elfcpp::DW_FORM_GNU_str_index:
+ default:
+ return false;
+ }
+ }
+ *die_end = die;
+ return true;
+}
+
+void
+Output_reduced_debug_abbrev_section::set_final_data_size()
+{
+ if (this->sized_ || this->failed_)
+ return;
+
+ uint64_t abbrev_number;
+ size_t LEB_size;
+ unsigned char* abbrev_data = this->postprocessing_buffer();
+ unsigned char* abbrev_end = this->postprocessing_buffer() +
+ this->postprocessing_buffer_size();
+ this->write_to_postprocessing_buffer();
+ while(abbrev_data < abbrev_end)
+ {
+ uint64_t abbrev_offset = abbrev_data - this->postprocessing_buffer();
+ while((abbrev_number = read_unsigned_LEB_128(abbrev_data, &LEB_size)))
+ {
+ if (abbrev_data >= abbrev_end)
+ {
+ failed("Debug abbreviations extend beyond .debug_abbrev "
+ "section; failed to reduce debug abbreviations");
+ return;
+ }
+ abbrev_data += LEB_size;
+
+ // Together with the abbreviation number these fields make up
+ // the header for each abbreviation.
+ uint64_t abbrev_type = read_unsigned_LEB_128(abbrev_data, &LEB_size);
+ abbrev_data += LEB_size;
+
+ // This would ordinarily be the has_children field of the
+ // abbreviation. But it's going to be false after reducing the
+ // information, so there's no point in storing it.
+ abbrev_data++;
+
+ // Read to the end of the current abbreviation.
+ // This is indicated by two zero unsigned LEBs in a row. We don't
+ // need to parse the data yet, so we just scan through the data
+ // looking for two consecutive 0 bytes indicating the end of the
+ // abbreviation.
+ unsigned char* current_abbrev;
+ for (current_abbrev = abbrev_data;
+ current_abbrev[0] || current_abbrev[1];
+ current_abbrev++)
+ {
+ if (current_abbrev >= abbrev_end)
+ {
+ this->failed(_("Debug abbreviations extend beyond "
+ ".debug_abbrev section; failed to reduce "
+ "debug abbreviations"));
+ return;
+ }
+ }
+ // Account for the two nulls and advance to the start of the
+ // next abbreviation.
+ current_abbrev += 2;
+
+ // We're eliminating every entry except for compile units, so we
+ // only need to store abbreviations that describe them
+ if (abbrev_type == elfcpp::DW_TAG_compile_unit)
+ {
+ write_unsigned_LEB_128(&this->data_, ++this->abbrev_count_);
+ write_unsigned_LEB_128(&this->data_, abbrev_type);
+ // has_children is false for all entries
+ this->data_.push_back(0);
+ this->abbrev_mapping_[std::make_pair(abbrev_offset,
+ abbrev_number)] =
+ std::make_pair(abbrev_count_, this->data_.size());
+ this->data_.insert(this->data_.end(), abbrev_data,
+ current_abbrev);
+ }
+ abbrev_data = current_abbrev;
+ }
+ gold_assert(LEB_size == 1);
+ abbrev_data += LEB_size;
+ }
+ // Null terminate the list of abbreviations
+ this->data_.push_back(0);
+ this->set_data_size(data_.size());
+ this->sized_ = true;
+}
+
+void
+Output_reduced_debug_abbrev_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->failed_)
+ memcpy(view, this->postprocessing_buffer(),
+ this->postprocessing_buffer_size());
+ else
+ memcpy(view, &this->data_.front(), data_size);
+ of->write_output_view(offset, data_size, view);
+}
+
+// Locates the abbreviation with abbreviation_number abbrev_number in the
+// abbreviation table at offset abbrev_offset. abbrev_number is updated with
+// its new abbreviation number and a pointer to the beginning of the
+// abbreviation is returned.
+unsigned char*
+Output_reduced_debug_abbrev_section::get_new_abbrev(
+ uint64_t* abbrev_number, uint64_t abbrev_offset)
+{
+ set_final_data_size();
+ std::pair<uint64_t, uint64_t> abbrev_info =
+ this->abbrev_mapping_[std::make_pair(abbrev_offset, *abbrev_number)];
+ *abbrev_number = abbrev_info.first;
+ return &this->data_[abbrev_info.second];
+}
+
+void Output_reduced_debug_info_section::set_final_data_size()
+{
+ if (this->failed_)
+ return;
+ unsigned char* debug_info = this->postprocessing_buffer();
+ unsigned char* debug_info_end = (this->postprocessing_buffer()
+ + this->postprocessing_buffer_size());
+ unsigned char* next_compile_unit;
+ this->write_to_postprocessing_buffer();
+
+ while (debug_info < debug_info_end)
+ {
+ uint32_t compile_unit_start = read_from_pointer<32>(&debug_info);
+ // The first 4 bytes of each compile unit determine whether or
+ // not we're using dwarf32 or dwarf64. This is not necessarily
+ // related to whether the binary is 32 or 64 bits.
+ if (compile_unit_start == 0xFFFFFFFF)
+ {
+ // Technically the size can be up to 96 bits. Rather than handle
+ // 96/128 bit integers we just truncate the size at 64 bits.
+ if (0 != read_from_pointer<32>(&debug_info))
+ {
+ this->failed(_("Extremely large compile unit in debug info; "
+ "failed to reduce debug info"));
+ return;
+ }
+ const int dwarf64_header_size = sizeof(uint64_t) + sizeof(uint16_t) +
+ sizeof(uint64_t) + sizeof(uint8_t);
+ if (debug_info + dwarf64_header_size >= debug_info_end)
+ {
+ this->failed(_("Debug info extends beyond .debug_info section;"
+ "failed to reduce debug info"));
+ return;
+ }
+
+ uint64_t compile_unit_size = read_from_pointer<64>(&debug_info);
+ next_compile_unit = debug_info + compile_unit_size;
+ uint16_t version = read_from_pointer<16>(&debug_info);
+ uint64_t abbrev_offset = read_from_pointer<64>(&debug_info);
+ uint8_t address_size = read_from_pointer<8>(&debug_info);
+ size_t LEB_size;
+ uint64_t abbreviation_number = read_unsigned_LEB_128(debug_info,
+ &LEB_size);
+ debug_info += LEB_size;
+ unsigned char* die_abbrev = this->associated_abbrev_->get_new_abbrev(
+ &abbreviation_number, abbrev_offset);
+ unsigned char* die_end;
+ if (!this->get_die_end(debug_info, die_abbrev, &die_end,
+ debug_info_end, address_size, true))
+ {
+ this->failed(_("Invalid DIE in debug info; "
+ "failed to reduce debug info"));
+ return;
+ }
+
+ insert_into_vector<32>(&this->data_, 0xFFFFFFFF);
+ insert_into_vector<32>(&this->data_, 0);
+ insert_into_vector<64>(
+ &this->data_,
+ (11 + get_length_as_unsigned_LEB_128(abbreviation_number)
+ + die_end - debug_info));
+ insert_into_vector<16>(&this->data_, version);
+ insert_into_vector<64>(&this->data_, 0);
+ insert_into_vector<8>(&this->data_, address_size);
+ write_unsigned_LEB_128(&this->data_, abbreviation_number);
+ this->data_.insert(this->data_.end(), debug_info, die_end);
+ }
+ else
+ {
+ const int dwarf32_header_size =
+ sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint8_t);
+ if (debug_info + dwarf32_header_size >= debug_info_end)
+ {
+ this->failed(_("Debug info extends beyond .debug_info section; "
+ "failed to reduce debug info"));
+ return;
+ }
+ uint32_t compile_unit_size = compile_unit_start;
+ next_compile_unit = debug_info + compile_unit_size;
+ uint16_t version = read_from_pointer<16>(&debug_info);
+ uint32_t abbrev_offset = read_from_pointer<32>(&debug_info);
+ uint8_t address_size = read_from_pointer<8>(&debug_info);
+ size_t LEB_size;
+ uint64_t abbreviation_number = read_unsigned_LEB_128(debug_info,
+ &LEB_size);
+ debug_info += LEB_size;
+ unsigned char* die_abbrev = this->associated_abbrev_->get_new_abbrev(
+ &abbreviation_number, abbrev_offset);
+ unsigned char* die_end;
+ if (!this->get_die_end(debug_info, die_abbrev, &die_end,
+ debug_info_end, address_size, false))
+ {
+ this->failed(_("Invalid DIE in debug info; "
+ "failed to reduce debug info"));
+ return;
+ }
+
+ insert_into_vector<32>(
+ &this->data_,
+ (7 + get_length_as_unsigned_LEB_128(abbreviation_number)
+ + die_end - debug_info));
+ insert_into_vector<16>(&this->data_, version);
+ insert_into_vector<32>(&this->data_, 0);
+ insert_into_vector<8>(&this->data_, address_size);
+ write_unsigned_LEB_128(&this->data_, abbreviation_number);
+ this->data_.insert(this->data_.end(), debug_info, die_end);
+ }
+ debug_info = next_compile_unit;
+ }
+ this->set_data_size(data_.size());
+}
+
+void Output_reduced_debug_info_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->failed_)
+ memcpy(view, this->postprocessing_buffer(),
+ this->postprocessing_buffer_size());
+ else
+ memcpy(view, &this->data_.front(), data_size);
+ of->write_output_view(offset, data_size, view);
+}
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/reduced_debug_output.h b/binutils-2.25/gold/reduced_debug_output.h
new file mode 100644
index 00000000..d1682288
--- /dev/null
+++ b/binutils-2.25/gold/reduced_debug_output.h
@@ -0,0 +1,140 @@
+// reduced_debug_output.h -- reduce debugging information -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Caleb Howe <cshowe@google.com>.
+
+// 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.
+
+// Reduce the size of the debug sections by emitting only debug line number
+// information. We still need to emit skeleton debug_info and debug_abbrev
+// sections for standard tools to parse the debug information correctly. These
+// classes remove all debug information entries from the .debug_info section
+// except for those describing compilation units as these DIEs contain
+// references to the debug line information needed by most parsers.
+
+#ifndef GOLD_REDUCED_DEBUG_OUTPUT_H
+#define GOLD_REDUCED_DEBUG_OUTPUT_H
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "output.h"
+
+namespace gold
+{
+
+class Output_reduced_debug_abbrev_section : public Output_section
+{
+ public:
+ Output_reduced_debug_abbrev_section(const char* name, elfcpp::Elf_Word flags,
+ elfcpp::Elf_Xword type)
+ : Output_section(name, flags, type), sized_(false),
+ abbrev_count_(0), failed_(false)
+ { this->set_requires_postprocessing(); }
+
+ unsigned char* get_new_abbrev(uint64_t* abbrev_number,
+ uint64_t abbrev_offset);
+
+ protected:
+ // Set the final data size.
+ void
+ set_final_data_size();
+
+ // Write out the new debug abbreviations
+ void
+ do_write(Output_file*);
+
+ private:
+ void
+ failed(std::string reason)
+ {
+ gold_warning("%s", reason.c_str());
+ failed_ = true;
+ }
+
+ // The reduced debug abbreviations
+ std::vector<unsigned char> data_;
+
+ // We map the abbreviation table offset and abbreviation number of the
+ // old abbreviation to the number and size of the new abbreviation.
+ std::map<std::pair<uint64_t, uint64_t>,
+ std::pair<uint64_t, uint64_t> > abbrev_mapping_;
+
+ bool sized_;
+
+ // The count of abbreviations in the output data
+ int abbrev_count_;
+
+ // Whether or not the debug reduction has failed for any reason
+ bool failed_;
+};
+
+class Output_reduced_debug_info_section : public Output_section
+{
+ public:
+ Output_reduced_debug_info_section(const char* name, elfcpp::Elf_Word flags,
+ elfcpp::Elf_Xword type)
+ : Output_section(name, flags, type), failed_(false)
+ { this->set_requires_postprocessing(); }
+
+ void
+ set_abbreviations(Output_reduced_debug_abbrev_section* abbrevs)
+ { associated_abbrev_ = abbrevs; }
+
+ protected:
+ // Set the final data size.
+ void
+ set_final_data_size();
+
+ // Write out the new debug info
+ void
+ do_write(Output_file*);
+
+ private:
+ void
+ failed(std::string reason)
+ {
+ gold_warning("%s", reason.c_str());
+ this->failed_ = true;
+ }
+
+ // Given a pointer to the beginning of a die and the beginning of the
+ // associated abbreviation fills in die_end with the end of the information
+ // entry. If successful returns true. Get_die_end also takes a pointer to
+ // the end of the buffer containing the die. If die_end would be beyond the
+ // end of the buffer, or if an unsupported dwarf form is encountered returns
+ // false.
+ bool
+ get_die_end(unsigned char* die, unsigned char* abbrev,
+ unsigned char** die_end, unsigned char* buffer_end,
+ int address_size, bool is64);
+
+ // The reduced debug info
+ std::vector<unsigned char> data_;
+
+ // Each debug info section needs to be associated with a debug abbrev section
+ Output_reduced_debug_abbrev_section* associated_abbrev_;
+
+ // Whether or not the debug reduction has failed for any reason
+ bool failed_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_REDUCED_DEBUG_OUTPUT_H)
diff --git a/binutils-2.25/gold/reloc-types.h b/binutils-2.25/gold/reloc-types.h
new file mode 100644
index 00000000..f13e64ae
--- /dev/null
+++ b/binutils-2.25/gold/reloc-types.h
@@ -0,0 +1,92 @@
+// reloc-types.h -- ELF relocation templates for gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 header files defines a few convenient templated types for use
+// when handling ELF relocations.
+
+#ifndef GOLD_RELOC_TYPES_H
+#define GOLD_RELOC_TYPES_H
+
+#include "elfcpp.h"
+
+namespace gold
+{
+
+// Pick the ELF relocation accessor class and the size based on
+// SH_TYPE, which is either elfcpp::SHT_REL or elfcpp::SHT_RELA.
+
+template<int sh_type, int size, bool big_endian>
+struct Reloc_types;
+
+template<int size, bool big_endian>
+struct Reloc_types<elfcpp::SHT_REL, size, big_endian>
+{
+ typedef typename elfcpp::Rel<size, big_endian> Reloc;
+ typedef typename elfcpp::Rel_write<size, big_endian> Reloc_write;
+ static const int reloc_size = elfcpp::Elf_sizes<size>::rel_size;
+
+ static inline typename elfcpp::Elf_types<size>::Elf_Swxword
+ get_reloc_addend(const Reloc*)
+ { gold_unreachable(); }
+
+ static inline typename elfcpp::Elf_types<size>::Elf_Swxword
+ get_reloc_addend_noerror(const Reloc*)
+ { return 0; }
+
+ static inline void
+ set_reloc_addend(Reloc_write*,
+ typename elfcpp::Elf_types<size>::Elf_Swxword)
+ { gold_unreachable(); }
+
+ static inline void
+ copy_reloc_addend(Reloc_write*, const Reloc*)
+ { gold_unreachable(); }
+};
+
+template<int size, bool big_endian>
+struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
+{
+ typedef typename elfcpp::Rela<size, big_endian> Reloc;
+ typedef typename elfcpp::Rela_write<size, big_endian> Reloc_write;
+ static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+
+ static inline typename elfcpp::Elf_types<size>::Elf_Swxword
+ get_reloc_addend(const Reloc* p)
+ { return p->get_r_addend(); }
+
+ static inline typename elfcpp::Elf_types<size>::Elf_Swxword
+ get_reloc_addend_noerror(const Reloc* p)
+ { return p->get_r_addend(); }
+
+ static inline void
+ set_reloc_addend(Reloc_write* p,
+ typename elfcpp::Elf_types<size>::Elf_Swxword val)
+ { p->put_r_addend(val); }
+
+ static inline void
+ copy_reloc_addend(Reloc_write* to, const Reloc* from)
+ { to->put_r_addend(from->get_r_addend()); }
+};
+
+}; // End namespace gold.
+
+#endif // !defined(GOLD_RELOC_TYPE_SH)
diff --git a/binutils-2.25/gold/reloc.cc b/binutils-2.25/gold/reloc.cc
new file mode 100644
index 00000000..ca7f32fd
--- /dev/null
+++ b/binutils-2.25/gold/reloc.cc
@@ -0,0 +1,1849 @@
+// reloc.cc -- relocate input files for gold.
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <algorithm>
+
+#include "workqueue.h"
+#include "layout.h"
+#include "symtab.h"
+#include "output.h"
+#include "merge.h"
+#include "object.h"
+#include "target-reloc.h"
+#include "reloc.h"
+#include "icf.h"
+#include "compressed_output.h"
+#include "incremental.h"
+
+namespace gold
+{
+
+// Read_relocs methods.
+
+// These tasks just read the relocation information from the file.
+// After reading it, the start another task to process the
+// information. These tasks requires access to the file.
+
+Task_token*
+Read_relocs::is_runnable()
+{
+ return this->object_->is_locked() ? this->object_->token() : NULL;
+}
+
+// Lock the file.
+
+void
+Read_relocs::locks(Task_locker* tl)
+{
+ Task_token* token = this->object_->token();
+ if (token != NULL)
+ tl->add(this, token);
+}
+
+// Read the relocations and then start a Scan_relocs_task.
+
+void
+Read_relocs::run(Workqueue* workqueue)
+{
+ Read_relocs_data* rd = new Read_relocs_data;
+ this->object_->read_relocs(rd);
+ this->object_->set_relocs_data(rd);
+ this->object_->release();
+
+ // If garbage collection or identical comdat folding is desired, we
+ // process the relocs first before scanning them. Scanning of relocs is
+ // done only after garbage or identical sections is identified.
+ if (parameters->options().gc_sections()
+ || parameters->options().icf_enabled())
+ {
+ workqueue->queue_next(new Gc_process_relocs(this->symtab_,
+ this->layout_,
+ this->object_, rd,
+ this->this_blocker_,
+ this->next_blocker_));
+ }
+ else
+ {
+ workqueue->queue_next(new Scan_relocs(this->symtab_, this->layout_,
+ this->object_, rd,
+ this->this_blocker_,
+ this->next_blocker_));
+ }
+}
+
+// Return a debugging name for the task.
+
+std::string
+Read_relocs::get_name() const
+{
+ return "Read_relocs " + this->object_->name();
+}
+
+// Gc_process_relocs methods.
+
+Gc_process_relocs::~Gc_process_relocs()
+{
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+}
+
+// These tasks process the relocations read by Read_relocs and
+// determine which sections are referenced and which are garbage.
+// This task is done only when --gc-sections is used. This is blocked
+// by THIS_BLOCKER_. It unblocks NEXT_BLOCKER_.
+
+Task_token*
+Gc_process_relocs::is_runnable()
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ if (this->object_->is_locked())
+ return this->object_->token();
+ return NULL;
+}
+
+void
+Gc_process_relocs::locks(Task_locker* tl)
+{
+ tl->add(this, this->object_->token());
+ tl->add(this, this->next_blocker_);
+}
+
+void
+Gc_process_relocs::run(Workqueue*)
+{
+ this->object_->gc_process_relocs(this->symtab_, this->layout_, this->rd_);
+ this->object_->release();
+}
+
+// Return a debugging name for the task.
+
+std::string
+Gc_process_relocs::get_name() const
+{
+ return "Gc_process_relocs " + this->object_->name();
+}
+
+// Scan_relocs methods.
+
+Scan_relocs::~Scan_relocs()
+{
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+}
+
+// These tasks scan the relocations read by Read_relocs and mark up
+// the symbol table to indicate which relocations are required. We
+// use a lock on the symbol table to keep them from interfering with
+// each other.
+
+Task_token*
+Scan_relocs::is_runnable()
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ if (this->object_->is_locked())
+ return this->object_->token();
+ return NULL;
+}
+
+// Return the locks we hold: one on the file, one on the symbol table
+// and one blocker.
+
+void
+Scan_relocs::locks(Task_locker* tl)
+{
+ Task_token* token = this->object_->token();
+ if (token != NULL)
+ tl->add(this, token);
+ tl->add(this, this->next_blocker_);
+}
+
+// Scan the relocs.
+
+void
+Scan_relocs::run(Workqueue*)
+{
+ this->object_->scan_relocs(this->symtab_, this->layout_, this->rd_);
+ delete this->rd_;
+ this->rd_ = NULL;
+ this->object_->release();
+}
+
+// Return a debugging name for the task.
+
+std::string
+Scan_relocs::get_name() const
+{
+ return "Scan_relocs " + this->object_->name();
+}
+
+// Relocate_task methods.
+
+// We may have to wait for the output sections to be written.
+
+Task_token*
+Relocate_task::is_runnable()
+{
+ if (this->object_->relocs_must_follow_section_writes()
+ && this->output_sections_blocker_->is_blocked())
+ return this->output_sections_blocker_;
+
+ if (this->object_->is_locked())
+ return this->object_->token();
+
+ return NULL;
+}
+
+// We want to lock the file while we run. We want to unblock
+// INPUT_SECTIONS_BLOCKER and FINAL_BLOCKER when we are done.
+// INPUT_SECTIONS_BLOCKER may be NULL.
+
+void
+Relocate_task::locks(Task_locker* tl)
+{
+ if (this->input_sections_blocker_ != NULL)
+ tl->add(this, this->input_sections_blocker_);
+ tl->add(this, this->final_blocker_);
+ Task_token* token = this->object_->token();
+ if (token != NULL)
+ tl->add(this, token);
+}
+
+// Run the task.
+
+void
+Relocate_task::run(Workqueue*)
+{
+ this->object_->relocate(this->symtab_, this->layout_, this->of_);
+
+ // This is normally the last thing we will do with an object, so
+ // uncache all views.
+ this->object_->clear_view_cache_marks();
+
+ this->object_->release();
+}
+
+// Return a debugging name for the task.
+
+std::string
+Relocate_task::get_name() const
+{
+ return "Relocate_task " + this->object_->name();
+}
+
+// Read the relocs and local symbols from the object file and store
+// the information in RD.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
+{
+ rd->relocs.clear();
+
+ unsigned int shnum = this->shnum();
+ if (shnum == 0)
+ return;
+
+ rd->relocs.reserve(shnum / 2);
+
+ const Output_sections& out_sections(this->output_sections());
+ const std::vector<Address>& out_offsets(this->section_offsets());
+
+ const unsigned char* pshdrs = this->get_view(this->elf_file_.shoff(),
+ shnum * This::shdr_size,
+ true, true);
+ // Skip the first, dummy, section.
+ const unsigned char* ps = pshdrs + This::shdr_size;
+ for (unsigned int i = 1; i < shnum; ++i, ps += This::shdr_size)
+ {
+ typename This::Shdr shdr(ps);
+
+ unsigned int sh_type = shdr.get_sh_type();
+ if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA)
+ continue;
+
+ unsigned int shndx = this->adjust_shndx(shdr.get_sh_info());
+ if (shndx >= shnum)
+ {
+ this->error(_("relocation section %u has bad info %u"),
+ i, shndx);
+ continue;
+ }
+
+ Output_section* os = out_sections[shndx];
+ if (os == NULL)
+ continue;
+
+ // We are scanning relocations in order to fill out the GOT and
+ // PLT sections. Relocations for sections which are not
+ // allocated (typically debugging sections) should not add new
+ // GOT and PLT entries. So we skip them unless this is a
+ // relocatable link or we need to emit relocations. FIXME: What
+ // should we do if a linker script maps a section with SHF_ALLOC
+ // clear to a section with SHF_ALLOC set?
+ typename This::Shdr secshdr(pshdrs + shndx * This::shdr_size);
+ bool is_section_allocated = ((secshdr.get_sh_flags() & elfcpp::SHF_ALLOC)
+ != 0);
+ if (!is_section_allocated
+ && !parameters->options().relocatable()
+ && !parameters->options().emit_relocs()
+ && !parameters->incremental())
+ continue;
+
+ if (this->adjust_shndx(shdr.get_sh_link()) != this->symtab_shndx_)
+ {
+ this->error(_("relocation section %u uses unexpected "
+ "symbol table %u"),
+ i, this->adjust_shndx(shdr.get_sh_link()));
+ continue;
+ }
+
+ off_t sh_size = shdr.get_sh_size();
+
+ if (sh_size == 0)
+ continue;
+
+ unsigned int reloc_size;
+ if (sh_type == elfcpp::SHT_REL)
+ reloc_size = elfcpp::Elf_sizes<size>::rel_size;
+ else
+ reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+ if (reloc_size != shdr.get_sh_entsize())
+ {
+ this->error(_("unexpected entsize for reloc section %u: %lu != %u"),
+ i, static_cast<unsigned long>(shdr.get_sh_entsize()),
+ reloc_size);
+ continue;
+ }
+
+ size_t reloc_count = sh_size / reloc_size;
+ if (static_cast<off_t>(reloc_count * reloc_size) != sh_size)
+ {
+ this->error(_("reloc section %u size %lu uneven"),
+ i, static_cast<unsigned long>(sh_size));
+ continue;
+ }
+
+ rd->relocs.push_back(Section_relocs());
+ Section_relocs& sr(rd->relocs.back());
+ sr.reloc_shndx = i;
+ sr.data_shndx = shndx;
+ sr.contents = this->get_lasting_view(shdr.get_sh_offset(), sh_size,
+ true, true);
+ sr.sh_type = sh_type;
+ sr.reloc_count = reloc_count;
+ sr.output_section = os;
+ sr.needs_special_offset_handling = out_offsets[shndx] == invalid_address;
+ sr.is_data_section_allocated = is_section_allocated;
+ }
+
+ // Read the local symbols.
+ gold_assert(this->symtab_shndx_ != -1U);
+ if (this->symtab_shndx_ == 0 || this->local_symbol_count_ == 0)
+ rd->local_symbols = NULL;
+ else
+ {
+ typename This::Shdr symtabshdr(pshdrs
+ + this->symtab_shndx_ * This::shdr_size);
+ gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+ 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;
+ rd->local_symbols = this->get_lasting_view(symtabshdr.get_sh_offset(),
+ locsize, true, true);
+ }
+}
+
+// Process the relocs to generate mappings from source sections to referenced
+// sections. This is used during garbage collection to determine garbage
+// sections.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::do_gc_process_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd)
+{
+ Sized_target<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
+
+ const unsigned char* local_symbols;
+ if (rd->local_symbols == NULL)
+ local_symbols = NULL;
+ else
+ local_symbols = rd->local_symbols->data();
+
+ for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
+ p != rd->relocs.end();
+ ++p)
+ {
+ if (!parameters->options().relocatable())
+ {
+ // As noted above, when not generating an object file, we
+ // only scan allocated sections. We may see a non-allocated
+ // section here if we are emitting relocs.
+ if (p->is_data_section_allocated)
+ target->gc_process_relocs(symtab, layout, this,
+ p->data_shndx, p->sh_type,
+ p->contents->data(), p->reloc_count,
+ p->output_section,
+ p->needs_special_offset_handling,
+ this->local_symbol_count_,
+ local_symbols);
+ }
+ }
+}
+
+
+// Scan the relocs and adjust the symbol table. This looks for
+// relocations which require GOT/PLT/COPY relocations.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::do_scan_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd)
+{
+ Sized_target<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
+
+ const unsigned char* local_symbols;
+ if (rd->local_symbols == NULL)
+ local_symbols = NULL;
+ else
+ local_symbols = rd->local_symbols->data();
+
+ // For incremental links, allocate the counters for incremental relocations.
+ if (layout->incremental_inputs() != NULL)
+ this->allocate_incremental_reloc_counts();
+
+ for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
+ p != rd->relocs.end();
+ ++p)
+ {
+ // When garbage collection is on, unreferenced sections are not included
+ // in the link that would have been included normally. This is known only
+ // after Read_relocs hence this check has to be done again.
+ if (parameters->options().gc_sections()
+ || parameters->options().icf_enabled())
+ {
+ if (p->output_section == NULL)
+ continue;
+ }
+ if (!parameters->options().relocatable())
+ {
+ // As noted above, when not generating an object file, we
+ // only scan allocated sections. We may see a non-allocated
+ // section here if we are emitting relocs.
+ if (p->is_data_section_allocated)
+ target->scan_relocs(symtab, layout, this, p->data_shndx,
+ p->sh_type, p->contents->data(),
+ p->reloc_count, p->output_section,
+ p->needs_special_offset_handling,
+ this->local_symbol_count_,
+ local_symbols);
+ if (parameters->options().emit_relocs())
+ this->emit_relocs_scan(symtab, layout, local_symbols, p);
+ if (layout->incremental_inputs() != NULL)
+ this->incremental_relocs_scan(p);
+ }
+ else
+ {
+ Relocatable_relocs* rr = this->relocatable_relocs(p->reloc_shndx);
+ gold_assert(rr != NULL);
+ rr->set_reloc_count(p->reloc_count);
+ target->scan_relocatable_relocs(symtab, layout, this,
+ p->data_shndx, p->sh_type,
+ p->contents->data(),
+ p->reloc_count,
+ p->output_section,
+ p->needs_special_offset_handling,
+ this->local_symbol_count_,
+ local_symbols,
+ rr);
+ }
+
+ delete p->contents;
+ p->contents = NULL;
+ }
+
+ // For incremental links, finalize the allocation of relocations.
+ if (layout->incremental_inputs() != NULL)
+ this->finalize_incremental_relocs(layout, true);
+
+ if (rd->local_symbols != NULL)
+ {
+ delete rd->local_symbols;
+ rd->local_symbols = NULL;
+ }
+}
+
+// This is a strategy class we use when scanning for --emit-relocs.
+
+template<int sh_type>
+class Emit_relocs_strategy
+{
+ public:
+ // A local non-section symbol.
+ inline Relocatable_relocs::Reloc_strategy
+ local_non_section_strategy(unsigned int, Relobj*, unsigned int)
+ { return Relocatable_relocs::RELOC_COPY; }
+
+ // A local section symbol.
+ inline Relocatable_relocs::Reloc_strategy
+ local_section_strategy(unsigned int, Relobj*)
+ {
+ if (sh_type == elfcpp::SHT_RELA)
+ return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA;
+ else
+ {
+ // The addend is stored in the section contents. Since this
+ // is not a relocatable link, we are going to apply the
+ // relocation contents to the section as usual. This means
+ // that we have no way to record the original addend. If the
+ // original addend is not zero, there is basically no way for
+ // the user to handle this correctly. Caveat emptor.
+ return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0;
+ }
+ }
+
+ // A global symbol.
+ inline Relocatable_relocs::Reloc_strategy
+ global_strategy(unsigned int, Relobj*, unsigned int)
+ { return Relocatable_relocs::RELOC_COPY; }
+};
+
+// Scan the input relocations for --emit-relocs.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::emit_relocs_scan(
+ Symbol_table* symtab,
+ Layout* layout,
+ const unsigned char* plocal_syms,
+ const Read_relocs_data::Relocs_list::iterator& p)
+{
+ Relocatable_relocs* rr = this->relocatable_relocs(p->reloc_shndx);
+ gold_assert(rr != NULL);
+ rr->set_reloc_count(p->reloc_count);
+
+ if (p->sh_type == elfcpp::SHT_REL)
+ this->emit_relocs_scan_reltype<elfcpp::SHT_REL>(symtab, layout,
+ plocal_syms, p, rr);
+ else
+ {
+ gold_assert(p->sh_type == elfcpp::SHT_RELA);
+ this->emit_relocs_scan_reltype<elfcpp::SHT_RELA>(symtab, layout,
+ plocal_syms, p, rr);
+ }
+}
+
+// Scan the input relocation for --emit-relocs, templatized on the
+// type of the relocation section.
+
+template<int size, bool big_endian>
+template<int sh_type>
+void
+Sized_relobj_file<size, big_endian>::emit_relocs_scan_reltype(
+ Symbol_table* symtab,
+ Layout* layout,
+ const unsigned char* plocal_syms,
+ const Read_relocs_data::Relocs_list::iterator& p,
+ Relocatable_relocs* rr)
+{
+ scan_relocatable_relocs<size, big_endian, sh_type,
+ Emit_relocs_strategy<sh_type> >(
+ symtab,
+ layout,
+ this,
+ p->data_shndx,
+ p->contents->data(),
+ p->reloc_count,
+ p->output_section,
+ p->needs_special_offset_handling,
+ this->local_symbol_count_,
+ plocal_syms,
+ rr);
+}
+
+// Scan the input relocations for --incremental.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::incremental_relocs_scan(
+ const Read_relocs_data::Relocs_list::iterator& p)
+{
+ if (p->sh_type == elfcpp::SHT_REL)
+ this->incremental_relocs_scan_reltype<elfcpp::SHT_REL>(p);
+ else
+ {
+ gold_assert(p->sh_type == elfcpp::SHT_RELA);
+ this->incremental_relocs_scan_reltype<elfcpp::SHT_RELA>(p);
+ }
+}
+
+// Scan the input relocation for --incremental, templatized on the
+// type of the relocation section.
+
+template<int size, bool big_endian>
+template<int sh_type>
+void
+Sized_relobj_file<size, big_endian>::incremental_relocs_scan_reltype(
+ const Read_relocs_data::Relocs_list::iterator& p)
+{
+ typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+ const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+ const unsigned char* prelocs = p->contents->data();
+ size_t reloc_count = p->reloc_count;
+
+ for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+ Reltype reloc(prelocs);
+
+ if (p->needs_special_offset_handling
+ && !p->output_section->is_input_address_mapped(this, p->data_shndx,
+ reloc.get_r_offset()))
+ continue;
+
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info =
+ reloc.get_r_info();
+ const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+
+ if (r_sym >= this->local_symbol_count_)
+ this->count_incremental_reloc(r_sym - this->local_symbol_count_);
+ }
+}
+
+// Relocate the input sections and write out the local symbols.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::do_relocate(const Symbol_table* symtab,
+ const Layout* layout,
+ Output_file* of)
+{
+ unsigned int shnum = this->shnum();
+
+ // Read the section headers.
+ const unsigned char* pshdrs = this->get_view(this->elf_file_.shoff(),
+ shnum * This::shdr_size,
+ true, true);
+
+ Views views;
+ views.resize(shnum);
+
+ // Make two passes over the sections. The first one copies the
+ // section data to the output file. The second one applies
+ // relocations.
+
+ this->write_sections(layout, pshdrs, of, &views);
+
+ // To speed up relocations, we set up hash tables for fast lookup of
+ // input offsets to output addresses.
+ this->initialize_input_to_output_maps();
+
+ // Apply relocations.
+
+ this->relocate_sections(symtab, layout, pshdrs, of, &views);
+
+ // After we've done the relocations, we release the hash tables,
+ // since we no longer need them.
+ this->free_input_to_output_maps();
+
+ // Write out the accumulated views.
+ for (unsigned int i = 1; i < shnum; ++i)
+ {
+ if (views[i].view != NULL)
+ {
+ if (views[i].is_ctors_reverse_view)
+ this->reverse_words(views[i].view, views[i].view_size);
+ if (!views[i].is_postprocessing_view)
+ {
+ if (views[i].is_input_output_view)
+ of->write_input_output_view(views[i].offset,
+ views[i].view_size,
+ views[i].view);
+ else
+ of->write_output_view(views[i].offset, views[i].view_size,
+ views[i].view);
+ }
+ }
+ }
+
+ // Write out the local symbols.
+ this->write_local_symbols(of, layout->sympool(), layout->dynpool(),
+ layout->symtab_xindex(), layout->dynsym_xindex(),
+ layout->symtab_section_offset());
+}
+
+// Sort a Read_multiple vector by file offset.
+struct Read_multiple_compare
+{
+ inline bool
+ operator()(const File_read::Read_multiple_entry& rme1,
+ const File_read::Read_multiple_entry& rme2) const
+ { return rme1.file_offset < rme2.file_offset; }
+};
+
+// Write section data to the output file. PSHDRS points to the
+// section headers. Record the views in *PVIEWS for use when
+// relocating.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::write_sections(const Layout* layout,
+ const unsigned char* pshdrs,
+ Output_file* of,
+ Views* pviews)
+{
+ unsigned int shnum = this->shnum();
+ const Output_sections& out_sections(this->output_sections());
+ const std::vector<Address>& out_offsets(this->section_offsets());
+
+ File_read::Read_multiple rm;
+ bool is_sorted = true;
+
+ const unsigned char* p = pshdrs + This::shdr_size;
+ for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
+ {
+ View_size* pvs = &(*pviews)[i];
+
+ pvs->view = NULL;
+
+ const Output_section* os = out_sections[i];
+ if (os == NULL)
+ continue;
+ Address output_offset = out_offsets[i];
+
+ typename This::Shdr shdr(p);
+
+ if (shdr.get_sh_type() == elfcpp::SHT_NOBITS)
+ continue;
+
+ if ((parameters->options().relocatable()
+ || parameters->options().emit_relocs())
+ && (shdr.get_sh_type() == elfcpp::SHT_REL
+ || shdr.get_sh_type() == elfcpp::SHT_RELA)
+ && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
+ {
+ // This is a reloc section in a relocatable link or when
+ // emitting relocs. We don't need to read the input file.
+ // The size and file offset are stored in the
+ // Relocatable_relocs structure.
+ Relocatable_relocs* rr = this->relocatable_relocs(i);
+ gold_assert(rr != NULL);
+ Output_data* posd = rr->output_data();
+ gold_assert(posd != NULL);
+
+ pvs->offset = posd->offset();
+ pvs->view_size = posd->data_size();
+ pvs->view = of->get_output_view(pvs->offset, pvs->view_size);
+ pvs->address = posd->address();
+ pvs->is_input_output_view = false;
+ pvs->is_postprocessing_view = false;
+ pvs->is_ctors_reverse_view = false;
+
+ continue;
+ }
+
+ // In the normal case, this input section is simply mapped to
+ // the output section at offset OUTPUT_OFFSET.
+
+ // However, if OUTPUT_OFFSET == INVALID_ADDRESS, then input data is
+ // handled specially--e.g., a .eh_frame section. The relocation
+ // routines need to check for each reloc where it should be
+ // applied. For this case, we need an input/output view for the
+ // entire contents of the section in the output file. We don't
+ // want to copy the contents of the input section to the output
+ // section; the output section contents were already written,
+ // and we waited for them in Relocate_task::is_runnable because
+ // relocs_must_follow_section_writes is set for the object.
+
+ // Regardless of which of the above cases is true, we have to
+ // check requires_postprocessing of the output section. If that
+ // is false, then we work with views of the output file
+ // directly. If it is true, then we work with a separate
+ // buffer, and the output section is responsible for writing the
+ // final data to the output file.
+
+ off_t output_section_offset;
+ Address output_section_size;
+ if (!os->requires_postprocessing())
+ {
+ output_section_offset = os->offset();
+ output_section_size = convert_types<Address, off_t>(os->data_size());
+ }
+ else
+ {
+ output_section_offset = 0;
+ output_section_size =
+ convert_types<Address, off_t>(os->postprocessing_buffer_size());
+ }
+
+ off_t view_start;
+ section_size_type view_size;
+ bool must_decompress = false;
+ if (output_offset != invalid_address)
+ {
+ view_start = output_section_offset + output_offset;
+ view_size = convert_to_section_size_type(shdr.get_sh_size());
+ section_size_type uncompressed_size;
+ if (this->section_is_compressed(i, &uncompressed_size))
+ {
+ view_size = uncompressed_size;
+ must_decompress = true;
+ }
+ }
+ else
+ {
+ view_start = output_section_offset;
+ view_size = convert_to_section_size_type(output_section_size);
+ }
+
+ if (view_size == 0)
+ continue;
+
+ gold_assert(output_offset == invalid_address
+ || output_offset + view_size <= output_section_size);
+
+ unsigned char* view;
+ if (os->requires_postprocessing())
+ {
+ unsigned char* buffer = os->postprocessing_buffer();
+ view = buffer + view_start;
+ if (output_offset != invalid_address && !must_decompress)
+ {
+ off_t sh_offset = shdr.get_sh_offset();
+ if (!rm.empty() && rm.back().file_offset > sh_offset)
+ is_sorted = false;
+ rm.push_back(File_read::Read_multiple_entry(sh_offset,
+ view_size, view));
+ }
+ }
+ else
+ {
+ if (output_offset == invalid_address)
+ view = of->get_input_output_view(view_start, view_size);
+ else
+ {
+ view = of->get_output_view(view_start, view_size);
+ if (!must_decompress)
+ {
+ off_t sh_offset = shdr.get_sh_offset();
+ if (!rm.empty() && rm.back().file_offset > sh_offset)
+ is_sorted = false;
+ rm.push_back(File_read::Read_multiple_entry(sh_offset,
+ view_size, view));
+ }
+ }
+ }
+
+ if (must_decompress)
+ {
+ // Read and decompress the section.
+ section_size_type len;
+ const unsigned char* p = this->section_contents(i, &len, false);
+ if (!decompress_input_section(p, len, view, view_size))
+ this->error(_("could not decompress section %s"),
+ this->section_name(i).c_str());
+ }
+
+ pvs->view = view;
+ pvs->address = os->address();
+ if (output_offset != invalid_address)
+ pvs->address += output_offset;
+ pvs->offset = view_start;
+ pvs->view_size = view_size;
+ pvs->is_input_output_view = output_offset == invalid_address;
+ pvs->is_postprocessing_view = os->requires_postprocessing();
+ pvs->is_ctors_reverse_view =
+ (!parameters->options().relocatable()
+ && view_size > size / 8
+ && (strcmp(os->name(), ".init_array") == 0
+ || strcmp(os->name(), ".fini_array") == 0)
+ && layout->is_ctors_in_init_array(this, i));
+ }
+
+ // Actually read the data.
+ if (!rm.empty())
+ {
+ if (!is_sorted)
+ std::sort(rm.begin(), rm.end(), Read_multiple_compare());
+ this->read_multiple(rm);
+ }
+}
+
+// Relocate section data. VIEWS points to the section data as views
+// in the output file.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::do_relocate_sections(
+ const Symbol_table* symtab,
+ const Layout* layout,
+ const unsigned char* pshdrs,
+ Output_file* of,
+ Views* pviews)
+{
+ unsigned int shnum = this->shnum();
+ Sized_target<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
+
+ const Output_sections& out_sections(this->output_sections());
+ const std::vector<Address>& out_offsets(this->section_offsets());
+
+ Relocate_info<size, big_endian> relinfo;
+ relinfo.symtab = symtab;
+ relinfo.layout = layout;
+ relinfo.object = this;
+
+ const unsigned char* p = pshdrs + This::shdr_size;
+ for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
+ {
+ typename This::Shdr shdr(p);
+
+ unsigned int sh_type = shdr.get_sh_type();
+ if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA)
+ continue;
+
+ off_t sh_size = shdr.get_sh_size();
+ if (sh_size == 0)
+ continue;
+
+ unsigned int index = this->adjust_shndx(shdr.get_sh_info());
+ if (index >= this->shnum())
+ {
+ this->error(_("relocation section %u has bad info %u"),
+ i, index);
+ continue;
+ }
+
+ Output_section* os = out_sections[index];
+ if (os == NULL)
+ {
+ // This relocation section is against a section which we
+ // discarded.
+ continue;
+ }
+ Address output_offset = out_offsets[index];
+
+ gold_assert((*pviews)[index].view != NULL);
+ if (parameters->options().relocatable())
+ gold_assert((*pviews)[i].view != NULL);
+
+ if (this->adjust_shndx(shdr.get_sh_link()) != this->symtab_shndx_)
+ {
+ gold_error(_("relocation section %u uses unexpected "
+ "symbol table %u"),
+ i, this->adjust_shndx(shdr.get_sh_link()));
+ continue;
+ }
+
+ const unsigned char* prelocs = this->get_view(shdr.get_sh_offset(),
+ sh_size, true, false);
+
+ unsigned int reloc_size;
+ if (sh_type == elfcpp::SHT_REL)
+ reloc_size = elfcpp::Elf_sizes<size>::rel_size;
+ else
+ reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+
+ if (reloc_size != shdr.get_sh_entsize())
+ {
+ gold_error(_("unexpected entsize for reloc section %u: %lu != %u"),
+ i, static_cast<unsigned long>(shdr.get_sh_entsize()),
+ reloc_size);
+ continue;
+ }
+
+ size_t reloc_count = sh_size / reloc_size;
+ if (static_cast<off_t>(reloc_count * reloc_size) != sh_size)
+ {
+ gold_error(_("reloc section %u size %lu uneven"),
+ i, static_cast<unsigned long>(sh_size));
+ continue;
+ }
+
+ gold_assert(output_offset != invalid_address
+ || this->relocs_must_follow_section_writes());
+
+ relinfo.reloc_shndx = i;
+ relinfo.reloc_shdr = p;
+ relinfo.data_shndx = index;
+ relinfo.data_shdr = pshdrs + index * This::shdr_size;
+ unsigned char* view = (*pviews)[index].view;
+ Address address = (*pviews)[index].address;
+ section_size_type view_size = (*pviews)[index].view_size;
+
+ Reloc_symbol_changes* reloc_map = NULL;
+ if (this->uses_split_stack() && output_offset != invalid_address)
+ {
+ typename This::Shdr data_shdr(pshdrs + index * This::shdr_size);
+ if ((data_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0)
+ this->split_stack_adjust(symtab, pshdrs, sh_type, index,
+ prelocs, reloc_count, view, view_size,
+ &reloc_map);
+ }
+
+ if (!parameters->options().relocatable())
+ {
+ target->relocate_section(&relinfo, sh_type, prelocs, reloc_count, os,
+ output_offset == invalid_address,
+ view, address, view_size, reloc_map);
+ if (parameters->options().emit_relocs())
+ {
+ Relocatable_relocs* rr = this->relocatable_relocs(i);
+ target->relocate_relocs(&relinfo, sh_type, prelocs, reloc_count,
+ os, output_offset, rr,
+ view, address, view_size,
+ (*pviews)[i].view,
+ (*pviews)[i].view_size);
+ }
+ if (parameters->incremental())
+ this->incremental_relocs_write(&relinfo, sh_type, prelocs,
+ reloc_count, os, output_offset, of);
+ }
+ else
+ {
+ Relocatable_relocs* rr = this->relocatable_relocs(i);
+ target->relocate_relocs(&relinfo, sh_type, prelocs, reloc_count,
+ os, output_offset, rr,
+ view, address, view_size,
+ (*pviews)[i].view,
+ (*pviews)[i].view_size);
+ }
+ }
+}
+
+// Write the incremental relocs.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::incremental_relocs_write(
+ const Relocate_info<size, big_endian>* relinfo,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ Address output_offset,
+ Output_file* of)
+{
+ if (sh_type == elfcpp::SHT_REL)
+ this->incremental_relocs_write_reltype<elfcpp::SHT_REL>(
+ relinfo,
+ prelocs,
+ reloc_count,
+ output_section,
+ output_offset,
+ of);
+ else
+ {
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+ this->incremental_relocs_write_reltype<elfcpp::SHT_RELA>(
+ relinfo,
+ prelocs,
+ reloc_count,
+ output_section,
+ output_offset,
+ of);
+ }
+}
+
+// Write the incremental relocs, templatized on the type of the
+// relocation section.
+
+template<int size, bool big_endian>
+template<int sh_type>
+void
+Sized_relobj_file<size, big_endian>::incremental_relocs_write_reltype(
+ const Relocate_info<size, big_endian>* relinfo,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ Address output_offset,
+ Output_file* of)
+{
+ typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reloc;
+ const unsigned int reloc_size =
+ Reloc_types<sh_type, size, big_endian>::reloc_size;
+ const unsigned int sizeof_addr = size / 8;
+ const unsigned int incr_reloc_size =
+ Incremental_relocs_reader<size, big_endian>::reloc_size;
+
+ unsigned int out_shndx = output_section->out_shndx();
+
+ // Get a view for the .gnu_incremental_relocs section.
+
+ Incremental_inputs* inputs = relinfo->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);
+
+ for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+ Reloc reloc(prelocs);
+
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+ const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ const unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+ if (r_sym < this->local_symbol_count_)
+ continue;
+
+ // Get the new offset--the location in the output section where
+ // this relocation should be applied.
+
+ Address offset = reloc.get_r_offset();
+ if (output_offset != invalid_address)
+ offset += output_offset;
+ else
+ {
+ section_offset_type sot_offset =
+ convert_types<section_offset_type, Address>(offset);
+ section_offset_type new_sot_offset =
+ output_section->output_offset(relinfo->object,
+ relinfo->data_shndx,
+ sot_offset);
+ gold_assert(new_sot_offset != -1);
+ offset += new_sot_offset;
+ }
+
+ // Get the addend.
+ typename elfcpp::Elf_types<size>::Elf_Swxword addend;
+ if (sh_type == elfcpp::SHT_RELA)
+ addend =
+ Reloc_types<sh_type, size, big_endian>::get_reloc_addend(&reloc);
+ else
+ {
+ // FIXME: Get the addend for SHT_REL.
+ addend = 0;
+ }
+
+ // Get the index of the output relocation.
+
+ unsigned int reloc_index =
+ this->next_incremental_reloc_index(r_sym - this->local_symbol_count_);
+
+ // Write the relocation.
+
+ unsigned char* pov = view + reloc_index * incr_reloc_size;
+ elfcpp::Swap<32, big_endian>::writeval(pov, r_type);
+ elfcpp::Swap<32, big_endian>::writeval(pov + 4, out_shndx);
+ elfcpp::Swap<size, big_endian>::writeval(pov + 8, offset);
+ elfcpp::Swap<size, big_endian>::writeval(pov + 8 + sizeof_addr, addend);
+ of->write_output_view(pov - view, incr_reloc_size, view);
+ }
+}
+
+// Create merge hash tables for the local symbols. These are used to
+// speed up relocations.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::initialize_input_to_output_maps()
+{
+ const unsigned int loccount = this->local_symbol_count_;
+ for (unsigned int i = 1; i < loccount; ++i)
+ {
+ Symbol_value<size>& lv(this->local_values_[i]);
+ lv.initialize_input_to_output_map(this);
+ }
+}
+
+// Free merge hash tables for the local symbols.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::free_input_to_output_maps()
+{
+ const unsigned int loccount = this->local_symbol_count_;
+ for (unsigned int i = 1; i < loccount; ++i)
+ {
+ Symbol_value<size>& lv(this->local_values_[i]);
+ lv.free_input_to_output_map();
+ }
+}
+
+// If an object was compiled with -fsplit-stack, this is called to
+// check whether any relocations refer to functions defined in objects
+// which were not compiled with -fsplit-stack. If they were, then we
+// need to apply some target-specific adjustments to request
+// additional stack space.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::split_stack_adjust(
+ const Symbol_table* symtab,
+ 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)
+{
+ if (sh_type == elfcpp::SHT_REL)
+ this->split_stack_adjust_reltype<elfcpp::SHT_REL>(symtab, pshdrs, shndx,
+ prelocs, reloc_count,
+ view, view_size,
+ reloc_map);
+ else
+ {
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+ this->split_stack_adjust_reltype<elfcpp::SHT_RELA>(symtab, pshdrs, shndx,
+ prelocs, reloc_count,
+ view, view_size,
+ reloc_map);
+ }
+}
+
+// Adjust for -fsplit-stack, templatized on the type of the relocation
+// section.
+
+template<int size, bool big_endian>
+template<int sh_type>
+void
+Sized_relobj_file<size, big_endian>::split_stack_adjust_reltype(
+ const Symbol_table* symtab,
+ 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)
+{
+ typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+ const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+
+ size_t local_count = this->local_symbol_count();
+
+ std::vector<section_offset_type> non_split_refs;
+
+ const unsigned char* pr = prelocs;
+ for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
+ {
+ Reltype reloc(pr);
+
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ if (r_sym < local_count)
+ continue;
+
+ const Symbol* gsym = this->global_symbol(r_sym);
+ gold_assert(gsym != NULL);
+ if (gsym->is_forwarder())
+ gsym = symtab->resolve_forwards(gsym);
+
+ // See if this relocation refers to a function defined in an
+ // object compiled without -fsplit-stack. Note that we don't
+ // care about the type of relocation--this means that in some
+ // cases we will ask for a large stack unnecessarily, but this
+ // is not fatal. FIXME: Some targets have symbols which are
+ // functions but are not type STT_FUNC, e.g., STT_ARM_TFUNC.
+ if (!gsym->is_undefined()
+ && gsym->source() == Symbol::FROM_OBJECT
+ && !gsym->object()->uses_split_stack())
+ {
+ unsigned int r_type = elfcpp::elf_r_type<size>(reloc.get_r_info());
+ if (parameters->target().is_call_to_non_split(gsym, r_type))
+ {
+ section_offset_type offset =
+ convert_to_section_size_type(reloc.get_r_offset());
+ non_split_refs.push_back(offset);
+ }
+ }
+ }
+
+ if (non_split_refs.empty())
+ return;
+
+ // At this point, every entry in NON_SPLIT_REFS indicates a
+ // relocation which refers to a function in an object compiled
+ // without -fsplit-stack. We now have to convert that list into a
+ // set of offsets to functions. First, we find all the functions.
+
+ Function_offsets function_offsets;
+ this->find_functions(pshdrs, shndx, &function_offsets);
+ if (function_offsets.empty())
+ return;
+
+ // Now get a list of the function with references to non split-stack
+ // code.
+
+ Function_offsets calls_non_split;
+ for (std::vector<section_offset_type>::const_iterator p
+ = non_split_refs.begin();
+ p != non_split_refs.end();
+ ++p)
+ {
+ Function_offsets::const_iterator low = function_offsets.lower_bound(*p);
+ if (low == function_offsets.end())
+ --low;
+ else if (low->first == *p)
+ ;
+ else if (low == function_offsets.begin())
+ continue;
+ else
+ --low;
+
+ calls_non_split.insert(*low);
+ }
+ if (calls_non_split.empty())
+ return;
+
+ // Now we have a set of functions to adjust. The adjustments are
+ // target specific. Besides changing the output section view
+ // however, it likes, the target may request a relocation change
+ // from one global symbol name to another.
+
+ for (Function_offsets::const_iterator p = calls_non_split.begin();
+ p != calls_non_split.end();
+ ++p)
+ {
+ std::string from;
+ std::string to;
+ parameters->target().calls_non_split(this, shndx, p->first, p->second,
+ view, view_size, &from, &to);
+ if (!from.empty())
+ {
+ gold_assert(!to.empty());
+ Symbol* tosym = NULL;
+
+ // Find relocations in the relevant function which are for
+ // FROM.
+ pr = prelocs;
+ for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
+ {
+ Reltype reloc(pr);
+
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info =
+ reloc.get_r_info();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ if (r_sym < local_count)
+ continue;
+
+ section_offset_type offset =
+ convert_to_section_size_type(reloc.get_r_offset());
+ if (offset < p->first
+ || (offset
+ >= (p->first
+ + static_cast<section_offset_type>(p->second))))
+ continue;
+
+ const Symbol* gsym = this->global_symbol(r_sym);
+ if (from == gsym->name())
+ {
+ if (tosym == NULL)
+ {
+ tosym = symtab->lookup(to.c_str());
+ if (tosym == NULL)
+ {
+ this->error(_("could not convert call "
+ "to '%s' to '%s'"),
+ from.c_str(), to.c_str());
+ break;
+ }
+ }
+
+ if (*reloc_map == NULL)
+ *reloc_map = new Reloc_symbol_changes(reloc_count);
+ (*reloc_map)->set(i, tosym);
+ }
+ }
+ }
+ }
+}
+
+// Find all the function in this object defined in section SHNDX.
+// Store their offsets in the section in FUNCTION_OFFSETS.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::find_functions(
+ const unsigned char* pshdrs,
+ unsigned int shndx,
+ Sized_relobj_file<size, big_endian>::Function_offsets* function_offsets)
+{
+ // We need to read the symbols to find the functions. If we wanted
+ // to, we could cache reading the symbols across all sections in the
+ // object.
+ const unsigned int symtab_shndx = this->symtab_shndx_;
+ typename This::Shdr symtabshdr(pshdrs + symtab_shndx * This::shdr_size);
+ gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+
+ typename elfcpp::Elf_types<size>::Elf_WXword sh_size =
+ symtabshdr.get_sh_size();
+ const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
+ sh_size, true, true);
+
+ const int sym_size = This::sym_size;
+ const unsigned int symcount = sh_size / sym_size;
+ for (unsigned int i = 0; i < symcount; ++i, psyms += sym_size)
+ {
+ typename elfcpp::Sym<size, big_endian> isym(psyms);
+
+ // FIXME: Some targets can have functions which do not have type
+ // STT_FUNC, e.g., STT_ARM_TFUNC.
+ if (isym.get_st_type() != elfcpp::STT_FUNC
+ || isym.get_st_size() == 0)
+ continue;
+
+ bool is_ordinary;
+ unsigned int sym_shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(),
+ &is_ordinary);
+ if (!is_ordinary || sym_shndx != shndx)
+ continue;
+
+ section_offset_type value =
+ convert_to_section_size_type(isym.get_st_value());
+ section_size_type fnsize =
+ convert_to_section_size_type(isym.get_st_size());
+
+ (*function_offsets)[value] = fnsize;
+ }
+}
+
+// Reverse the words in a section. Used for .ctors sections mapped to
+// .init_array sections. See ctors_sections_in_init_array in
+// layout.cc.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::reverse_words(unsigned char* view,
+ section_size_type view_size)
+{
+ typedef typename elfcpp::Swap<size, big_endian>::Valtype Valtype;
+ Valtype* vview = reinterpret_cast<Valtype*>(view);
+ section_size_type vview_size = view_size / (size / 8);
+ for (section_size_type i = 0; i < vview_size / 2; ++i)
+ {
+ Valtype tmp = vview[i];
+ vview[i] = vview[vview_size - 1 - i];
+ vview[vview_size - 1 - i] = tmp;
+ }
+}
+
+// Class Merged_symbol_value.
+
+template<int size>
+void
+Merged_symbol_value<size>::initialize_input_to_output_map(
+ const Relobj* object,
+ unsigned int input_shndx)
+{
+ Object_merge_map* map = object->merge_map();
+ map->initialize_input_to_output_map<size>(input_shndx,
+ this->output_start_address_,
+ &this->output_addresses_);
+}
+
+// Get the output value corresponding to an input offset if we
+// couldn't find it in the hash table.
+
+template<int size>
+typename elfcpp::Elf_types<size>::Elf_Addr
+Merged_symbol_value<size>::value_from_output_section(
+ const Relobj* object,
+ unsigned int input_shndx,
+ typename elfcpp::Elf_types<size>::Elf_Addr input_offset) const
+{
+ section_offset_type output_offset;
+ bool found = object->merge_map()->get_output_offset(NULL, input_shndx,
+ input_offset,
+ &output_offset);
+
+ // If this assertion fails, it means that some relocation was
+ // against a portion of an input merge section which we didn't map
+ // to the output file and we didn't explicitly discard. We should
+ // always map all portions of input merge sections.
+ gold_assert(found);
+
+ if (output_offset == -1)
+ return 0;
+ else
+ return this->output_start_address_ + output_offset;
+}
+
+// Track_relocs methods.
+
+// Initialize the class to track the relocs. This gets the object,
+// the reloc section index, and the type of the relocs. This returns
+// false if something goes wrong.
+
+template<int size, bool big_endian>
+bool
+Track_relocs<size, big_endian>::initialize(
+ Object* object,
+ unsigned int reloc_shndx,
+ unsigned int reloc_type)
+{
+ // If RELOC_SHNDX is -1U, it means there is more than one reloc
+ // section for the .eh_frame section. We can't handle that case.
+ if (reloc_shndx == -1U)
+ return false;
+
+ // If RELOC_SHNDX is 0, there is no reloc section.
+ if (reloc_shndx == 0)
+ return true;
+
+ // Get the contents of the reloc section.
+ this->prelocs_ = object->section_contents(reloc_shndx, &this->len_, false);
+
+ if (reloc_type == elfcpp::SHT_REL)
+ this->reloc_size_ = elfcpp::Elf_sizes<size>::rel_size;
+ else if (reloc_type == elfcpp::SHT_RELA)
+ this->reloc_size_ = elfcpp::Elf_sizes<size>::rela_size;
+ else
+ gold_unreachable();
+
+ if (this->len_ % this->reloc_size_ != 0)
+ {
+ object->error(_("reloc section size %zu is not a multiple of "
+ "reloc size %d\n"),
+ static_cast<size_t>(this->len_),
+ this->reloc_size_);
+ return false;
+ }
+
+ return true;
+}
+
+// Return the offset of the next reloc, or -1 if there isn't one.
+
+template<int size, bool big_endian>
+off_t
+Track_relocs<size, big_endian>::next_offset() const
+{
+ if (this->pos_ >= this->len_)
+ return -1;
+
+ // Rel and Rela start out the same, so we can always use Rel to find
+ // the r_offset value.
+ elfcpp::Rel<size, big_endian> rel(this->prelocs_ + this->pos_);
+ return rel.get_r_offset();
+}
+
+// Return the index of the symbol referenced by the next reloc, or -1U
+// if there aren't any more relocs.
+
+template<int size, bool big_endian>
+unsigned int
+Track_relocs<size, big_endian>::next_symndx() const
+{
+ if (this->pos_ >= this->len_)
+ return -1U;
+
+ // Rel and Rela start out the same, so we can use Rel to find the
+ // symbol index.
+ elfcpp::Rel<size, big_endian> rel(this->prelocs_ + this->pos_);
+ return elfcpp::elf_r_sym<size>(rel.get_r_info());
+}
+
+// Return the addend of the next reloc, or 0 if there isn't one.
+
+template<int size, bool big_endian>
+uint64_t
+Track_relocs<size, big_endian>::next_addend() const
+{
+ if (this->pos_ >= this->len_)
+ return 0;
+ if (this->reloc_size_ == elfcpp::Elf_sizes<size>::rel_size)
+ return 0;
+ elfcpp::Rela<size, big_endian> rela(this->prelocs_ + this->pos_);
+ return rela.get_r_addend();
+}
+
+// Advance to the next reloc whose r_offset is greater than or equal
+// to OFFSET. Return the number of relocs we skip.
+
+template<int size, bool big_endian>
+int
+Track_relocs<size, big_endian>::advance(off_t offset)
+{
+ int ret = 0;
+ while (this->pos_ < this->len_)
+ {
+ // Rel and Rela start out the same, so we can always use Rel to
+ // find the r_offset value.
+ elfcpp::Rel<size, big_endian> rel(this->prelocs_ + this->pos_);
+ if (static_cast<off_t>(rel.get_r_offset()) >= offset)
+ break;
+ ++ret;
+ this->pos_ += this->reloc_size_;
+ }
+ return ret;
+}
+
+// Instantiate the templates we need.
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+void
+Sized_relobj_file<32, false>::do_read_relocs(Read_relocs_data* rd);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+void
+Sized_relobj_file<32, true>::do_read_relocs(Read_relocs_data* rd);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+void
+Sized_relobj_file<64, false>::do_read_relocs(Read_relocs_data* rd);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+void
+Sized_relobj_file<64, true>::do_read_relocs(Read_relocs_data* rd);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+void
+Sized_relobj_file<32, false>::do_gc_process_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+void
+Sized_relobj_file<32, true>::do_gc_process_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+void
+Sized_relobj_file<64, false>::do_gc_process_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+void
+Sized_relobj_file<64, true>::do_gc_process_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+void
+Sized_relobj_file<32, false>::do_scan_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+void
+Sized_relobj_file<32, true>::do_scan_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+void
+Sized_relobj_file<64, false>::do_scan_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+void
+Sized_relobj_file<64, true>::do_scan_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+void
+Sized_relobj_file<32, false>::do_relocate(const Symbol_table* symtab,
+ const Layout* layout,
+ Output_file* of);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+void
+Sized_relobj_file<32, true>::do_relocate(const Symbol_table* symtab,
+ const Layout* layout,
+ Output_file* of);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+void
+Sized_relobj_file<64, false>::do_relocate(const Symbol_table* symtab,
+ const Layout* layout,
+ Output_file* of);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+void
+Sized_relobj_file<64, true>::do_relocate(const Symbol_table* symtab,
+ const Layout* layout,
+ Output_file* of);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+void
+Sized_relobj_file<32, false>::do_relocate_sections(
+ const Symbol_table* symtab,
+ const Layout* layout,
+ const unsigned char* pshdrs,
+ Output_file* of,
+ Views* pviews);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+void
+Sized_relobj_file<32, true>::do_relocate_sections(
+ const Symbol_table* symtab,
+ const Layout* layout,
+ const unsigned char* pshdrs,
+ Output_file* of,
+ Views* pviews);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+void
+Sized_relobj_file<64, false>::do_relocate_sections(
+ const Symbol_table* symtab,
+ const Layout* layout,
+ const unsigned char* pshdrs,
+ Output_file* of,
+ Views* pviews);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+void
+Sized_relobj_file<64, true>::do_relocate_sections(
+ const Symbol_table* symtab,
+ const Layout* layout,
+ const unsigned char* pshdrs,
+ Output_file* of,
+ Views* pviews);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+void
+Sized_relobj_file<32, false>::initialize_input_to_output_maps();
+
+template
+void
+Sized_relobj_file<32, false>::free_input_to_output_maps();
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+void
+Sized_relobj_file<32, true>::initialize_input_to_output_maps();
+
+template
+void
+Sized_relobj_file<32, true>::free_input_to_output_maps();
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+void
+Sized_relobj_file<64, false>::initialize_input_to_output_maps();
+
+template
+void
+Sized_relobj_file<64, false>::free_input_to_output_maps();
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+void
+Sized_relobj_file<64, true>::initialize_input_to_output_maps();
+
+template
+void
+Sized_relobj_file<64, true>::free_input_to_output_maps();
+#endif
+
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+template
+class Merged_symbol_value<32>;
+#endif
+
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+template
+class Merged_symbol_value<64>;
+#endif
+
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+template
+class Symbol_value<32>;
+#endif
+
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+template
+class Symbol_value<64>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Track_relocs<32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Track_relocs<32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Track_relocs<64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Track_relocs<64, true>;
+#endif
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/reloc.h b/binutils-2.25/gold/reloc.h
new file mode 100644
index 00000000..4eca71a7
--- /dev/null
+++ b/binutils-2.25/gold/reloc.h
@@ -0,0 +1,899 @@
+// reloc.h -- relocate input files for gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This 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_RELOC_H
+#define GOLD_RELOC_H
+
+#include <vector>
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+#endif
+
+#include "elfcpp.h"
+#include "workqueue.h"
+
+namespace gold
+{
+
+class General_options;
+class Object;
+class Relobj;
+struct Read_relocs_data;
+class Symbol;
+class Layout;
+class Output_data;
+class Output_section;
+
+template<int size>
+class Sized_symbol;
+
+template<int size, bool big_endian>
+class Sized_relobj_file;
+
+template<int size>
+class Symbol_value;
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Output_data_reloc;
+
+// A class to read the relocations for an object file, and then queue
+// up a task to see if they require any GOT/PLT/COPY relocations in
+// the symbol table.
+
+class Read_relocs : public Task
+{
+ public:
+ // THIS_BLOCKER and NEXT_BLOCKER are passed along to a Scan_relocs
+ // or Gc_process_relocs task, so that they run in a deterministic
+ // order.
+ Read_relocs(Symbol_table* symtab, Layout* layout, Relobj* object,
+ Task_token* this_blocker, Task_token* next_blocker)
+ : symtab_(symtab), layout_(layout), object_(object),
+ this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const;
+
+ private:
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Relobj* object_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// Process the relocs to figure out which sections are garbage.
+// Very similar to scan relocs.
+
+class Gc_process_relocs : public Task
+{
+ public:
+ // THIS_BLOCKER prevents this task from running until the previous
+ // one is finished. NEXT_BLOCKER prevents the next task from
+ // running.
+ Gc_process_relocs(Symbol_table* symtab, Layout* layout, Relobj* object,
+ Read_relocs_data* rd, Task_token* this_blocker,
+ Task_token* next_blocker)
+ : symtab_(symtab), layout_(layout), object_(object), rd_(rd),
+ this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Gc_process_relocs();
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const;
+
+ private:
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Relobj* object_;
+ Read_relocs_data* rd_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// Scan the relocations for an object to see if they require any
+// GOT/PLT/COPY relocations.
+
+class Scan_relocs : public Task
+{
+ public:
+ // THIS_BLOCKER prevents this task from running until the previous
+ // one is finished. NEXT_BLOCKER prevents the next task from
+ // running.
+ Scan_relocs(Symbol_table* symtab, Layout* layout, Relobj* object,
+ Read_relocs_data* rd, Task_token* this_blocker,
+ Task_token* next_blocker)
+ : symtab_(symtab), layout_(layout), object_(object), rd_(rd),
+ this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Scan_relocs();
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const;
+
+ private:
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Relobj* object_;
+ Read_relocs_data* rd_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// A class to perform all the relocations for an object file.
+
+class Relocate_task : public Task
+{
+ public:
+ Relocate_task(const Symbol_table* symtab, const Layout* layout,
+ Relobj* object, Output_file* of,
+ Task_token* input_sections_blocker,
+ Task_token* output_sections_blocker, Task_token* final_blocker)
+ : symtab_(symtab), layout_(layout), object_(object), of_(of),
+ input_sections_blocker_(input_sections_blocker),
+ 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;
+
+ private:
+ const Symbol_table* symtab_;
+ const Layout* layout_;
+ Relobj* object_;
+ Output_file* of_;
+ Task_token* input_sections_blocker_;
+ Task_token* output_sections_blocker_;
+ Task_token* final_blocker_;
+};
+
+// During a relocatable link, this class records how relocations
+// should be handled for a single input reloc section. An instance of
+// this class is created while scanning relocs, and it is used while
+// processing relocs.
+
+class Relocatable_relocs
+{
+ public:
+ // We use a vector of unsigned char to indicate how the input relocs
+ // should be handled. Each element is one of the following values.
+ // We create this vector when we initially scan the relocations.
+ enum Reloc_strategy
+ {
+ // Copy the input reloc. Don't modify it other than updating the
+ // r_offset field and the r_sym part of the r_info field.
+ RELOC_COPY,
+ // Copy the input reloc which is against an STT_SECTION symbol.
+ // Update the r_offset and r_sym part of the r_info field. Adjust
+ // the addend by subtracting the value of the old local symbol and
+ // adding the value of the new local symbol. The addend is in the
+ // SHT_RELA reloc and the contents of the data section do not need
+ // to be changed.
+ RELOC_ADJUST_FOR_SECTION_RELA,
+ // Like RELOC_ADJUST_FOR_SECTION_RELA but the addend should not be
+ // adjusted.
+ RELOC_ADJUST_FOR_SECTION_0,
+ // Like RELOC_ADJUST_FOR_SECTION_RELA but the contents of the
+ // section need to be changed. The number indicates the number of
+ // bytes in the addend in the section contents.
+ RELOC_ADJUST_FOR_SECTION_1,
+ RELOC_ADJUST_FOR_SECTION_2,
+ RELOC_ADJUST_FOR_SECTION_4,
+ RELOC_ADJUST_FOR_SECTION_8,
+ // Like RELOC_ADJUST_FOR_SECTION_4 but for unaligned relocs.
+ RELOC_ADJUST_FOR_SECTION_4_UNALIGNED,
+ // Discard the input reloc--process it completely when relocating
+ // the data section contents.
+ RELOC_DISCARD,
+ // An input reloc which is not discarded, but which requires
+ // target specific processing in order to update it.
+ RELOC_SPECIAL
+ };
+
+ Relocatable_relocs()
+ : reloc_strategies_(), output_reloc_count_(0), posd_(NULL)
+ { }
+
+ // Record the number of relocs.
+ void
+ set_reloc_count(size_t reloc_count)
+ { this->reloc_strategies_.reserve(reloc_count); }
+
+ // Record what to do for the next reloc.
+ void
+ set_next_reloc_strategy(Reloc_strategy strategy)
+ {
+ this->reloc_strategies_.push_back(static_cast<unsigned char>(strategy));
+ if (strategy != RELOC_DISCARD)
+ ++this->output_reloc_count_;
+ }
+
+ // Record the Output_data associated with this reloc section.
+ void
+ set_output_data(Output_data* posd)
+ {
+ gold_assert(this->posd_ == NULL);
+ this->posd_ = posd;
+ }
+
+ // Return the Output_data associated with this reloc section.
+ Output_data*
+ output_data() const
+ { return this->posd_; }
+
+ // Return what to do for reloc I.
+ Reloc_strategy
+ strategy(unsigned int i) const
+ {
+ gold_assert(i < this->reloc_strategies_.size());
+ return static_cast<Reloc_strategy>(this->reloc_strategies_[i]);
+ }
+
+ // Return the number of relocations to create in the output file.
+ size_t
+ output_reloc_count() const
+ { return this->output_reloc_count_; }
+
+ private:
+ typedef std::vector<unsigned char> Reloc_strategies;
+
+ // The strategies for the input reloc. There is one entry in this
+ // vector for each relocation in the input section.
+ Reloc_strategies reloc_strategies_;
+ // The number of relocations to be created in the output file.
+ size_t output_reloc_count_;
+ // The output data structure associated with this relocation.
+ Output_data* posd_;
+};
+
+// Standard relocation routines which are used on many targets. Here
+// SIZE and BIG_ENDIAN refer to the target, not the relocation type.
+
+template<int size, bool big_endian>
+class Relocate_functions
+{
+private:
+ // Do a simple relocation with the addend in the section contents.
+ // VALSIZE is the size of the value.
+ template<int valsize>
+ static inline void
+ rel(unsigned char* view,
+ typename elfcpp::Swap<valsize, big_endian>::Valtype value)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype x = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, x + value);
+ }
+
+ // Like the above but for relocs at unaligned addresses.
+ template<int valsize>
+ static inline void
+ rel_unaligned(unsigned char* view,
+ typename elfcpp::Swap<valsize, big_endian>::Valtype value)
+ {
+ typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
+ Valtype;
+ Valtype x = elfcpp::Swap_unaligned<valsize, big_endian>::readval(view);
+ elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view, x + value);
+ }
+
+ // Do a simple relocation using a Symbol_value with the addend in
+ // the section contents. VALSIZE is the size of the value to
+ // relocate.
+ template<int valsize>
+ static inline void
+ rel(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype x = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ x = psymval->value(object, x);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, x);
+ }
+
+ // Like the above but for relocs at unaligned addresses.
+ template<int valsize>
+ static inline void
+ rel_unaligned(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval)
+ {
+ typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
+ Valtype;
+ Valtype x = elfcpp::Swap_unaligned<valsize, big_endian>::readval(view);
+ x = psymval->value(object, x);
+ elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view, x);
+ }
+
+ // Do a simple relocation with the addend in the relocation.
+ // VALSIZE is the size of the value.
+ template<int valsize>
+ static inline void
+ rela(unsigned char* view,
+ typename elfcpp::Swap<valsize, big_endian>::Valtype value,
+ typename elfcpp::Swap<valsize, big_endian>::Valtype addend)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, value + addend);
+ }
+
+ // Do a simple relocation using a symbol value with the addend in
+ // the relocation. VALSIZE is the size of the value.
+ template<int valsize>
+ static inline void
+ rela(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<valsize, big_endian>::Valtype addend)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype x = psymval->value(object, addend);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, x);
+ }
+
+ // Do a simple PC relative relocation with the addend in the section
+ // contents. VALSIZE is the size of the value.
+ template<int valsize>
+ static inline void
+ pcrel(unsigned char* view,
+ typename elfcpp::Swap<valsize, big_endian>::Valtype value,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype x = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, x + value - address);
+ }
+
+ // Like the above but for relocs at unaligned addresses.
+ template<int valsize>
+ static inline void
+ pcrel_unaligned(unsigned char* view,
+ typename elfcpp::Swap<valsize, big_endian>::Valtype value,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype x = elfcpp::Swap_unaligned<valsize, big_endian>::readval(view);
+ elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view,
+ x + value - address);
+ }
+
+ // Do a simple PC relative relocation with a Symbol_value with the
+ // addend in the section contents. VALSIZE is the size of the
+ // value.
+ template<int valsize>
+ static inline void
+ pcrel(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype x = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ x = psymval->value(object, x);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, x - address);
+ }
+
+ // Do a simple PC relative relocation with the addend in the
+ // relocation. VALSIZE is the size of the value.
+ template<int valsize>
+ static inline void
+ pcrela(unsigned char* view,
+ typename elfcpp::Swap<valsize, big_endian>::Valtype value,
+ typename elfcpp::Swap<valsize, big_endian>::Valtype addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, value + addend - address);
+ }
+
+ // Do a simple PC relative relocation with a Symbol_value with the
+ // addend in the relocation. VALSIZE is the size of the value.
+ template<int valsize>
+ static inline void
+ pcrela(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<valsize, big_endian>::Valtype addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype x = psymval->value(object, addend);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, x - address);
+ }
+
+ typedef Relocate_functions<size, big_endian> This;
+
+public:
+ // Do a simple 8-bit REL relocation with the addend in the section
+ // contents.
+ static inline void
+ rel8(unsigned char* view, unsigned char value)
+ { This::template rel<8>(view, value); }
+
+ static inline void
+ rel8(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval)
+ { This::template rel<8>(view, object, psymval); }
+
+ // Do an 8-bit RELA relocation with the addend in the relocation.
+ static inline void
+ rela8(unsigned char* view, unsigned char value, unsigned char addend)
+ { This::template rela<8>(view, value, addend); }
+
+ static inline void
+ rela8(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ unsigned char addend)
+ { This::template rela<8>(view, object, psymval, addend); }
+
+ // Do a simple 8-bit PC relative relocation with the addend in the
+ // section contents.
+ static inline void
+ pcrel8(unsigned char* view, unsigned char value,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<8>(view, value, address); }
+
+ static inline void
+ pcrel8(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<8>(view, object, psymval, address); }
+
+ // Do a simple 8-bit PC relative RELA relocation with the addend in
+ // the reloc.
+ static inline void
+ pcrela8(unsigned char* view, unsigned char value, unsigned char addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrela<8>(view, value, addend, address); }
+
+ static inline void
+ pcrela8(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ unsigned char addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrela<8>(view, object, psymval, addend, address); }
+
+ // Do a simple 16-bit REL relocation with the addend in the section
+ // contents.
+ static inline void
+ rel16(unsigned char* view, elfcpp::Elf_Half value)
+ { This::template rel<16>(view, value); }
+
+ static inline void
+ rel16(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval)
+ { This::template rel<16>(view, object, psymval); }
+
+ // Do an 16-bit RELA relocation with the addend in the relocation.
+ static inline void
+ rela16(unsigned char* view, elfcpp::Elf_Half value, elfcpp::Elf_Half addend)
+ { This::template rela<16>(view, value, addend); }
+
+ static inline void
+ rela16(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ elfcpp::Elf_Half addend)
+ { This::template rela<16>(view, object, psymval, addend); }
+
+ // Do a simple 16-bit PC relative REL relocation with the addend in
+ // the section contents.
+ static inline void
+ pcrel16(unsigned char* view, elfcpp::Elf_Half value,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<16>(view, value, address); }
+
+ static inline void
+ pcrel16(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<16>(view, object, psymval, address); }
+
+ // Do a simple 16-bit PC relative RELA relocation with the addend in
+ // the reloc.
+ static inline void
+ pcrela16(unsigned char* view, elfcpp::Elf_Half value,
+ elfcpp::Elf_Half addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrela<16>(view, value, addend, address); }
+
+ static inline void
+ pcrela16(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ elfcpp::Elf_Half addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrela<16>(view, object, psymval, addend, address); }
+
+ // Do a simple 32-bit REL relocation with the addend in the section
+ // contents.
+ static inline void
+ rel32(unsigned char* view, elfcpp::Elf_Word value)
+ { This::template rel<32>(view, value); }
+
+ // Like above but for relocs at unaligned addresses.
+ static inline void
+ rel32_unaligned(unsigned char* view, elfcpp::Elf_Word value)
+ { This::template rel_unaligned<32>(view, value); }
+
+ static inline void
+ rel32(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval)
+ { This::template rel<32>(view, object, psymval); }
+
+ // Like above but for relocs at unaligned addresses.
+ static inline void
+ rel32_unaligned(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval)
+ { This::template rel_unaligned<32>(view, object, psymval); }
+
+ // Do an 32-bit RELA relocation with the addend in the relocation.
+ static inline void
+ rela32(unsigned char* view, elfcpp::Elf_Word value, elfcpp::Elf_Word addend)
+ { This::template rela<32>(view, value, addend); }
+
+ static inline void
+ rela32(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ elfcpp::Elf_Word addend)
+ { This::template rela<32>(view, object, psymval, addend); }
+
+ // Do a simple 32-bit PC relative REL relocation with the addend in
+ // the section contents.
+ static inline void
+ pcrel32(unsigned char* view, elfcpp::Elf_Word value,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<32>(view, value, address); }
+
+ // Unaligned version of the above.
+ static inline void
+ pcrel32_unaligned(unsigned char* view, elfcpp::Elf_Word value,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel_unaligned<32>(view, value, address); }
+
+ static inline void
+ pcrel32(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<32>(view, object, psymval, address); }
+
+ // Do a simple 32-bit PC relative RELA relocation with the addend in
+ // the relocation.
+ static inline void
+ pcrela32(unsigned char* view, elfcpp::Elf_Word value,
+ elfcpp::Elf_Word addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrela<32>(view, value, addend, address); }
+
+ static inline void
+ pcrela32(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ elfcpp::Elf_Word addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrela<32>(view, object, psymval, addend, address); }
+
+ // Do a simple 64-bit REL relocation with the addend in the section
+ // contents.
+ static inline void
+ rel64(unsigned char* view, elfcpp::Elf_Xword value)
+ { This::template rel<64>(view, value); }
+
+ static inline void
+ rel64(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval)
+ { This::template rel<64>(view, object, psymval); }
+
+ // Do a 64-bit RELA relocation with the addend in the relocation.
+ static inline void
+ rela64(unsigned char* view, elfcpp::Elf_Xword value,
+ elfcpp::Elf_Xword addend)
+ { This::template rela<64>(view, value, addend); }
+
+ static inline void
+ rela64(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ elfcpp::Elf_Xword addend)
+ { This::template rela<64>(view, object, psymval, addend); }
+
+ // Do a simple 64-bit PC relative REL relocation with the addend in
+ // the section contents.
+ static inline void
+ pcrel64(unsigned char* view, elfcpp::Elf_Xword value,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<64>(view, value, address); }
+
+ static inline void
+ pcrel64(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<64>(view, object, psymval, address); }
+
+ // Do a simple 64-bit PC relative RELA relocation with the addend in
+ // the relocation.
+ static inline void
+ pcrela64(unsigned char* view, elfcpp::Elf_Xword value,
+ elfcpp::Elf_Xword addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrela<64>(view, value, addend, address); }
+
+ static inline void
+ pcrela64(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ elfcpp::Elf_Xword addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrela<64>(view, object, psymval, addend, address); }
+};
+
+// Integer manipulation functions used by various targets when
+// performing relocations.
+
+template<int bits>
+class Bits
+{
+ public:
+ // Sign extend an n-bit unsigned integer stored in a uint32_t into
+ // an int32_t. BITS must be between 1 and 32.
+ static inline int32_t
+ sign_extend32(uint32_t val)
+ {
+ gold_assert(bits > 0 && bits <= 32);
+ if (bits == 32)
+ return static_cast<int32_t>(val);
+ uint32_t mask = (~static_cast<uint32_t>(0)) >> (32 - bits);
+ val &= mask;
+ uint32_t top_bit = 1U << (bits - 1);
+ int32_t as_signed = static_cast<int32_t>(val);
+ if ((val & top_bit) != 0)
+ as_signed -= static_cast<int32_t>(top_bit * 2);
+ return as_signed;
+ }
+
+ // Return true if VAL (stored in a uint32_t) has overflowed a signed
+ // value with BITS bits.
+ static inline bool
+ has_overflow32(uint32_t val)
+ {
+ gold_assert(bits > 0 && bits <= 32);
+ if (bits == 32)
+ return false;
+ int32_t max = (1 << (bits - 1)) - 1;
+ int32_t min = -(1 << (bits - 1));
+ int32_t as_signed = static_cast<int32_t>(val);
+ return as_signed > max || as_signed < min;
+ }
+
+ // Return true if VAL (stored in a uint32_t) has overflowed both a
+ // signed and an unsigned value. E.g.,
+ // Bits<8>::has_signed_unsigned_overflow32 would check -128 <= VAL <
+ // 255.
+ static inline bool
+ has_signed_unsigned_overflow32(uint32_t val)
+ {
+ gold_assert(bits > 0 && bits <= 32);
+ if (bits == 32)
+ return false;
+ int32_t max = static_cast<int32_t>((1U << bits) - 1);
+ int32_t min = -(1 << (bits - 1));
+ int32_t as_signed = static_cast<int32_t>(val);
+ return as_signed > max || as_signed < min;
+ }
+
+ // Select bits from A and B using bits in MASK. For each n in
+ // [0..31], the n-th bit in the result is chosen from the n-th bits
+ // of A and B. A zero selects A and a one selects B.
+ static inline uint32_t
+ bit_select32(uint32_t a, uint32_t b, uint32_t mask)
+ { return (a & ~mask) | (b & mask); }
+
+ // Sign extend an n-bit unsigned integer stored in a uint64_t into
+ // an int64_t. BITS must be between 1 and 64.
+ static inline int64_t
+ sign_extend(uint64_t val)
+ {
+ gold_assert(bits > 0 && bits <= 64);
+ if (bits == 64)
+ return static_cast<int64_t>(val);
+ uint64_t mask = (~static_cast<uint64_t>(0)) >> (64 - bits);
+ val &= mask;
+ uint64_t top_bit = static_cast<uint64_t>(1) << (bits - 1);
+ int64_t as_signed = static_cast<int64_t>(val);
+ if ((val & top_bit) != 0)
+ as_signed -= static_cast<int64_t>(top_bit * 2);
+ return as_signed;
+ }
+
+ // Return true if VAL (stored in a uint64_t) has overflowed a signed
+ // value with BITS bits.
+ static inline bool
+ has_overflow(uint64_t val)
+ {
+ gold_assert(bits > 0 && bits <= 64);
+ if (bits == 64)
+ return false;
+ int64_t max = (static_cast<int64_t>(1) << (bits - 1)) - 1;
+ int64_t min = -(static_cast<int64_t>(1) << (bits - 1));
+ int64_t as_signed = static_cast<int64_t>(val);
+ return as_signed > max || as_signed < min;
+ }
+
+ // Return true if VAL (stored in a uint64_t) has overflowed both a
+ // signed and an unsigned value. E.g.,
+ // Bits<8>::has_signed_unsigned_overflow would check -128 <= VAL <
+ // 255.
+ static inline bool
+ has_signed_unsigned_overflow64(uint64_t val)
+ {
+ gold_assert(bits > 0 && bits <= 64);
+ if (bits == 64)
+ return false;
+ int64_t max = static_cast<int64_t>((static_cast<uint64_t>(1) << bits) - 1);
+ int64_t min = -(static_cast<int64_t>(1) << (bits - 1));
+ int64_t as_signed = static_cast<int64_t>(val);
+ return as_signed > max || as_signed < min;
+ }
+
+ // Select bits from A and B using bits in MASK. For each n in
+ // [0..31], the n-th bit in the result is chosen from the n-th bits
+ // of A and B. A zero selects A and a one selects B.
+ static inline uint64_t
+ bit_select64(uint64_t a, uint64_t b, uint64_t mask)
+ { return (a & ~mask) | (b & mask); }
+};
+
+// Track relocations while reading a section. This lets you ask for
+// the relocation at a certain offset, and see how relocs occur
+// between points of interest.
+
+template<int size, bool big_endian>
+class Track_relocs
+{
+ public:
+ Track_relocs()
+ : prelocs_(NULL), len_(0), pos_(0), reloc_size_(0)
+ { }
+
+ // Initialize the Track_relocs object. OBJECT is the object holding
+ // the reloc section, RELOC_SHNDX is the section index of the reloc
+ // section, and RELOC_TYPE is the type of the reloc section
+ // (elfcpp::SHT_REL or elfcpp::SHT_RELA). This returns false if
+ // something went wrong.
+ bool
+ initialize(Object* object, unsigned int reloc_shndx,
+ unsigned int reloc_type);
+
+ // Return the offset in the data section to which the next reloc
+ // applies. This returns -1 if there is no next reloc.
+ off_t
+ next_offset() const;
+
+ // Return the symbol index of the next reloc. This returns -1U if
+ // there is no next reloc.
+ unsigned int
+ next_symndx() const;
+
+ // Return the addend of the next reloc. This returns 0 if there is
+ // no next reloc.
+ uint64_t
+ next_addend() const;
+
+ // Advance to OFFSET within the data section, and return the number
+ // of relocs which would be skipped.
+ int
+ advance(off_t offset);
+
+ // Checkpoint the current position in the reloc section.
+ section_size_type
+ checkpoint() const
+ { return this->pos_; }
+
+ // Reset the position to CHECKPOINT.
+ void
+ reset(section_size_type checkpoint)
+ { this->pos_ = checkpoint; }
+
+ private:
+ // The contents of the input object's reloc section.
+ const unsigned char* prelocs_;
+ // The length of the reloc section.
+ section_size_type len_;
+ // Our current position in the reloc section.
+ section_size_type pos_;
+ // The size of the relocs in the section.
+ int reloc_size_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_RELOC_H)
diff --git a/binutils-2.25/gold/resolve.cc b/binutils-2.25/gold/resolve.cc
new file mode 100644
index 00000000..3b6e7069
--- /dev/null
+++ b/binutils-2.25/gold/resolve.cc
@@ -0,0 +1,1085 @@
+// resolve.cc -- symbol resolution for gold
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 "elfcpp.h"
+#include "target.h"
+#include "object.h"
+#include "symtab.h"
+#include "plugin.h"
+
+namespace gold
+{
+
+// Symbol methods used in this file.
+
+// This symbol is being overridden by another symbol whose version is
+// VERSION. Update the VERSION_ field accordingly.
+
+inline void
+Symbol::override_version(const char* version)
+{
+ if (version == NULL)
+ {
+ // This is the case where this symbol is NAME/VERSION, and the
+ // version was not marked as hidden. That makes it the default
+ // version, so we create NAME/NULL. Later we see another symbol
+ // NAME/NULL, and that symbol is overriding this one. In this
+ // case, since NAME/VERSION is the default, we make NAME/NULL
+ // override NAME/VERSION as well. They are already the same
+ // Symbol structure. Setting the VERSION_ field to NULL ensures
+ // that it will be output with the correct, empty, version.
+ this->version_ = version;
+ }
+ else
+ {
+ // This is the case where this symbol is NAME/VERSION_ONE, and
+ // now we see NAME/VERSION_TWO, and NAME/VERSION_TWO is
+ // overriding NAME. If VERSION_ONE and VERSION_TWO are
+ // different, then this can only happen when VERSION_ONE is NULL
+ // and VERSION_TWO is not hidden.
+ gold_assert(this->version_ == version || this->version_ == NULL);
+ this->version_ = version;
+ }
+}
+
+// This symbol is being overidden by another symbol whose visibility
+// is VISIBILITY. Updated the VISIBILITY_ field accordingly.
+
+inline void
+Symbol::override_visibility(elfcpp::STV visibility)
+{
+ // The rule for combining visibility is that we always choose the
+ // most constrained visibility. In order of increasing constraint,
+ // visibility goes PROTECTED, HIDDEN, INTERNAL. This is the reverse
+ // of the numeric values, so the effect is that we always want the
+ // smallest non-zero value.
+ if (visibility != elfcpp::STV_DEFAULT)
+ {
+ if (this->visibility_ == elfcpp::STV_DEFAULT)
+ this->visibility_ = visibility;
+ else if (this->visibility_ > visibility)
+ this->visibility_ = visibility;
+ }
+}
+
+// Override the fields in Symbol.
+
+template<int size, bool big_endian>
+void
+Symbol::override_base(const elfcpp::Sym<size, big_endian>& sym,
+ unsigned int st_shndx, bool is_ordinary,
+ Object* object, const char* version)
+{
+ gold_assert(this->source_ == FROM_OBJECT);
+ this->u_.from_object.object = object;
+ this->override_version(version);
+ this->u_.from_object.shndx = st_shndx;
+ this->is_ordinary_shndx_ = is_ordinary;
+ // Don't override st_type from plugin placeholder symbols.
+ if (object->pluginobj() == NULL)
+ this->type_ = sym.get_st_type();
+ this->binding_ = sym.get_st_bind();
+ this->override_visibility(sym.get_st_visibility());
+ this->nonvis_ = sym.get_st_nonvis();
+ if (object->is_dynamic())
+ this->in_dyn_ = true;
+ else
+ this->in_reg_ = true;
+}
+
+// Override the fields in Sized_symbol.
+
+template<int size>
+template<bool big_endian>
+void
+Sized_symbol<size>::override(const elfcpp::Sym<size, big_endian>& sym,
+ unsigned st_shndx, bool is_ordinary,
+ Object* object, const char* version)
+{
+ this->override_base(sym, st_shndx, is_ordinary, object, version);
+ this->value_ = sym.get_st_value();
+ this->symsize_ = sym.get_st_size();
+}
+
+// Override TOSYM with symbol FROMSYM, defined in OBJECT, with version
+// VERSION. This handles all aliases of TOSYM.
+
+template<int size, bool big_endian>
+void
+Symbol_table::override(Sized_symbol<size>* tosym,
+ const elfcpp::Sym<size, big_endian>& fromsym,
+ unsigned int st_shndx, bool is_ordinary,
+ Object* object, const char* version)
+{
+ tosym->override(fromsym, st_shndx, is_ordinary, object, version);
+ if (tosym->has_alias())
+ {
+ Symbol* sym = this->weak_aliases_[tosym];
+ gold_assert(sym != NULL);
+ Sized_symbol<size>* ssym = this->get_sized_symbol<size>(sym);
+ do
+ {
+ ssym->override(fromsym, st_shndx, is_ordinary, object, version);
+ sym = this->weak_aliases_[ssym];
+ gold_assert(sym != NULL);
+ ssym = this->get_sized_symbol<size>(sym);
+ }
+ while (ssym != tosym);
+ }
+}
+
+// The resolve functions build a little code for each symbol.
+// Bit 0: 0 for global, 1 for weak.
+// Bit 1: 0 for regular object, 1 for shared object
+// Bits 2-3: 0 for normal, 1 for undefined, 2 for common
+// This gives us values from 0 to 11.
+
+static const int global_or_weak_shift = 0;
+static const unsigned int global_flag = 0 << global_or_weak_shift;
+static const unsigned int weak_flag = 1 << global_or_weak_shift;
+
+static const int regular_or_dynamic_shift = 1;
+static const unsigned int regular_flag = 0 << regular_or_dynamic_shift;
+static const unsigned int dynamic_flag = 1 << regular_or_dynamic_shift;
+
+static const int def_undef_or_common_shift = 2;
+static const unsigned int def_flag = 0 << def_undef_or_common_shift;
+static const unsigned int undef_flag = 1 << def_undef_or_common_shift;
+static const unsigned int common_flag = 2 << def_undef_or_common_shift;
+
+// This convenience function combines all the flags based on facts
+// about the symbol.
+
+static unsigned int
+symbol_to_bits(elfcpp::STB binding, bool is_dynamic,
+ unsigned int shndx, bool is_ordinary, elfcpp::STT type)
+{
+ unsigned int bits;
+
+ switch (binding)
+ {
+ case elfcpp::STB_GLOBAL:
+ case elfcpp::STB_GNU_UNIQUE:
+ bits = global_flag;
+ break;
+
+ case elfcpp::STB_WEAK:
+ bits = weak_flag;
+ break;
+
+ case elfcpp::STB_LOCAL:
+ // We should only see externally visible symbols in the symbol
+ // table.
+ gold_error(_("invalid STB_LOCAL symbol in external symbols"));
+ bits = global_flag;
+
+ default:
+ // Any target which wants to handle STB_LOOS, etc., needs to
+ // define a resolve method.
+ gold_error(_("unsupported symbol binding %d"), static_cast<int>(binding));
+ bits = global_flag;
+ }
+
+ if (is_dynamic)
+ bits |= dynamic_flag;
+ else
+ bits |= regular_flag;
+
+ switch (shndx)
+ {
+ case elfcpp::SHN_UNDEF:
+ bits |= undef_flag;
+ break;
+
+ case elfcpp::SHN_COMMON:
+ if (!is_ordinary)
+ bits |= common_flag;
+ break;
+
+ default:
+ if (type == elfcpp::STT_COMMON)
+ bits |= common_flag;
+ else if (!is_ordinary && Symbol::is_common_shndx(shndx))
+ bits |= common_flag;
+ else
+ bits |= def_flag;
+ break;
+ }
+
+ return bits;
+}
+
+// Resolve a symbol. This is called the second and subsequent times
+// we see a symbol. TO is the pre-existing symbol. ST_SHNDX is the
+// section index for SYM, possibly adjusted for many sections.
+// IS_ORDINARY is whether ST_SHNDX is a normal section index rather
+// than a special code. ORIG_ST_SHNDX is the original section index,
+// before any munging because of discarded sections, except that all
+// non-ordinary section indexes are mapped to SHN_UNDEF. VERSION is
+// the version of SYM.
+
+template<int size, bool big_endian>
+void
+Symbol_table::resolve(Sized_symbol<size>* to,
+ const elfcpp::Sym<size, big_endian>& sym,
+ unsigned int st_shndx, bool is_ordinary,
+ unsigned int orig_st_shndx,
+ Object* object, const char* version)
+{
+ // It's possible for a symbol to be defined in an object file
+ // using .symver to give it a version, and for there to also be
+ // a linker script giving that symbol the same version. We
+ // don't want to give a multiple-definition error for this
+ // harmless redefinition.
+ bool to_is_ordinary;
+ if (to->source() == Symbol::FROM_OBJECT
+ && to->object() == object
+ && is_ordinary
+ && to->is_defined()
+ && to->shndx(&to_is_ordinary) == st_shndx
+ && to_is_ordinary
+ && to->value() == sym.get_st_value())
+ return;
+
+ if (parameters->target().has_resolve())
+ {
+ Sized_target<size, big_endian>* sized_target;
+ sized_target = parameters->sized_target<size, big_endian>();
+ sized_target->resolve(to, sym, object, version);
+ return;
+ }
+
+ if (!object->is_dynamic())
+ {
+ // Record that we've seen this symbol in a regular object.
+ to->set_in_reg();
+ }
+ else if (st_shndx == elfcpp::SHN_UNDEF
+ && (to->visibility() == elfcpp::STV_HIDDEN
+ || to->visibility() == elfcpp::STV_INTERNAL))
+ {
+ // A dynamic object cannot reference a hidden or internal symbol
+ // defined in another object.
+ gold_warning(_("%s symbol '%s' in %s is referenced by DSO %s"),
+ (to->visibility() == elfcpp::STV_HIDDEN
+ ? "hidden"
+ : "internal"),
+ to->demangled_name().c_str(),
+ to->object()->name().c_str(),
+ object->name().c_str());
+ return;
+ }
+ else
+ {
+ // Record that we've seen this symbol in a dynamic object.
+ to->set_in_dyn();
+ }
+
+ // Record if we've seen this symbol in a real ELF object (i.e., the
+ // symbol is referenced from outside the world known to the plugin).
+ if (object->pluginobj() == NULL && !object->is_dynamic())
+ to->set_in_real_elf();
+
+ // If we're processing replacement files, allow new symbols to override
+ // the placeholders from the plugin objects.
+ if (to->source() == Symbol::FROM_OBJECT)
+ {
+ Pluginobj* obj = to->object()->pluginobj();
+ if (obj != NULL
+ && parameters->options().plugins()->in_replacement_phase())
+ {
+ this->override(to, sym, st_shndx, is_ordinary, object, version);
+ return;
+ }
+ }
+
+ // A new weak undefined reference, merging with an old weak
+ // reference, could be a One Definition Rule (ODR) violation --
+ // especially if the types or sizes of the references differ. We'll
+ // store such pairs and look them up later to make sure they
+ // actually refer to the same lines of code. We also check
+ // combinations of weak and strong, which might occur if one case is
+ // inline and the other is not. (Note: not all ODR violations can
+ // be found this way, and not everything this finds is an ODR
+ // violation. But it's helpful to warn about.)
+ if (parameters->options().detect_odr_violations()
+ && (sym.get_st_bind() == elfcpp::STB_WEAK
+ || to->binding() == elfcpp::STB_WEAK)
+ && orig_st_shndx != elfcpp::SHN_UNDEF
+ && to->shndx(&to_is_ordinary) != elfcpp::SHN_UNDEF
+ && to_is_ordinary
+ && sym.get_st_size() != 0 // Ignore weird 0-sized symbols.
+ && to->symsize() != 0
+ && (sym.get_st_type() != to->type()
+ || sym.get_st_size() != to->symsize())
+ // C does not have a concept of ODR, so we only need to do this
+ // on C++ symbols. These have (mangled) names starting with _Z.
+ && to->name()[0] == '_' && to->name()[1] == 'Z')
+ {
+ Symbol_location fromloc
+ = { object, orig_st_shndx, static_cast<off_t>(sym.get_st_value()) };
+ Symbol_location toloc = { to->object(), to->shndx(&to_is_ordinary),
+ static_cast<off_t>(to->value()) };
+ this->candidate_odr_violations_[to->name()].insert(fromloc);
+ this->candidate_odr_violations_[to->name()].insert(toloc);
+ }
+
+ // Plugins don't provide a symbol type, so adopt the existing type
+ // if the FROM symbol is from a plugin.
+ elfcpp::STT fromtype = (object->pluginobj() != NULL
+ ? to->type()
+ : sym.get_st_type());
+ unsigned int frombits = symbol_to_bits(sym.get_st_bind(),
+ object->is_dynamic(),
+ st_shndx, is_ordinary,
+ fromtype);
+
+ bool adjust_common_sizes;
+ bool adjust_dyndef;
+ typename Sized_symbol<size>::Size_type tosize = to->symsize();
+ if (Symbol_table::should_override(to, frombits, fromtype, OBJECT,
+ object, &adjust_common_sizes,
+ &adjust_dyndef))
+ {
+ elfcpp::STB tobinding = to->binding();
+ typename Sized_symbol<size>::Value_type tovalue = to->value();
+ this->override(to, sym, st_shndx, is_ordinary, object, version);
+ if (adjust_common_sizes)
+ {
+ if (tosize > to->symsize())
+ to->set_symsize(tosize);
+ if (tovalue > to->value())
+ to->set_value(tovalue);
+ }
+ if (adjust_dyndef)
+ {
+ // We are overriding an UNDEF or WEAK UNDEF with a DYN DEF.
+ // Remember which kind of UNDEF it was for future reference.
+ to->set_undef_binding(tobinding);
+ }
+ }
+ else
+ {
+ if (adjust_common_sizes)
+ {
+ if (sym.get_st_size() > tosize)
+ to->set_symsize(sym.get_st_size());
+ if (sym.get_st_value() > to->value())
+ to->set_value(sym.get_st_value());
+ }
+ if (adjust_dyndef)
+ {
+ // We are keeping a DYN DEF after seeing an UNDEF or WEAK UNDEF.
+ // Remember which kind of UNDEF it was.
+ to->set_undef_binding(sym.get_st_bind());
+ }
+ // The ELF ABI says that even for a reference to a symbol we
+ // merge the visibility.
+ to->override_visibility(sym.get_st_visibility());
+ }
+
+ if (adjust_common_sizes && parameters->options().warn_common())
+ {
+ if (tosize > sym.get_st_size())
+ Symbol_table::report_resolve_problem(false,
+ _("common of '%s' overriding "
+ "smaller common"),
+ to, OBJECT, object);
+ else if (tosize < sym.get_st_size())
+ Symbol_table::report_resolve_problem(false,
+ _("common of '%s' overidden by "
+ "larger common"),
+ to, OBJECT, object);
+ else
+ Symbol_table::report_resolve_problem(false,
+ _("multiple common of '%s'"),
+ to, OBJECT, object);
+ }
+}
+
+// Handle the core of symbol resolution. This is called with the
+// existing symbol, TO, and a bitflag describing the new symbol. This
+// returns true if we should override the existing symbol with the new
+// one, and returns false otherwise. It sets *ADJUST_COMMON_SIZES to
+// true if we should set the symbol size to the maximum of the TO and
+// FROM sizes. It handles error conditions.
+
+bool
+Symbol_table::should_override(const Symbol* to, unsigned int frombits,
+ elfcpp::STT fromtype, Defined defined,
+ Object* object, bool* adjust_common_sizes,
+ bool* adjust_dyndef)
+{
+ *adjust_common_sizes = false;
+ *adjust_dyndef = false;
+
+ unsigned int tobits;
+ if (to->source() == Symbol::IS_UNDEFINED)
+ tobits = symbol_to_bits(to->binding(), false, elfcpp::SHN_UNDEF, true,
+ to->type());
+ else if (to->source() != Symbol::FROM_OBJECT)
+ tobits = symbol_to_bits(to->binding(), false, elfcpp::SHN_ABS, false,
+ to->type());
+ else
+ {
+ bool is_ordinary;
+ unsigned int shndx = to->shndx(&is_ordinary);
+ tobits = symbol_to_bits(to->binding(),
+ to->object()->is_dynamic(),
+ shndx,
+ is_ordinary,
+ to->type());
+ }
+
+ if ((to->type() == elfcpp::STT_TLS) ^ (fromtype == elfcpp::STT_TLS)
+ && !to->is_placeholder())
+ Symbol_table::report_resolve_problem(true,
+ _("symbol '%s' used as both __thread "
+ "and non-__thread"),
+ to, defined, object);
+
+ // We use a giant switch table for symbol resolution. This code is
+ // unwieldy, but: 1) it is efficient; 2) we definitely handle all
+ // cases; 3) it is easy to change the handling of a particular case.
+ // The alternative would be a series of conditionals, but it is easy
+ // to get the ordering wrong. This could also be done as a table,
+ // but that is no easier to understand than this large switch
+ // statement.
+
+ // These are the values generated by the bit codes.
+ enum
+ {
+ DEF = global_flag | regular_flag | def_flag,
+ WEAK_DEF = weak_flag | regular_flag | def_flag,
+ DYN_DEF = global_flag | dynamic_flag | def_flag,
+ DYN_WEAK_DEF = weak_flag | dynamic_flag | def_flag,
+ UNDEF = global_flag | regular_flag | undef_flag,
+ WEAK_UNDEF = weak_flag | regular_flag | undef_flag,
+ DYN_UNDEF = global_flag | dynamic_flag | undef_flag,
+ DYN_WEAK_UNDEF = weak_flag | dynamic_flag | undef_flag,
+ COMMON = global_flag | regular_flag | common_flag,
+ WEAK_COMMON = weak_flag | regular_flag | common_flag,
+ DYN_COMMON = global_flag | dynamic_flag | common_flag,
+ DYN_WEAK_COMMON = weak_flag | dynamic_flag | common_flag
+ };
+
+ switch (tobits * 16 + frombits)
+ {
+ case DEF * 16 + DEF:
+ // Two definitions of the same symbol.
+
+ // If either symbol is defined by an object included using
+ // --just-symbols, then don't warn. This is for compatibility
+ // with the GNU linker. FIXME: This is a hack.
+ if ((to->source() == Symbol::FROM_OBJECT && to->object()->just_symbols())
+ || (object != NULL && object->just_symbols()))
+ return false;
+
+ if (!parameters->options().muldefs())
+ Symbol_table::report_resolve_problem(true,
+ _("multiple definition of '%s'"),
+ to, defined, object);
+ return false;
+
+ case WEAK_DEF * 16 + DEF:
+ // We've seen a weak definition, and now we see a strong
+ // definition. In the original SVR4 linker, this was treated as
+ // a multiple definition error. In the Solaris linker and the
+ // GNU linker, a weak definition followed by a regular
+ // definition causes the weak definition to be overridden. We
+ // are currently compatible with the GNU linker. In the future
+ // we should add a target specific option to change this.
+ // FIXME.
+ return true;
+
+ case DYN_DEF * 16 + DEF:
+ case DYN_WEAK_DEF * 16 + DEF:
+ // We've seen a definition in a dynamic object, and now we see a
+ // definition in a regular object. The definition in the
+ // regular object overrides the definition in the dynamic
+ // object.
+ return true;
+
+ case UNDEF * 16 + DEF:
+ case WEAK_UNDEF * 16 + DEF:
+ case DYN_UNDEF * 16 + DEF:
+ case DYN_WEAK_UNDEF * 16 + DEF:
+ // We've seen an undefined reference, and now we see a
+ // definition. We use the definition.
+ return true;
+
+ case COMMON * 16 + DEF:
+ case WEAK_COMMON * 16 + DEF:
+ case DYN_COMMON * 16 + DEF:
+ case DYN_WEAK_COMMON * 16 + DEF:
+ // We've seen a common symbol and now we see a definition. The
+ // definition overrides.
+ if (parameters->options().warn_common())
+ Symbol_table::report_resolve_problem(false,
+ _("definition of '%s' overriding "
+ "common"),
+ to, defined, object);
+ return true;
+
+ case DEF * 16 + WEAK_DEF:
+ case WEAK_DEF * 16 + WEAK_DEF:
+ // We've seen a definition and now we see a weak definition. We
+ // ignore the new weak definition.
+ return false;
+
+ case DYN_DEF * 16 + WEAK_DEF:
+ case DYN_WEAK_DEF * 16 + WEAK_DEF:
+ // We've seen a dynamic definition and now we see a regular weak
+ // definition. The regular weak definition overrides.
+ return true;
+
+ case UNDEF * 16 + WEAK_DEF:
+ case WEAK_UNDEF * 16 + WEAK_DEF:
+ case DYN_UNDEF * 16 + WEAK_DEF:
+ case DYN_WEAK_UNDEF * 16 + WEAK_DEF:
+ // A weak definition of a currently undefined symbol.
+ return true;
+
+ case COMMON * 16 + WEAK_DEF:
+ case WEAK_COMMON * 16 + WEAK_DEF:
+ // A weak definition does not override a common definition.
+ return false;
+
+ case DYN_COMMON * 16 + WEAK_DEF:
+ case DYN_WEAK_COMMON * 16 + WEAK_DEF:
+ // A weak definition does override a definition in a dynamic
+ // object.
+ if (parameters->options().warn_common())
+ Symbol_table::report_resolve_problem(false,
+ _("definition of '%s' overriding "
+ "dynamic common definition"),
+ to, defined, object);
+ return true;
+
+ case DEF * 16 + DYN_DEF:
+ case WEAK_DEF * 16 + DYN_DEF:
+ case DYN_DEF * 16 + DYN_DEF:
+ case DYN_WEAK_DEF * 16 + DYN_DEF:
+ // Ignore a dynamic definition if we already have a definition.
+ return false;
+
+ case UNDEF * 16 + DYN_DEF:
+ case DYN_UNDEF * 16 + DYN_DEF:
+ case DYN_WEAK_UNDEF * 16 + DYN_DEF:
+ // Use a dynamic definition if we have a reference.
+ return true;
+
+ case WEAK_UNDEF * 16 + DYN_DEF:
+ // When overriding a weak undef by a dynamic definition,
+ // we need to remember that the original undef was weak.
+ *adjust_dyndef = true;
+ return true;
+
+ case COMMON * 16 + DYN_DEF:
+ case WEAK_COMMON * 16 + DYN_DEF:
+ case DYN_COMMON * 16 + DYN_DEF:
+ case DYN_WEAK_COMMON * 16 + DYN_DEF:
+ // Ignore a dynamic definition if we already have a common
+ // definition.
+ return false;
+
+ case DEF * 16 + DYN_WEAK_DEF:
+ case WEAK_DEF * 16 + DYN_WEAK_DEF:
+ case DYN_DEF * 16 + DYN_WEAK_DEF:
+ case DYN_WEAK_DEF * 16 + DYN_WEAK_DEF:
+ // Ignore a weak dynamic definition if we already have a
+ // definition.
+ return false;
+
+ case UNDEF * 16 + DYN_WEAK_DEF:
+ // When overriding an undef by a dynamic weak definition,
+ // we need to remember that the original undef was not weak.
+ *adjust_dyndef = true;
+ return true;
+
+ case DYN_UNDEF * 16 + DYN_WEAK_DEF:
+ case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF:
+ // Use a weak dynamic definition if we have a reference.
+ return true;
+
+ case WEAK_UNDEF * 16 + DYN_WEAK_DEF:
+ // When overriding a weak undef by a dynamic definition,
+ // we need to remember that the original undef was weak.
+ *adjust_dyndef = true;
+ return true;
+
+ case COMMON * 16 + DYN_WEAK_DEF:
+ case WEAK_COMMON * 16 + DYN_WEAK_DEF:
+ case DYN_COMMON * 16 + DYN_WEAK_DEF:
+ case DYN_WEAK_COMMON * 16 + DYN_WEAK_DEF:
+ // Ignore a weak dynamic definition if we already have a common
+ // definition.
+ return false;
+
+ case DEF * 16 + UNDEF:
+ case WEAK_DEF * 16 + UNDEF:
+ case UNDEF * 16 + UNDEF:
+ // A new undefined reference tells us nothing.
+ return false;
+
+ case DYN_DEF * 16 + UNDEF:
+ case DYN_WEAK_DEF * 16 + UNDEF:
+ // For a dynamic def, we need to remember which kind of undef we see.
+ *adjust_dyndef = true;
+ return false;
+
+ case WEAK_UNDEF * 16 + UNDEF:
+ case DYN_UNDEF * 16 + UNDEF:
+ case DYN_WEAK_UNDEF * 16 + UNDEF:
+ // A strong undef overrides a dynamic or weak undef.
+ return true;
+
+ case COMMON * 16 + UNDEF:
+ case WEAK_COMMON * 16 + UNDEF:
+ case DYN_COMMON * 16 + UNDEF:
+ case DYN_WEAK_COMMON * 16 + UNDEF:
+ // A new undefined reference tells us nothing.
+ return false;
+
+ case DEF * 16 + WEAK_UNDEF:
+ case WEAK_DEF * 16 + WEAK_UNDEF:
+ case UNDEF * 16 + WEAK_UNDEF:
+ case WEAK_UNDEF * 16 + WEAK_UNDEF:
+ case DYN_UNDEF * 16 + WEAK_UNDEF:
+ case COMMON * 16 + WEAK_UNDEF:
+ case WEAK_COMMON * 16 + WEAK_UNDEF:
+ case DYN_COMMON * 16 + WEAK_UNDEF:
+ case DYN_WEAK_COMMON * 16 + WEAK_UNDEF:
+ // A new weak undefined reference tells us nothing unless the
+ // exisiting symbol is a dynamic weak reference.
+ return false;
+
+ case DYN_WEAK_UNDEF * 16 + WEAK_UNDEF:
+ // A new weak reference overrides an existing dynamic weak reference.
+ // This is necessary because a dynamic weak reference remembers
+ // the old binding, which may not be weak. If we keeps the existing
+ // dynamic weak reference, the weakness may be dropped in the output.
+ return true;
+
+ case DYN_DEF * 16 + WEAK_UNDEF:
+ case DYN_WEAK_DEF * 16 + WEAK_UNDEF:
+ // For a dynamic def, we need to remember which kind of undef we see.
+ *adjust_dyndef = true;
+ return false;
+
+ case DEF * 16 + DYN_UNDEF:
+ case WEAK_DEF * 16 + DYN_UNDEF:
+ case DYN_DEF * 16 + DYN_UNDEF:
+ case DYN_WEAK_DEF * 16 + DYN_UNDEF:
+ case UNDEF * 16 + DYN_UNDEF:
+ case WEAK_UNDEF * 16 + DYN_UNDEF:
+ case DYN_UNDEF * 16 + DYN_UNDEF:
+ case DYN_WEAK_UNDEF * 16 + DYN_UNDEF:
+ case COMMON * 16 + DYN_UNDEF:
+ case WEAK_COMMON * 16 + DYN_UNDEF:
+ case DYN_COMMON * 16 + DYN_UNDEF:
+ case DYN_WEAK_COMMON * 16 + DYN_UNDEF:
+ // A new dynamic undefined reference tells us nothing.
+ return false;
+
+ case DEF * 16 + DYN_WEAK_UNDEF:
+ case WEAK_DEF * 16 + DYN_WEAK_UNDEF:
+ case DYN_DEF * 16 + DYN_WEAK_UNDEF:
+ case DYN_WEAK_DEF * 16 + DYN_WEAK_UNDEF:
+ case UNDEF * 16 + DYN_WEAK_UNDEF:
+ case WEAK_UNDEF * 16 + DYN_WEAK_UNDEF:
+ case DYN_UNDEF * 16 + DYN_WEAK_UNDEF:
+ case DYN_WEAK_UNDEF * 16 + DYN_WEAK_UNDEF:
+ case COMMON * 16 + DYN_WEAK_UNDEF:
+ case WEAK_COMMON * 16 + DYN_WEAK_UNDEF:
+ case DYN_COMMON * 16 + DYN_WEAK_UNDEF:
+ case DYN_WEAK_COMMON * 16 + DYN_WEAK_UNDEF:
+ // A new weak dynamic undefined reference tells us nothing.
+ return false;
+
+ case DEF * 16 + COMMON:
+ // A common symbol does not override a definition.
+ if (parameters->options().warn_common())
+ Symbol_table::report_resolve_problem(false,
+ _("common '%s' overridden by "
+ "previous definition"),
+ to, defined, object);
+ return false;
+
+ case WEAK_DEF * 16 + COMMON:
+ case DYN_DEF * 16 + COMMON:
+ case DYN_WEAK_DEF * 16 + COMMON:
+ // A common symbol does override a weak definition or a dynamic
+ // definition.
+ return true;
+
+ case UNDEF * 16 + COMMON:
+ case WEAK_UNDEF * 16 + COMMON:
+ case DYN_UNDEF * 16 + COMMON:
+ case DYN_WEAK_UNDEF * 16 + COMMON:
+ // A common symbol is a definition for a reference.
+ return true;
+
+ case COMMON * 16 + COMMON:
+ // Set the size to the maximum.
+ *adjust_common_sizes = true;
+ return false;
+
+ case WEAK_COMMON * 16 + COMMON:
+ // I'm not sure just what a weak common symbol means, but
+ // presumably it can be overridden by a regular common symbol.
+ return true;
+
+ case DYN_COMMON * 16 + COMMON:
+ case DYN_WEAK_COMMON * 16 + COMMON:
+ // Use the real common symbol, but adjust the size if necessary.
+ *adjust_common_sizes = true;
+ return true;
+
+ case DEF * 16 + WEAK_COMMON:
+ case WEAK_DEF * 16 + WEAK_COMMON:
+ case DYN_DEF * 16 + WEAK_COMMON:
+ case DYN_WEAK_DEF * 16 + WEAK_COMMON:
+ // Whatever a weak common symbol is, it won't override a
+ // definition.
+ return false;
+
+ case UNDEF * 16 + WEAK_COMMON:
+ case WEAK_UNDEF * 16 + WEAK_COMMON:
+ case DYN_UNDEF * 16 + WEAK_COMMON:
+ case DYN_WEAK_UNDEF * 16 + WEAK_COMMON:
+ // A weak common symbol is better than an undefined symbol.
+ return true;
+
+ case COMMON * 16 + WEAK_COMMON:
+ case WEAK_COMMON * 16 + WEAK_COMMON:
+ case DYN_COMMON * 16 + WEAK_COMMON:
+ case DYN_WEAK_COMMON * 16 + WEAK_COMMON:
+ // Ignore a weak common symbol in the presence of a real common
+ // symbol.
+ return false;
+
+ case DEF * 16 + DYN_COMMON:
+ case WEAK_DEF * 16 + DYN_COMMON:
+ case DYN_DEF * 16 + DYN_COMMON:
+ case DYN_WEAK_DEF * 16 + DYN_COMMON:
+ // Ignore a dynamic common symbol in the presence of a
+ // definition.
+ return false;
+
+ case UNDEF * 16 + DYN_COMMON:
+ case WEAK_UNDEF * 16 + DYN_COMMON:
+ case DYN_UNDEF * 16 + DYN_COMMON:
+ case DYN_WEAK_UNDEF * 16 + DYN_COMMON:
+ // A dynamic common symbol is a definition of sorts.
+ return true;
+
+ case COMMON * 16 + DYN_COMMON:
+ case WEAK_COMMON * 16 + DYN_COMMON:
+ case DYN_COMMON * 16 + DYN_COMMON:
+ case DYN_WEAK_COMMON * 16 + DYN_COMMON:
+ // Set the size to the maximum.
+ *adjust_common_sizes = true;
+ return false;
+
+ case DEF * 16 + DYN_WEAK_COMMON:
+ case WEAK_DEF * 16 + DYN_WEAK_COMMON:
+ case DYN_DEF * 16 + DYN_WEAK_COMMON:
+ case DYN_WEAK_DEF * 16 + DYN_WEAK_COMMON:
+ // A common symbol is ignored in the face of a definition.
+ return false;
+
+ case UNDEF * 16 + DYN_WEAK_COMMON:
+ case WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
+ case DYN_UNDEF * 16 + DYN_WEAK_COMMON:
+ case DYN_WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
+ // I guess a weak common symbol is better than a definition.
+ return true;
+
+ case COMMON * 16 + DYN_WEAK_COMMON:
+ case WEAK_COMMON * 16 + DYN_WEAK_COMMON:
+ case DYN_COMMON * 16 + DYN_WEAK_COMMON:
+ case DYN_WEAK_COMMON * 16 + DYN_WEAK_COMMON:
+ // Set the size to the maximum.
+ *adjust_common_sizes = true;
+ return false;
+
+ default:
+ gold_unreachable();
+ }
+}
+
+// Issue an error or warning due to symbol resolution. IS_ERROR
+// indicates an error rather than a warning. MSG is the error
+// message; it is expected to have a %s for the symbol name. TO is
+// the existing symbol. DEFINED/OBJECT is where the new symbol was
+// found.
+
+// FIXME: We should have better location information here. When the
+// symbol is defined, we should be able to pull the location from the
+// debug info if there is any.
+
+void
+Symbol_table::report_resolve_problem(bool is_error, const char* msg,
+ const Symbol* to, Defined defined,
+ Object* object)
+{
+ std::string demangled(to->demangled_name());
+ size_t len = strlen(msg) + demangled.length() + 10;
+ char* buf = new char[len];
+ snprintf(buf, len, msg, demangled.c_str());
+
+ const char* objname;
+ switch (defined)
+ {
+ case OBJECT:
+ objname = object->name().c_str();
+ break;
+ case COPY:
+ objname = _("COPY reloc");
+ break;
+ case DEFSYM:
+ case UNDEFINED:
+ objname = _("command line");
+ break;
+ case SCRIPT:
+ objname = _("linker script");
+ break;
+ case PREDEFINED:
+ case INCREMENTAL_BASE:
+ objname = _("linker defined");
+ break;
+ default:
+ gold_unreachable();
+ }
+
+ if (is_error)
+ gold_error("%s: %s", objname, buf);
+ else
+ gold_warning("%s: %s", objname, buf);
+
+ delete[] buf;
+
+ if (to->source() == Symbol::FROM_OBJECT)
+ objname = to->object()->name().c_str();
+ else
+ objname = _("command line");
+ gold_info("%s: %s: previous definition here", program_name, objname);
+}
+
+// A special case of should_override which is only called for a strong
+// defined symbol from a regular object file. This is used when
+// defining special symbols.
+
+bool
+Symbol_table::should_override_with_special(const Symbol* to,
+ elfcpp::STT fromtype,
+ Defined defined)
+{
+ bool adjust_common_sizes;
+ bool adjust_dyn_def;
+ unsigned int frombits = global_flag | regular_flag | def_flag;
+ bool ret = Symbol_table::should_override(to, frombits, fromtype, defined,
+ NULL, &adjust_common_sizes,
+ &adjust_dyn_def);
+ gold_assert(!adjust_common_sizes && !adjust_dyn_def);
+ return ret;
+}
+
+// Override symbol base with a special symbol.
+
+void
+Symbol::override_base_with_special(const Symbol* from)
+{
+ bool same_name = this->name_ == from->name_;
+ gold_assert(same_name || this->has_alias());
+
+ this->source_ = from->source_;
+ switch (from->source_)
+ {
+ case FROM_OBJECT:
+ this->u_.from_object = from->u_.from_object;
+ break;
+ case IN_OUTPUT_DATA:
+ this->u_.in_output_data = from->u_.in_output_data;
+ break;
+ case IN_OUTPUT_SEGMENT:
+ this->u_.in_output_segment = from->u_.in_output_segment;
+ break;
+ case IS_CONSTANT:
+ case IS_UNDEFINED:
+ break;
+ default:
+ gold_unreachable();
+ break;
+ }
+
+ if (same_name)
+ {
+ // When overriding a versioned symbol with a special symbol, we
+ // may be changing the version. This will happen if we see a
+ // special symbol such as "_end" defined in a shared object with
+ // one version (from a version script), but we want to define it
+ // here with a different version (from a different version
+ // script).
+ this->version_ = from->version_;
+ }
+ this->type_ = from->type_;
+ this->binding_ = from->binding_;
+ this->override_visibility(from->visibility_);
+ this->nonvis_ = from->nonvis_;
+
+ // Special symbols are always considered to be regular symbols.
+ this->in_reg_ = true;
+
+ if (from->needs_dynsym_entry_)
+ this->needs_dynsym_entry_ = true;
+ if (from->needs_dynsym_value_)
+ this->needs_dynsym_value_ = true;
+
+ this->is_predefined_ = from->is_predefined_;
+
+ // We shouldn't see these flags. If we do, we need to handle them
+ // somehow.
+ gold_assert(!from->is_forwarder_);
+ gold_assert(!from->has_plt_offset());
+ gold_assert(!from->has_warning_);
+ gold_assert(!from->is_copied_from_dynobj_);
+ gold_assert(!from->is_forced_local_);
+}
+
+// Override a symbol with a special symbol.
+
+template<int size>
+void
+Sized_symbol<size>::override_with_special(const Sized_symbol<size>* from)
+{
+ this->override_base_with_special(from);
+ this->value_ = from->value_;
+ this->symsize_ = from->symsize_;
+}
+
+// Override TOSYM with the special symbol FROMSYM. This handles all
+// aliases of TOSYM.
+
+template<int size>
+void
+Symbol_table::override_with_special(Sized_symbol<size>* tosym,
+ const Sized_symbol<size>* fromsym)
+{
+ tosym->override_with_special(fromsym);
+ if (tosym->has_alias())
+ {
+ Symbol* sym = this->weak_aliases_[tosym];
+ gold_assert(sym != NULL);
+ Sized_symbol<size>* ssym = this->get_sized_symbol<size>(sym);
+ do
+ {
+ ssym->override_with_special(fromsym);
+ sym = this->weak_aliases_[ssym];
+ gold_assert(sym != NULL);
+ ssym = this->get_sized_symbol<size>(sym);
+ }
+ while (ssym != tosym);
+ }
+ if (tosym->binding() == elfcpp::STB_LOCAL
+ || ((tosym->visibility() == elfcpp::STV_HIDDEN
+ || tosym->visibility() == elfcpp::STV_INTERNAL)
+ && (tosym->binding() == elfcpp::STB_GLOBAL
+ || tosym->binding() == elfcpp::STB_GNU_UNIQUE
+ || tosym->binding() == elfcpp::STB_WEAK)
+ && !parameters->options().relocatable()))
+ this->force_local(tosym);
+}
+
+// Instantiate the templates we need. We could use the configure
+// script to restrict this to only the ones needed for implemented
+// targets.
+
+// We have to instantiate both big and little endian versions because
+// these are used by other templates that depends on size only.
+
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+template
+void
+Symbol_table::resolve<32, false>(
+ Sized_symbol<32>* to,
+ const elfcpp::Sym<32, false>& sym,
+ unsigned int st_shndx,
+ bool is_ordinary,
+ unsigned int orig_st_shndx,
+ Object* object,
+ const char* version);
+
+template
+void
+Symbol_table::resolve<32, true>(
+ Sized_symbol<32>* to,
+ const elfcpp::Sym<32, true>& sym,
+ unsigned int st_shndx,
+ bool is_ordinary,
+ unsigned int orig_st_shndx,
+ Object* object,
+ const char* version);
+#endif
+
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+template
+void
+Symbol_table::resolve<64, false>(
+ Sized_symbol<64>* to,
+ const elfcpp::Sym<64, false>& sym,
+ unsigned int st_shndx,
+ bool is_ordinary,
+ unsigned int orig_st_shndx,
+ Object* object,
+ const char* version);
+
+template
+void
+Symbol_table::resolve<64, true>(
+ Sized_symbol<64>* to,
+ const elfcpp::Sym<64, true>& sym,
+ unsigned int st_shndx,
+ bool is_ordinary,
+ unsigned int orig_st_shndx,
+ Object* object,
+ const char* version);
+#endif
+
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+template
+void
+Symbol_table::override_with_special<32>(Sized_symbol<32>*,
+ const Sized_symbol<32>*);
+#endif
+
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+template
+void
+Symbol_table::override_with_special<64>(Sized_symbol<64>*,
+ const Sized_symbol<64>*);
+#endif
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/script-c.h b/binutils-2.25/gold/script-c.h
new file mode 100644
index 00000000..28079503
--- /dev/null
+++ b/binutils-2.25/gold/script-c.h
@@ -0,0 +1,566 @@
+/* script-c.h -- C interface for linker scripts in gold. */
+
+/* Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>.
+
+ 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 exists so that both the bison parser and script.cc can
+ include it, so that they can communicate back and forth. */
+
+#ifndef GOLD_SCRIPT_C_H
+#define GOLD_SCRIPT_C_H
+
+#ifdef __cplusplus
+#include <vector>
+#include <string>
+#endif
+
+#ifdef __cplusplus
+
+// For the C++ code we declare the various supporting structures in
+// the gold namespace. For the C code we declare it at the top level.
+// The namespace level should not affect the layout of the structure.
+
+namespace gold
+{
+#endif
+
+/* A string value for the bison parser. */
+
+struct Parser_string
+{
+ const char* value;
+ size_t length;
+};
+
+/* The expression functions deal with pointers to Expression objects.
+ Since the bison parser generates C code, this is a hack to keep the
+ C++ code type safe. This hacks assumes that all pointers look
+ alike. */
+
+#ifdef __cplusplus
+class Expression;
+typedef Expression* Expression_ptr;
+#else
+typedef void* Expression_ptr;
+#endif
+
+/* Script_section type. */
+enum Script_section_type
+{
+ /* No section type. */
+ SCRIPT_SECTION_TYPE_NONE,
+ SCRIPT_SECTION_TYPE_NOLOAD,
+ SCRIPT_SECTION_TYPE_DSECT,
+ SCRIPT_SECTION_TYPE_COPY,
+ SCRIPT_SECTION_TYPE_INFO,
+ SCRIPT_SECTION_TYPE_OVERLAY
+};
+
+/* A constraint for whether to use a particular output section
+ definition. */
+
+enum Section_constraint
+{
+ /* No constraint. */
+ CONSTRAINT_NONE,
+ /* Only if all input sections are read-only. */
+ CONSTRAINT_ONLY_IF_RO,
+ /* Only if at least input section is writable. */
+ CONSTRAINT_ONLY_IF_RW,
+ /* Special constraint. */
+ CONSTRAINT_SPECIAL
+};
+
+/* The information we store for an output section header in the bison
+ parser. */
+
+struct Parser_output_section_header
+{
+ /* The address. This may be NULL. */
+ Expression_ptr address;
+ /* Section type. May be NULL string. */
+ enum Script_section_type section_type;
+ /* The load address, from the AT specifier. This may be NULL. */
+ Expression_ptr load_address;
+ /* The alignment, from the ALIGN specifier. This may be NULL. */
+ Expression_ptr align;
+ /* The input section alignment, from the SUBALIGN specifier. This
+ may be NULL. */
+ Expression_ptr subalign;
+ /* A constraint on this output section. */
+ enum Section_constraint constraint;
+};
+
+/* We keep vectors of strings. In order to manage this in both C and
+ C++, we use a pointer to a vector. This assumes that all pointers
+ look the same. */
+
+#ifdef __cplusplus
+typedef std::vector<std::string> String_list;
+typedef String_list* String_list_ptr;
+#else
+typedef void* String_list_ptr;
+#endif
+
+/* The information we store for an output section trailer in the bison
+ parser. */
+
+struct Parser_output_section_trailer
+{
+ /* The fill value. This may be NULL. */
+ Expression_ptr fill;
+ /* The program segments this section should go into. This may be
+ NULL. */
+ String_list_ptr phdrs;
+};
+
+/* The different sorts we can find in a linker script. */
+
+enum Sort_wildcard
+{
+ SORT_WILDCARD_NONE,
+ SORT_WILDCARD_BY_NAME,
+ SORT_WILDCARD_BY_ALIGNMENT,
+ SORT_WILDCARD_BY_NAME_BY_ALIGNMENT,
+ SORT_WILDCARD_BY_ALIGNMENT_BY_NAME
+};
+
+/* The information we build for a single wildcard specification. */
+
+struct Wildcard_section
+{
+ /* The wildcard spec itself. */
+ struct Parser_string name;
+ /* How the entries should be sorted. */
+ enum Sort_wildcard sort;
+};
+
+/* A vector of Wildcard_section entries. */
+
+#ifdef __cplusplus
+typedef std::vector<Wildcard_section> String_sort_list;
+typedef String_sort_list* String_sort_list_ptr;
+#else
+typedef void* String_sort_list_ptr;
+#endif
+
+/* A list of wildcard specifications, which may include EXCLUDE_FILE
+ clauses. */
+
+struct Wildcard_sections
+{
+ /* Wildcard specs. */
+ String_sort_list_ptr sections;
+ /* Exclusions. */
+ String_list_ptr exclude;
+};
+
+/* A complete input section specification. */
+
+struct Input_section_spec
+{
+ /* The file name. */
+ struct Wildcard_section file;
+ /* The list of sections. */
+ struct Wildcard_sections input_sections;
+};
+
+/* Information for a program header. */
+
+struct Phdr_info
+{
+ /* A boolean value: whether to include the file header. */
+ int includes_filehdr;
+ /* A boolean value: whether to include the program headers. */
+ int includes_phdrs;
+ /* A boolean value: whether the flags field is valid. */
+ int is_flags_valid;
+ /* The value to use for the flags. */
+ unsigned int flags;
+ /* The load address. */
+ Expression_ptr load_address;
+};
+
+struct Version_dependency_list;
+struct Version_expression_list;
+struct Version_tree;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The bison parser definitions. */
+
+#include "yyscript.h"
+
+/* The bison parser function. */
+
+extern int
+yyparse(void* closure);
+
+/* Called by the bison parser skeleton to return the next token. */
+
+extern int
+yylex(YYSTYPE*, void* closure);
+
+/* Called by the bison parser skeleton to report an error. */
+
+extern void
+yyerror(void* closure, const char*);
+
+/* Called by the bison parser to add an external symbol (a symbol in
+ an EXTERN declaration) to the link. */
+
+extern void
+script_add_extern(void* closure, const char*, size_t);
+
+/* Called by the bison parser to add a file to the link. */
+
+extern void
+script_add_file(void* closure, const char*, size_t);
+
+/* Called by the bison parser to add a library to the link. */
+
+extern void
+script_add_library(void* closure, const char*, size_t);
+
+/* Called by the bison parser to start and stop a group. */
+
+extern void
+script_start_group(void* closure);
+extern void
+script_end_group(void* closure);
+
+/* Called by the bison parser to start and end an AS_NEEDED list. */
+
+extern void
+script_start_as_needed(void* closure);
+extern void
+script_end_as_needed(void* closure);
+
+/* Called by the bison parser to set the entry symbol. */
+
+extern void
+script_set_entry(void* closure, const char*, size_t);
+
+/* Called by the bison parser to set whether to define common symbols. */
+
+extern void
+script_set_common_allocation(void* closure, int);
+
+/* Called by the bison parser to parse an OPTION. */
+
+extern void
+script_parse_option(void* closure, const char*, size_t);
+
+/* Called by the bison parser to handle OUTPUT_FORMAT. This return 0
+ if the parse should be aborted. */
+
+extern int
+script_check_output_format(void* closure, const char*, size_t,
+ const char*, size_t, const char*, size_t);
+
+/* Called by the bison parser to handle TARGET. */
+extern void
+script_set_target(void* closure, const char*, size_t);
+
+/* Called by the bison parser to handle SEARCH_DIR. */
+
+extern void
+script_add_search_dir(void* closure, const char*, size_t);
+
+/* Called by the bison parser to push the lexer into expression
+ mode. */
+
+extern void
+script_push_lex_into_expression_mode(void* closure);
+
+/* Called by the bison parser to push the lexer into version
+ mode. */
+
+extern void
+script_push_lex_into_version_mode(void* closure);
+
+/* Called by the bison parser to pop the lexer mode. */
+
+extern void
+script_pop_lex_mode(void* closure);
+
+/* Called by the bison parser to get the value of a symbol. This is
+ called for a reference to a symbol, but is not called for something
+ like "sym += 10". Uses of the special symbol "." can just call
+ script_exp_string. */
+
+extern Expression_ptr
+script_symbol(void* closure, const char*, size_t);
+
+/* Called by the bison parser to set a symbol to a value. PROVIDE is
+ non-zero if the symbol should be provided--only defined if there is
+ an undefined reference. HIDDEN is non-zero if the symbol should be
+ hidden. */
+
+extern void
+script_set_symbol(void* closure, const char*, size_t, Expression_ptr,
+ int provide, int hidden);
+
+/* Called by the bison parser to add an assertion. */
+
+extern void
+script_add_assertion(void* closure, Expression_ptr, const char* message,
+ size_t messagelen);
+
+/* Called by the bison parser to start a SECTIONS clause. */
+
+extern void
+script_start_sections(void* closure);
+
+/* Called by the bison parser to finish a SECTIONS clause. */
+
+extern void
+script_finish_sections(void* closure);
+
+/* Called by the bison parser to start handling input section
+ specifications for an output section. */
+
+extern void
+script_start_output_section(void* closure, const char* name, size_t namelen,
+ const struct Parser_output_section_header*);
+
+/* Called by the bison parser when done handling input section
+ specifications for an output section. */
+
+extern void
+script_finish_output_section(void* closure,
+ const struct Parser_output_section_trailer*);
+
+/* Called by the bison parser to handle a data statement (LONG, BYTE,
+ etc.) in an output section. */
+
+extern void
+script_add_data(void* closure, int data_token, Expression_ptr val);
+
+/* Called by the bison parser to set the fill value in an output
+ section. */
+
+extern void
+script_add_fill(void* closure, Expression_ptr val);
+
+/* Called by the bison parser to add an input section specification to
+ an output section. The KEEP parameter is non-zero if this is
+ within a KEEP clause, meaning that the garbage collector should not
+ discard it. */
+
+extern void
+script_add_input_section(void* closure, const struct Input_section_spec*,
+ int keep);
+
+/* Create a new list of string and sort entries. */
+
+extern String_sort_list_ptr
+script_new_string_sort_list(const struct Wildcard_section*);
+
+/* Add an entry to a list of string and sort entries. */
+
+extern String_sort_list_ptr
+script_string_sort_list_add(String_sort_list_ptr,
+ const struct Wildcard_section*);
+
+/* Create a new list of strings. */
+
+extern String_list_ptr
+script_new_string_list(const char*, size_t);
+
+/* Add an element to a list of strings. */
+
+extern String_list_ptr
+script_string_list_push_back(String_list_ptr, const char*, size_t);
+
+/* Concatenate two string lists. */
+
+extern String_list_ptr
+script_string_list_append(String_list_ptr, String_list_ptr);
+
+/* Define a new program header. */
+
+extern void
+script_add_phdr(void* closure, const char* name, size_t namelen,
+ unsigned int type, const struct Phdr_info*);
+
+/* Convert a program header string to a type. */
+
+extern unsigned int
+script_phdr_string_to_type(void* closure, const char*, size_t);
+
+/* Handle DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END. */
+
+extern void
+script_data_segment_align(void* closure);
+
+extern void
+script_data_segment_relro_end(void* closure);
+
+/* Record the fact that a SEGMENT_START expression is seen. */
+
+extern void
+script_saw_segment_start_expression(void* closure);
+
+/* Called by the bison parser for MEMORY regions. */
+
+extern void
+script_add_memory(void*, const char*, size_t, unsigned int,
+ Expression_ptr, Expression_ptr);
+
+extern unsigned int
+script_parse_memory_attr(void*, const char*, size_t, int);
+
+extern void
+script_set_section_region(void*, const char*, size_t, int);
+
+extern void
+script_include_directive(void *, const char*, size_t);
+
+/* Called by the bison parser for expressions. */
+
+extern Expression_ptr
+script_exp_unary_minus(Expression_ptr);
+extern Expression_ptr
+script_exp_unary_logical_not(Expression_ptr);
+extern Expression_ptr
+script_exp_unary_bitwise_not(Expression_ptr);
+extern Expression_ptr
+script_exp_binary_mult(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_div(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_mod(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_add(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_sub(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_lshift(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_rshift(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_eq(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_ne(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_le(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_ge(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_lt(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_gt(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_bitwise_and(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_bitwise_xor(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_bitwise_or(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_logical_and(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_binary_logical_or(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_trinary_cond(Expression_ptr, Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_integer(uint64_t);
+extern Expression_ptr
+script_exp_string(const char*, size_t);
+extern Expression_ptr
+script_exp_function_max(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_function_min(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_function_defined(const char*, size_t);
+extern Expression_ptr
+script_exp_function_sizeof_headers(void);
+extern Expression_ptr
+script_exp_function_alignof(const char*, size_t);
+extern Expression_ptr
+script_exp_function_sizeof(const char*, size_t);
+extern Expression_ptr
+script_exp_function_addr(const char*, size_t);
+extern Expression_ptr
+script_exp_function_loadaddr(const char*, size_t);
+extern Expression_ptr
+script_exp_function_origin(void*, const char*, size_t);
+extern Expression_ptr
+script_exp_function_length(void*, const char*, size_t);
+extern Expression_ptr
+script_exp_function_constant(const char*, size_t);
+extern Expression_ptr
+script_exp_function_absolute(Expression_ptr);
+extern Expression_ptr
+script_exp_function_align(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_function_data_segment_align(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_function_data_segment_relro_end(Expression_ptr, Expression_ptr);
+extern Expression_ptr
+script_exp_function_data_segment_end(Expression_ptr);
+extern Expression_ptr
+script_exp_function_segment_start(const char*, size_t, Expression_ptr);
+extern Expression_ptr
+script_exp_function_assert(Expression_ptr, const char*, size_t);
+
+extern void
+script_register_vers_node(void* closure,
+ const char* tag,
+ int taglen,
+ struct Version_tree*,
+ struct Version_dependency_list*);
+
+extern struct Version_dependency_list*
+script_add_vers_depend(void* closure,
+ struct Version_dependency_list* existing_dependencies,
+ const char* depend_to_add, int deplen);
+
+extern struct Version_expression_list*
+script_new_vers_pattern(void* closure,
+ struct Version_expression_list*,
+ const char*, int, int);
+
+extern struct Version_expression_list*
+script_merge_expressions(struct Version_expression_list* a,
+ struct Version_expression_list* b);
+
+extern struct Version_tree*
+script_new_vers_node(void* closure,
+ struct Version_expression_list* global,
+ struct Version_expression_list* local);
+
+extern void
+version_script_push_lang(void* closure, const char* lang, int langlen);
+
+extern void
+version_script_pop_lang(void* closure);
+
+#ifdef __cplusplus
+} // End extern "C"
+#endif
+
+#ifdef __cplusplus
+} // End namespace gold.
+#endif
+
+#endif /* !defined(GOLD_SCRIPT_C_H) */
diff --git a/binutils-2.25/gold/script-sections.cc b/binutils-2.25/gold/script-sections.cc
new file mode 100644
index 00000000..a57e53ff
--- /dev/null
+++ b/binutils-2.25/gold/script-sections.cc
@@ -0,0 +1,4372 @@
+// script-sections.cc -- linker script SECTIONS for gold
+
+// Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cstring>
+#include <algorithm>
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+#include <fnmatch.h>
+
+#include "parameters.h"
+#include "object.h"
+#include "layout.h"
+#include "output.h"
+#include "script-c.h"
+#include "script.h"
+#include "script-sections.h"
+
+// Support for the SECTIONS clause in linker scripts.
+
+namespace gold
+{
+
+// A region of memory.
+class Memory_region
+{
+ public:
+ Memory_region(const char* name, size_t namelen, unsigned int attributes,
+ Expression* start, Expression* length)
+ : name_(name, namelen),
+ attributes_(attributes),
+ start_(start),
+ length_(length),
+ current_offset_(0),
+ vma_sections_(),
+ lma_sections_(),
+ last_section_(NULL)
+ { }
+
+ // Return the name of this region.
+ const std::string&
+ name() const
+ { return this->name_; }
+
+ // Return the start address of this region.
+ Expression*
+ start_address() const
+ { return this->start_; }
+
+ // Return the length of this region.
+ Expression*
+ length() const
+ { return this->length_; }
+
+ // Print the region (when debugging).
+ void
+ print(FILE*) const;
+
+ // Return true if <name,namelen> matches this region.
+ bool
+ name_match(const char* name, size_t namelen)
+ {
+ return (this->name_.length() == namelen
+ && strncmp(this->name_.c_str(), name, namelen) == 0);
+ }
+
+ Expression*
+ get_current_address() const
+ {
+ return
+ script_exp_binary_add(this->start_,
+ script_exp_integer(this->current_offset_));
+ }
+
+ void
+ increment_offset(std::string section_name, uint64_t amount,
+ const Symbol_table* symtab, const Layout* layout)
+ {
+ this->current_offset_ += amount;
+
+ if (this->current_offset_
+ > this->length_->eval(symtab, layout, false))
+ gold_error(_("section %s overflows end of region %s"),
+ section_name.c_str(), this->name_.c_str());
+ }
+
+ // Returns true iff there is room left in this region
+ // for AMOUNT more bytes of data.
+ bool
+ has_room_for(const Symbol_table* symtab, const Layout* layout,
+ uint64_t amount) const
+ {
+ return (this->current_offset_ + amount
+ < this->length_->eval(symtab, layout, false));
+ }
+
+ // Return true if the provided section flags
+ // are compatible with this region's attributes.
+ bool
+ attributes_compatible(elfcpp::Elf_Xword flags, elfcpp::Elf_Xword type) const;
+
+ void
+ add_section(Output_section_definition* sec, bool vma)
+ {
+ if (vma)
+ this->vma_sections_.push_back(sec);
+ else
+ this->lma_sections_.push_back(sec);
+ }
+
+ typedef std::vector<Output_section_definition*> Section_list;
+
+ // Return the start of the list of sections
+ // whose VMAs are taken from this region.
+ Section_list::const_iterator
+ get_vma_section_list_start() const
+ { return this->vma_sections_.begin(); }
+
+ // Return the start of the list of sections
+ // whose LMAs are taken from this region.
+ Section_list::const_iterator
+ get_lma_section_list_start() const
+ { return this->lma_sections_.begin(); }
+
+ // Return the end of the list of sections
+ // whose VMAs are taken from this region.
+ Section_list::const_iterator
+ get_vma_section_list_end() const
+ { return this->vma_sections_.end(); }
+
+ // Return the end of the list of sections
+ // whose LMAs are taken from this region.
+ Section_list::const_iterator
+ get_lma_section_list_end() const
+ { return this->lma_sections_.end(); }
+
+ Output_section_definition*
+ get_last_section() const
+ { return this->last_section_; }
+
+ void
+ set_last_section(Output_section_definition* sec)
+ { this->last_section_ = sec; }
+
+ private:
+
+ std::string name_;
+ unsigned int attributes_;
+ Expression* start_;
+ Expression* length_;
+ // The offset to the next free byte in the region.
+ // Note - for compatibility with GNU LD we only maintain one offset
+ // regardless of whether the region is being used for VMA values,
+ // LMA values, or both.
+ uint64_t current_offset_;
+ // A list of sections whose VMAs are set inside this region.
+ Section_list vma_sections_;
+ // A list of sections whose LMAs are set inside this region.
+ Section_list lma_sections_;
+ // The latest section to make use of this region.
+ Output_section_definition* last_section_;
+};
+
+// Return true if the provided section flags
+// are compatible with this region's attributes.
+
+bool
+Memory_region::attributes_compatible(elfcpp::Elf_Xword flags,
+ elfcpp::Elf_Xword type) const
+{
+ unsigned int attrs = this->attributes_;
+
+ // No attributes means that this region is not compatible with anything.
+ if (attrs == 0)
+ return false;
+
+ bool match = true;
+ do
+ {
+ switch (attrs & - attrs)
+ {
+ case MEM_EXECUTABLE:
+ if ((flags & elfcpp::SHF_EXECINSTR) == 0)
+ match = false;
+ break;
+
+ case MEM_WRITEABLE:
+ if ((flags & elfcpp::SHF_WRITE) == 0)
+ match = false;
+ break;
+
+ case MEM_READABLE:
+ // All sections are presumed readable.
+ break;
+
+ case MEM_ALLOCATABLE:
+ if ((flags & elfcpp::SHF_ALLOC) == 0)
+ match = false;
+ break;
+
+ case MEM_INITIALIZED:
+ if ((type & elfcpp::SHT_NOBITS) != 0)
+ match = false;
+ break;
+ }
+ attrs &= ~ (attrs & - attrs);
+ }
+ while (attrs != 0);
+
+ return match;
+}
+
+// Print a memory region.
+
+void
+Memory_region::print(FILE* f) const
+{
+ fprintf(f, " %s", this->name_.c_str());
+
+ unsigned int attrs = this->attributes_;
+ if (attrs != 0)
+ {
+ fprintf(f, " (");
+ do
+ {
+ switch (attrs & - attrs)
+ {
+ case MEM_EXECUTABLE: fputc('x', f); break;
+ case MEM_WRITEABLE: fputc('w', f); break;
+ case MEM_READABLE: fputc('r', f); break;
+ case MEM_ALLOCATABLE: fputc('a', f); break;
+ case MEM_INITIALIZED: fputc('i', f); break;
+ default:
+ gold_unreachable();
+ }
+ attrs &= ~ (attrs & - attrs);
+ }
+ while (attrs != 0);
+ fputc(')', f);
+ }
+
+ fprintf(f, " : origin = ");
+ this->start_->print(f);
+ fprintf(f, ", length = ");
+ this->length_->print(f);
+ fprintf(f, "\n");
+}
+
+// Manage orphan sections. This is intended to be largely compatible
+// with the GNU linker. The Linux kernel implicitly relies on
+// something similar to the GNU linker's orphan placement. We
+// originally used a simpler scheme here, but it caused the kernel
+// build to fail, and was also rather inefficient.
+
+class Orphan_section_placement
+{
+ private:
+ typedef Script_sections::Elements_iterator Elements_iterator;
+
+ public:
+ Orphan_section_placement();
+
+ // Handle an output section during initialization of this mapping.
+ void
+ output_section_init(const std::string& name, Output_section*,
+ Elements_iterator location);
+
+ // Initialize the last location.
+ void
+ last_init(Elements_iterator location);
+
+ // Set *PWHERE to the address of an iterator pointing to the
+ // location to use for an orphan section. Return true if the
+ // iterator has a value, false otherwise.
+ bool
+ find_place(Output_section*, Elements_iterator** pwhere);
+
+ // Return the iterator being used for sections at the very end of
+ // the linker script.
+ Elements_iterator
+ last_place() const;
+
+ private:
+ // The places that we specifically recognize. This list is copied
+ // from the GNU linker.
+ enum Place_index
+ {
+ PLACE_TEXT,
+ PLACE_RODATA,
+ PLACE_DATA,
+ PLACE_TLS,
+ PLACE_TLS_BSS,
+ PLACE_BSS,
+ PLACE_REL,
+ PLACE_INTERP,
+ PLACE_NONALLOC,
+ PLACE_LAST,
+ PLACE_MAX
+ };
+
+ // The information we keep for a specific place.
+ struct Place
+ {
+ // The name of sections for this place.
+ const char* name;
+ // Whether we have a location for this place.
+ bool have_location;
+ // The iterator for this place.
+ Elements_iterator location;
+ };
+
+ // Initialize one place element.
+ void
+ initialize_place(Place_index, const char*);
+
+ // The places.
+ Place places_[PLACE_MAX];
+ // True if this is the first call to output_section_init.
+ bool first_init_;
+};
+
+// Initialize Orphan_section_placement.
+
+Orphan_section_placement::Orphan_section_placement()
+ : first_init_(true)
+{
+ this->initialize_place(PLACE_TEXT, ".text");
+ this->initialize_place(PLACE_RODATA, ".rodata");
+ this->initialize_place(PLACE_DATA, ".data");
+ this->initialize_place(PLACE_TLS, NULL);
+ this->initialize_place(PLACE_TLS_BSS, NULL);
+ this->initialize_place(PLACE_BSS, ".bss");
+ this->initialize_place(PLACE_REL, NULL);
+ this->initialize_place(PLACE_INTERP, ".interp");
+ this->initialize_place(PLACE_NONALLOC, NULL);
+ this->initialize_place(PLACE_LAST, NULL);
+}
+
+// Initialize one place element.
+
+void
+Orphan_section_placement::initialize_place(Place_index index, const char* name)
+{
+ this->places_[index].name = name;
+ this->places_[index].have_location = false;
+}
+
+// While initializing the Orphan_section_placement information, this
+// is called once for each output section named in the linker script.
+// If we found an output section during the link, it will be passed in
+// OS.
+
+void
+Orphan_section_placement::output_section_init(const std::string& name,
+ Output_section* os,
+ Elements_iterator location)
+{
+ bool first_init = this->first_init_;
+ this->first_init_ = false;
+
+ for (int i = 0; i < PLACE_MAX; ++i)
+ {
+ if (this->places_[i].name != NULL && this->places_[i].name == name)
+ {
+ if (this->places_[i].have_location)
+ {
+ // We have already seen a section with this name.
+ return;
+ }
+
+ this->places_[i].location = location;
+ this->places_[i].have_location = true;
+
+ // If we just found the .bss section, restart the search for
+ // an unallocated section. This follows the GNU linker's
+ // behaviour.
+ if (i == PLACE_BSS)
+ this->places_[PLACE_NONALLOC].have_location = false;
+
+ return;
+ }
+ }
+
+ // Relocation sections.
+ if (!this->places_[PLACE_REL].have_location
+ && os != NULL
+ && (os->type() == elfcpp::SHT_REL || os->type() == elfcpp::SHT_RELA)
+ && (os->flags() & elfcpp::SHF_ALLOC) != 0)
+ {
+ this->places_[PLACE_REL].location = location;
+ this->places_[PLACE_REL].have_location = true;
+ }
+
+ // We find the location for unallocated sections by finding the
+ // first debugging or comment section after the BSS section (if
+ // there is one).
+ if (!this->places_[PLACE_NONALLOC].have_location
+ && (name == ".comment" || Layout::is_debug_info_section(name.c_str())))
+ {
+ // We add orphan sections after the location in PLACES_. We
+ // want to store unallocated sections before LOCATION. If this
+ // is the very first section, we can't use it.
+ if (!first_init)
+ {
+ --location;
+ this->places_[PLACE_NONALLOC].location = location;
+ this->places_[PLACE_NONALLOC].have_location = true;
+ }
+ }
+}
+
+// Initialize the last location.
+
+void
+Orphan_section_placement::last_init(Elements_iterator location)
+{
+ this->places_[PLACE_LAST].location = location;
+ this->places_[PLACE_LAST].have_location = true;
+}
+
+// Set *PWHERE to the address of an iterator pointing to the location
+// to use for an orphan section. Return true if the iterator has a
+// value, false otherwise.
+
+bool
+Orphan_section_placement::find_place(Output_section* os,
+ Elements_iterator** pwhere)
+{
+ // Figure out where OS should go. This is based on the GNU linker
+ // code. FIXME: The GNU linker handles small data sections
+ // specially, but we don't.
+ elfcpp::Elf_Word type = os->type();
+ elfcpp::Elf_Xword flags = os->flags();
+ Place_index index;
+ if ((flags & elfcpp::SHF_ALLOC) == 0
+ && !Layout::is_debug_info_section(os->name()))
+ index = PLACE_NONALLOC;
+ else if ((flags & elfcpp::SHF_ALLOC) == 0)
+ index = PLACE_LAST;
+ else if (type == elfcpp::SHT_NOTE)
+ index = PLACE_INTERP;
+ else if ((flags & elfcpp::SHF_TLS) != 0)
+ {
+ if (type == elfcpp::SHT_NOBITS)
+ index = PLACE_TLS_BSS;
+ else
+ index = PLACE_TLS;
+ }
+ else if (type == elfcpp::SHT_NOBITS)
+ index = PLACE_BSS;
+ else if ((flags & elfcpp::SHF_WRITE) != 0)
+ index = PLACE_DATA;
+ else if (type == elfcpp::SHT_REL || type == elfcpp::SHT_RELA)
+ index = PLACE_REL;
+ else if ((flags & elfcpp::SHF_EXECINSTR) == 0)
+ index = PLACE_RODATA;
+ else
+ index = PLACE_TEXT;
+
+ // If we don't have a location yet, try to find one based on a
+ // plausible ordering of sections.
+ if (!this->places_[index].have_location)
+ {
+ Place_index follow;
+ switch (index)
+ {
+ default:
+ follow = PLACE_MAX;
+ break;
+ case PLACE_RODATA:
+ follow = PLACE_TEXT;
+ break;
+ case PLACE_BSS:
+ follow = PLACE_DATA;
+ break;
+ case PLACE_REL:
+ follow = PLACE_TEXT;
+ break;
+ case PLACE_INTERP:
+ follow = PLACE_TEXT;
+ break;
+ case PLACE_TLS:
+ follow = PLACE_DATA;
+ break;
+ case PLACE_TLS_BSS:
+ follow = PLACE_TLS;
+ if (!this->places_[PLACE_TLS].have_location)
+ follow = PLACE_DATA;
+ break;
+ }
+ if (follow != PLACE_MAX && this->places_[follow].have_location)
+ {
+ // Set the location of INDEX to the location of FOLLOW. The
+ // location of INDEX will then be incremented by the caller,
+ // so anything in INDEX will continue to be after anything
+ // in FOLLOW.
+ this->places_[index].location = this->places_[follow].location;
+ this->places_[index].have_location = true;
+ }
+ }
+
+ *pwhere = &this->places_[index].location;
+ bool ret = this->places_[index].have_location;
+
+ // The caller will set the location.
+ this->places_[index].have_location = true;
+
+ return ret;
+}
+
+// Return the iterator being used for sections at the very end of the
+// linker script.
+
+Orphan_section_placement::Elements_iterator
+Orphan_section_placement::last_place() const
+{
+ gold_assert(this->places_[PLACE_LAST].have_location);
+ return this->places_[PLACE_LAST].location;
+}
+
+// An element in a SECTIONS clause.
+
+class Sections_element
+{
+ public:
+ Sections_element()
+ { }
+
+ virtual ~Sections_element()
+ { }
+
+ // Return whether an output section is relro.
+ virtual bool
+ is_relro() const
+ { return false; }
+
+ // Record that an output section is relro.
+ virtual void
+ set_is_relro()
+ { }
+
+ // Create any required output sections. The only real
+ // implementation is in Output_section_definition.
+ virtual void
+ create_sections(Layout*)
+ { }
+
+ // Add any symbol being defined to the symbol table.
+ virtual void
+ add_symbols_to_table(Symbol_table*)
+ { }
+
+ // Finalize symbols and check assertions.
+ virtual void
+ finalize_symbols(Symbol_table*, const Layout*, uint64_t*)
+ { }
+
+ // Return the output section name to use for an input file name and
+ // section name. This only real implementation is in
+ // Output_section_definition.
+ virtual const char*
+ output_section_name(const char*, const char*, Output_section***,
+ Script_sections::Section_type*, bool*)
+ { return NULL; }
+
+ // Initialize OSP with an output section.
+ virtual void
+ orphan_section_init(Orphan_section_placement*,
+ Script_sections::Elements_iterator)
+ { }
+
+ // Set section addresses. This includes applying assignments if the
+ // expression is an absolute value.
+ virtual void
+ set_section_addresses(Symbol_table*, Layout*, uint64_t*, uint64_t*,
+ uint64_t*)
+ { }
+
+ // Check a constraint (ONLY_IF_RO, etc.) on an output section. If
+ // this section is constrained, and the input sections do not match,
+ // return the constraint, and set *POSD.
+ virtual Section_constraint
+ check_constraint(Output_section_definition**)
+ { return CONSTRAINT_NONE; }
+
+ // See if this is the alternate output section for a constrained
+ // output section. If it is, transfer the Output_section and return
+ // true. Otherwise return false.
+ virtual bool
+ alternate_constraint(Output_section_definition*, Section_constraint)
+ { return false; }
+
+ // Get the list of segments to use for an allocated section when
+ // using a PHDRS clause. If this is an allocated section, return
+ // the Output_section, and set *PHDRS_LIST (the first parameter) to
+ // the list of PHDRS to which it should be attached. If the PHDRS
+ // were not specified, don't change *PHDRS_LIST. When not returning
+ // NULL, set *ORPHAN (the second parameter) according to whether
+ // this is an orphan section--one that is not mentioned in the
+ // linker script.
+ virtual Output_section*
+ allocate_to_segment(String_list**, bool*)
+ { return NULL; }
+
+ // Look for an output section by name and return the address, the
+ // load address, the alignment, and the size. This is used when an
+ // expression refers to an output section which was not actually
+ // created. This returns true if the section was found, false
+ // otherwise. The only real definition is for
+ // Output_section_definition.
+ virtual bool
+ get_output_section_info(const char*, uint64_t*, uint64_t*, uint64_t*,
+ uint64_t*) const
+ { return false; }
+
+ // Return the associated Output_section if there is one.
+ virtual Output_section*
+ get_output_section() const
+ { return NULL; }
+
+ // Set the section's memory regions.
+ virtual void
+ set_memory_region(Memory_region*, bool)
+ { gold_error(_("Attempt to set a memory region for a non-output section")); }
+
+ // Print the element for debugging purposes.
+ virtual void
+ print(FILE* f) const = 0;
+};
+
+// An assignment in a SECTIONS clause outside of an output section.
+
+class Sections_element_assignment : public Sections_element
+{
+ public:
+ Sections_element_assignment(const char* name, size_t namelen,
+ Expression* val, bool provide, bool hidden)
+ : assignment_(name, namelen, false, val, provide, hidden)
+ { }
+
+ // Add the symbol to the symbol table.
+ void
+ add_symbols_to_table(Symbol_table* symtab)
+ { this->assignment_.add_to_table(symtab); }
+
+ // Finalize the symbol.
+ void
+ finalize_symbols(Symbol_table* symtab, const Layout* layout,
+ uint64_t* dot_value)
+ {
+ this->assignment_.finalize_with_dot(symtab, layout, *dot_value, NULL);
+ }
+
+ // Set the section address. There is no section here, but if the
+ // value is absolute, we set the symbol. This permits us to use
+ // absolute symbols when setting dot.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout,
+ uint64_t* dot_value, uint64_t*, uint64_t*)
+ {
+ this->assignment_.set_if_absolute(symtab, layout, true, *dot_value, NULL);
+ }
+
+ // Print for debugging.
+ void
+ print(FILE* f) const
+ {
+ fprintf(f, " ");
+ this->assignment_.print(f);
+ }
+
+ private:
+ Symbol_assignment assignment_;
+};
+
+// An assignment to the dot symbol in a SECTIONS clause outside of an
+// output section.
+
+class Sections_element_dot_assignment : public Sections_element
+{
+ public:
+ Sections_element_dot_assignment(Expression* val)
+ : val_(val)
+ { }
+
+ // Finalize the symbol.
+ void
+ finalize_symbols(Symbol_table* symtab, const Layout* layout,
+ uint64_t* dot_value)
+ {
+ // We ignore the section of the result because outside of an
+ // output section definition the dot symbol is always considered
+ // to be absolute.
+ *dot_value = this->val_->eval_with_dot(symtab, layout, true, *dot_value,
+ NULL, NULL, NULL, false);
+ }
+
+ // Update the dot symbol while setting section addresses.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout,
+ uint64_t* dot_value, uint64_t* dot_alignment,
+ uint64_t* load_address)
+ {
+ *dot_value = this->val_->eval_with_dot(symtab, layout, false, *dot_value,
+ NULL, NULL, dot_alignment, false);
+ *load_address = *dot_value;
+ }
+
+ // Print for debugging.
+ void
+ print(FILE* f) const
+ {
+ fprintf(f, " . = ");
+ this->val_->print(f);
+ fprintf(f, "\n");
+ }
+
+ private:
+ Expression* val_;
+};
+
+// An assertion in a SECTIONS clause outside of an output section.
+
+class Sections_element_assertion : public Sections_element
+{
+ public:
+ Sections_element_assertion(Expression* check, const char* message,
+ size_t messagelen)
+ : assertion_(check, message, messagelen)
+ { }
+
+ // Check the assertion.
+ void
+ finalize_symbols(Symbol_table* symtab, const Layout* layout, uint64_t*)
+ { this->assertion_.check(symtab, layout); }
+
+ // Print for debugging.
+ void
+ print(FILE* f) const
+ {
+ fprintf(f, " ");
+ this->assertion_.print(f);
+ }
+
+ private:
+ Script_assertion assertion_;
+};
+
+// An element in an output section in a SECTIONS clause.
+
+class Output_section_element
+{
+ public:
+ // A list of input sections.
+ typedef std::list<Output_section::Input_section> Input_section_list;
+
+ Output_section_element()
+ { }
+
+ virtual ~Output_section_element()
+ { }
+
+ // Return whether this element requires an output section to exist.
+ virtual bool
+ needs_output_section() const
+ { return false; }
+
+ // Add any symbol being defined to the symbol table.
+ virtual void
+ add_symbols_to_table(Symbol_table*)
+ { }
+
+ // Finalize symbols and check assertions.
+ virtual void
+ finalize_symbols(Symbol_table*, const Layout*, uint64_t*, Output_section**)
+ { }
+
+ // Return whether this element matches FILE_NAME and SECTION_NAME.
+ // The only real implementation is in Output_section_element_input.
+ virtual bool
+ match_name(const char*, const char*, bool *) const
+ { return false; }
+
+ // Set section addresses. This includes applying assignments if the
+ // expression is an absolute value.
+ virtual void
+ set_section_addresses(Symbol_table*, Layout*, Output_section*, uint64_t,
+ uint64_t*, uint64_t*, Output_section**, std::string*,
+ Input_section_list*)
+ { }
+
+ // Print the element for debugging purposes.
+ virtual void
+ print(FILE* f) const = 0;
+
+ protected:
+ // Return a fill string that is LENGTH bytes long, filling it with
+ // FILL.
+ std::string
+ get_fill_string(const std::string* fill, section_size_type length) const;
+};
+
+std::string
+Output_section_element::get_fill_string(const std::string* fill,
+ section_size_type length) const
+{
+ std::string this_fill;
+ this_fill.reserve(length);
+ while (this_fill.length() + fill->length() <= length)
+ this_fill += *fill;
+ if (this_fill.length() < length)
+ this_fill.append(*fill, 0, length - this_fill.length());
+ return this_fill;
+}
+
+// A symbol assignment in an output section.
+
+class Output_section_element_assignment : public Output_section_element
+{
+ public:
+ Output_section_element_assignment(const char* name, size_t namelen,
+ Expression* val, bool provide,
+ bool hidden)
+ : assignment_(name, namelen, false, val, provide, hidden)
+ { }
+
+ // Add the symbol to the symbol table.
+ void
+ add_symbols_to_table(Symbol_table* symtab)
+ { this->assignment_.add_to_table(symtab); }
+
+ // Finalize the symbol.
+ void
+ finalize_symbols(Symbol_table* symtab, const Layout* layout,
+ uint64_t* dot_value, Output_section** dot_section)
+ {
+ this->assignment_.finalize_with_dot(symtab, layout, *dot_value,
+ *dot_section);
+ }
+
+ // Set the section address. There is no section here, but if the
+ // value is absolute, we set the symbol. This permits us to use
+ // absolute symbols when setting dot.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*,
+ uint64_t, uint64_t* dot_value, uint64_t*,
+ Output_section** dot_section, std::string*,
+ Input_section_list*)
+ {
+ this->assignment_.set_if_absolute(symtab, layout, true, *dot_value,
+ *dot_section);
+ }
+
+ // Print for debugging.
+ void
+ print(FILE* f) const
+ {
+ fprintf(f, " ");
+ this->assignment_.print(f);
+ }
+
+ private:
+ Symbol_assignment assignment_;
+};
+
+// An assignment to the dot symbol in an output section.
+
+class Output_section_element_dot_assignment : public Output_section_element
+{
+ public:
+ Output_section_element_dot_assignment(Expression* val)
+ : val_(val)
+ { }
+
+ // An assignment to dot within an output section is enough to force
+ // the output section to exist.
+ bool
+ needs_output_section() const
+ { return true; }
+
+ // Finalize the symbol.
+ void
+ finalize_symbols(Symbol_table* symtab, const Layout* layout,
+ uint64_t* dot_value, Output_section** dot_section)
+ {
+ *dot_value = this->val_->eval_with_dot(symtab, layout, true, *dot_value,
+ *dot_section, dot_section, NULL,
+ true);
+ }
+
+ // Update the dot symbol while setting section addresses.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*,
+ uint64_t, uint64_t* dot_value, uint64_t*,
+ Output_section** dot_section, std::string*,
+ Input_section_list*);
+
+ // Print for debugging.
+ void
+ print(FILE* f) const
+ {
+ fprintf(f, " . = ");
+ this->val_->print(f);
+ fprintf(f, "\n");
+ }
+
+ private:
+ Expression* val_;
+};
+
+// Update the dot symbol while setting section addresses.
+
+void
+Output_section_element_dot_assignment::set_section_addresses(
+ Symbol_table* symtab,
+ Layout* layout,
+ Output_section* output_section,
+ uint64_t,
+ uint64_t* dot_value,
+ uint64_t* dot_alignment,
+ Output_section** dot_section,
+ std::string* fill,
+ Input_section_list*)
+{
+ uint64_t next_dot = this->val_->eval_with_dot(symtab, layout, false,
+ *dot_value, *dot_section,
+ dot_section, dot_alignment,
+ true);
+ if (next_dot < *dot_value)
+ gold_error(_("dot may not move backward"));
+ if (next_dot > *dot_value && output_section != NULL)
+ {
+ section_size_type length = convert_to_section_size_type(next_dot
+ - *dot_value);
+ Output_section_data* posd;
+ if (fill->empty())
+ posd = new Output_data_zero_fill(length, 0);
+ else
+ {
+ std::string this_fill = this->get_fill_string(fill, length);
+ posd = new Output_data_const(this_fill, 0);
+ }
+ output_section->add_output_section_data(posd);
+ layout->new_output_section_data_from_script(posd);
+ }
+ *dot_value = next_dot;
+}
+
+// An assertion in an output section.
+
+class Output_section_element_assertion : public Output_section_element
+{
+ public:
+ Output_section_element_assertion(Expression* check, const char* message,
+ size_t messagelen)
+ : assertion_(check, message, messagelen)
+ { }
+
+ void
+ print(FILE* f) const
+ {
+ fprintf(f, " ");
+ this->assertion_.print(f);
+ }
+
+ private:
+ Script_assertion assertion_;
+};
+
+// We use a special instance of Output_section_data to handle BYTE,
+// SHORT, etc. This permits forward references to symbols in the
+// expressions.
+
+class Output_data_expression : public Output_section_data
+{
+ public:
+ Output_data_expression(int size, bool is_signed, Expression* val,
+ const Symbol_table* symtab, const Layout* layout,
+ uint64_t dot_value, Output_section* dot_section)
+ : Output_section_data(size, 0, true),
+ is_signed_(is_signed), val_(val), symtab_(symtab),
+ layout_(layout), dot_value_(dot_value), dot_section_(dot_section)
+ { }
+
+ protected:
+ // Write the data to the output 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, _("** expression")); }
+
+ private:
+ template<bool big_endian>
+ void
+ endian_write_to_buffer(uint64_t, unsigned char*);
+
+ bool is_signed_;
+ Expression* val_;
+ const Symbol_table* symtab_;
+ const Layout* layout_;
+ uint64_t dot_value_;
+ Output_section* dot_section_;
+};
+
+// Write the data element to the output file.
+
+void
+Output_data_expression::do_write(Output_file* of)
+{
+ unsigned char* view = of->get_output_view(this->offset(), this->data_size());
+ this->write_to_buffer(view);
+ of->write_output_view(this->offset(), this->data_size(), view);
+}
+
+// Write the data element to a buffer.
+
+void
+Output_data_expression::do_write_to_buffer(unsigned char* buf)
+{
+ uint64_t val = this->val_->eval_with_dot(this->symtab_, this->layout_,
+ true, this->dot_value_,
+ this->dot_section_, NULL, NULL,
+ false);
+
+ if (parameters->target().is_big_endian())
+ this->endian_write_to_buffer<true>(val, buf);
+ else
+ this->endian_write_to_buffer<false>(val, buf);
+}
+
+template<bool big_endian>
+void
+Output_data_expression::endian_write_to_buffer(uint64_t val,
+ unsigned char* buf)
+{
+ switch (this->data_size())
+ {
+ case 1:
+ elfcpp::Swap_unaligned<8, big_endian>::writeval(buf, val);
+ break;
+ case 2:
+ elfcpp::Swap_unaligned<16, big_endian>::writeval(buf, val);
+ break;
+ case 4:
+ elfcpp::Swap_unaligned<32, big_endian>::writeval(buf, val);
+ break;
+ case 8:
+ if (parameters->target().get_size() == 32)
+ {
+ val &= 0xffffffff;
+ if (this->is_signed_ && (val & 0x80000000) != 0)
+ val |= 0xffffffff00000000LL;
+ }
+ elfcpp::Swap_unaligned<64, big_endian>::writeval(buf, val);
+ break;
+ default:
+ gold_unreachable();
+ }
+}
+
+// A data item in an output section.
+
+class Output_section_element_data : public Output_section_element
+{
+ public:
+ Output_section_element_data(int size, bool is_signed, Expression* val)
+ : size_(size), is_signed_(is_signed), val_(val)
+ { }
+
+ // If there is a data item, then we must create an output section.
+ bool
+ needs_output_section() const
+ { return true; }
+
+ // Finalize symbols--we just need to update dot.
+ void
+ finalize_symbols(Symbol_table*, const Layout*, uint64_t* dot_value,
+ Output_section**)
+ { *dot_value += this->size_; }
+
+ // Store the value in the section.
+ void
+ set_section_addresses(Symbol_table*, Layout*, Output_section*, uint64_t,
+ uint64_t* dot_value, uint64_t*, Output_section**,
+ std::string*, Input_section_list*);
+
+ // Print for debugging.
+ void
+ print(FILE*) const;
+
+ private:
+ // The size in bytes.
+ int size_;
+ // Whether the value is signed.
+ bool is_signed_;
+ // The value.
+ Expression* val_;
+};
+
+// Store the value in the section.
+
+void
+Output_section_element_data::set_section_addresses(
+ Symbol_table* symtab,
+ Layout* layout,
+ Output_section* os,
+ uint64_t,
+ uint64_t* dot_value,
+ uint64_t*,
+ Output_section** dot_section,
+ std::string*,
+ Input_section_list*)
+{
+ gold_assert(os != NULL);
+ Output_data_expression* expression =
+ new Output_data_expression(this->size_, this->is_signed_, this->val_,
+ symtab, layout, *dot_value, *dot_section);
+ os->add_output_section_data(expression);
+ layout->new_output_section_data_from_script(expression);
+ *dot_value += this->size_;
+}
+
+// Print for debugging.
+
+void
+Output_section_element_data::print(FILE* f) const
+{
+ const char* s;
+ switch (this->size_)
+ {
+ case 1:
+ s = "BYTE";
+ break;
+ case 2:
+ s = "SHORT";
+ break;
+ case 4:
+ s = "LONG";
+ break;
+ case 8:
+ if (this->is_signed_)
+ s = "SQUAD";
+ else
+ s = "QUAD";
+ break;
+ default:
+ gold_unreachable();
+ }
+ fprintf(f, " %s(", s);
+ this->val_->print(f);
+ fprintf(f, ")\n");
+}
+
+// A fill value setting in an output section.
+
+class Output_section_element_fill : public Output_section_element
+{
+ public:
+ Output_section_element_fill(Expression* val)
+ : val_(val)
+ { }
+
+ // Update the fill value while setting section addresses.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*,
+ uint64_t, uint64_t* dot_value, uint64_t*,
+ Output_section** dot_section,
+ std::string* fill, Input_section_list*)
+ {
+ Output_section* fill_section;
+ uint64_t fill_val = this->val_->eval_with_dot(symtab, layout, false,
+ *dot_value, *dot_section,
+ &fill_section, NULL, false);
+ if (fill_section != NULL)
+ gold_warning(_("fill value is not absolute"));
+ // FIXME: The GNU linker supports fill values of arbitrary length.
+ unsigned char fill_buff[4];
+ elfcpp::Swap_unaligned<32, true>::writeval(fill_buff, fill_val);
+ fill->assign(reinterpret_cast<char*>(fill_buff), 4);
+ }
+
+ // Print for debugging.
+ void
+ print(FILE* f) const
+ {
+ fprintf(f, " FILL(");
+ this->val_->print(f);
+ fprintf(f, ")\n");
+ }
+
+ private:
+ // The new fill value.
+ Expression* val_;
+};
+
+// An input section specification in an output section
+
+class Output_section_element_input : public Output_section_element
+{
+ public:
+ Output_section_element_input(const Input_section_spec* spec, bool keep);
+
+ // Finalize symbols--just update the value of the dot symbol.
+ void
+ finalize_symbols(Symbol_table*, const Layout*, uint64_t* dot_value,
+ Output_section** dot_section)
+ {
+ *dot_value = this->final_dot_value_;
+ *dot_section = this->final_dot_section_;
+ }
+
+ // See whether we match FILE_NAME and SECTION_NAME as an input section.
+ // If we do then also indicate whether the section should be KEPT.
+ bool
+ match_name(const char* file_name, const char* section_name, bool* keep) const;
+
+ // Set the section address.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*,
+ uint64_t subalign, uint64_t* dot_value, uint64_t*,
+ Output_section**, std::string* fill,
+ Input_section_list*);
+
+ // Print for debugging.
+ void
+ print(FILE* f) const;
+
+ private:
+ // An input section pattern.
+ struct Input_section_pattern
+ {
+ std::string pattern;
+ bool pattern_is_wildcard;
+ Sort_wildcard sort;
+
+ Input_section_pattern(const char* patterna, size_t patternlena,
+ Sort_wildcard sorta)
+ : pattern(patterna, patternlena),
+ pattern_is_wildcard(is_wildcard_string(this->pattern.c_str())),
+ sort(sorta)
+ { }
+ };
+
+ typedef std::vector<Input_section_pattern> Input_section_patterns;
+
+ // Filename_exclusions is a pair of filename pattern and a bool
+ // indicating whether the filename is a wildcard.
+ typedef std::vector<std::pair<std::string, bool> > Filename_exclusions;
+
+ // Return whether STRING matches PATTERN, where IS_WILDCARD_PATTERN
+ // indicates whether this is a wildcard pattern.
+ static inline bool
+ match(const char* string, const char* pattern, bool is_wildcard_pattern)
+ {
+ return (is_wildcard_pattern
+ ? fnmatch(pattern, string, 0) == 0
+ : strcmp(string, pattern) == 0);
+ }
+
+ // See if we match a file name.
+ bool
+ match_file_name(const char* file_name) const;
+
+ // The file name pattern. If this is the empty string, we match all
+ // files.
+ std::string filename_pattern_;
+ // Whether the file name pattern is a wildcard.
+ bool filename_is_wildcard_;
+ // How the file names should be sorted. This may only be
+ // SORT_WILDCARD_NONE or SORT_WILDCARD_BY_NAME.
+ Sort_wildcard filename_sort_;
+ // The list of file names to exclude.
+ Filename_exclusions filename_exclusions_;
+ // The list of input section patterns.
+ Input_section_patterns input_section_patterns_;
+ // Whether to keep this section when garbage collecting.
+ bool keep_;
+ // The value of dot after including all matching sections.
+ uint64_t final_dot_value_;
+ // The section where dot is defined after including all matching
+ // sections.
+ Output_section* final_dot_section_;
+};
+
+// Construct Output_section_element_input. The parser records strings
+// as pointers into a copy of the script file, which will go away when
+// parsing is complete. We make sure they are in std::string objects.
+
+Output_section_element_input::Output_section_element_input(
+ const Input_section_spec* spec,
+ bool keep)
+ : filename_pattern_(),
+ filename_is_wildcard_(false),
+ filename_sort_(spec->file.sort),
+ filename_exclusions_(),
+ input_section_patterns_(),
+ keep_(keep),
+ final_dot_value_(0),
+ final_dot_section_(NULL)
+{
+ // The filename pattern "*" is common, and matches all files. Turn
+ // it into the empty string.
+ if (spec->file.name.length != 1 || spec->file.name.value[0] != '*')
+ this->filename_pattern_.assign(spec->file.name.value,
+ spec->file.name.length);
+ this->filename_is_wildcard_ = is_wildcard_string(this->filename_pattern_.c_str());
+
+ if (spec->input_sections.exclude != NULL)
+ {
+ for (String_list::const_iterator p =
+ spec->input_sections.exclude->begin();
+ p != spec->input_sections.exclude->end();
+ ++p)
+ {
+ bool is_wildcard = is_wildcard_string((*p).c_str());
+ this->filename_exclusions_.push_back(std::make_pair(*p,
+ is_wildcard));
+ }
+ }
+
+ if (spec->input_sections.sections != NULL)
+ {
+ Input_section_patterns& isp(this->input_section_patterns_);
+ for (String_sort_list::const_iterator p =
+ spec->input_sections.sections->begin();
+ p != spec->input_sections.sections->end();
+ ++p)
+ isp.push_back(Input_section_pattern(p->name.value, p->name.length,
+ p->sort));
+ }
+}
+
+// See whether we match FILE_NAME.
+
+bool
+Output_section_element_input::match_file_name(const char* file_name) const
+{
+ if (!this->filename_pattern_.empty())
+ {
+ // If we were called with no filename, we refuse to match a
+ // pattern which requires a file name.
+ if (file_name == NULL)
+ return false;
+
+ if (!match(file_name, this->filename_pattern_.c_str(),
+ this->filename_is_wildcard_))
+ return false;
+ }
+
+ if (file_name != NULL)
+ {
+ // Now we have to see whether FILE_NAME matches one of the
+ // exclusion patterns, if any.
+ for (Filename_exclusions::const_iterator p =
+ this->filename_exclusions_.begin();
+ p != this->filename_exclusions_.end();
+ ++p)
+ {
+ if (match(file_name, p->first.c_str(), p->second))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// See whether we match FILE_NAME and SECTION_NAME. If we do then
+// KEEP indicates whether the section should survive garbage collection.
+
+bool
+Output_section_element_input::match_name(const char* file_name,
+ const char* section_name,
+ bool *keep) const
+{
+ if (!this->match_file_name(file_name))
+ return false;
+
+ *keep = this->keep_;
+
+ // If there are no section name patterns, then we match.
+ if (this->input_section_patterns_.empty())
+ return true;
+
+ // See whether we match the section name patterns.
+ for (Input_section_patterns::const_iterator p =
+ this->input_section_patterns_.begin();
+ p != this->input_section_patterns_.end();
+ ++p)
+ {
+ if (match(section_name, p->pattern.c_str(), p->pattern_is_wildcard))
+ return true;
+ }
+
+ // We didn't match any section names, so we didn't match.
+ return false;
+}
+
+// Information we use to sort the input sections.
+
+class Input_section_info
+{
+ public:
+ Input_section_info(const Output_section::Input_section& input_section)
+ : input_section_(input_section), section_name_(),
+ size_(0), addralign_(1)
+ { }
+
+ // Return the simple input section.
+ const Output_section::Input_section&
+ input_section() const
+ { return this->input_section_; }
+
+ // Return the object.
+ Relobj*
+ relobj() const
+ { return this->input_section_.relobj(); }
+
+ // Return the section index.
+ unsigned int
+ shndx()
+ { return this->input_section_.shndx(); }
+
+ // Return the section name.
+ const std::string&
+ section_name() const
+ { return this->section_name_; }
+
+ // Set the section name.
+ void
+ set_section_name(const std::string name)
+ { this->section_name_ = name; }
+
+ // Return the section size.
+ uint64_t
+ size() const
+ { return this->size_; }
+
+ // Set the section size.
+ void
+ set_size(uint64_t size)
+ { this->size_ = size; }
+
+ // Return the address alignment.
+ uint64_t
+ addralign() const
+ { return this->addralign_; }
+
+ // Set the address alignment.
+ void
+ set_addralign(uint64_t addralign)
+ { this->addralign_ = addralign; }
+
+ private:
+ // Input section, can be a relaxed section.
+ Output_section::Input_section input_section_;
+ // Name of the section.
+ std::string section_name_;
+ // Section size.
+ uint64_t size_;
+ // Address alignment.
+ uint64_t addralign_;
+};
+
+// A class to sort the input sections.
+
+class Input_section_sorter
+{
+ public:
+ Input_section_sorter(Sort_wildcard filename_sort, Sort_wildcard section_sort)
+ : filename_sort_(filename_sort), section_sort_(section_sort)
+ { }
+
+ bool
+ operator()(const Input_section_info&, const Input_section_info&) const;
+
+ private:
+ Sort_wildcard filename_sort_;
+ Sort_wildcard section_sort_;
+};
+
+bool
+Input_section_sorter::operator()(const Input_section_info& isi1,
+ const Input_section_info& isi2) const
+{
+ if (this->section_sort_ == SORT_WILDCARD_BY_NAME
+ || this->section_sort_ == SORT_WILDCARD_BY_NAME_BY_ALIGNMENT
+ || (this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT_BY_NAME
+ && isi1.addralign() == isi2.addralign()))
+ {
+ if (isi1.section_name() != isi2.section_name())
+ return isi1.section_name() < isi2.section_name();
+ }
+ if (this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT
+ || this->section_sort_ == SORT_WILDCARD_BY_NAME_BY_ALIGNMENT
+ || this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT_BY_NAME)
+ {
+ if (isi1.addralign() != isi2.addralign())
+ return isi1.addralign() < isi2.addralign();
+ }
+ if (this->filename_sort_ == SORT_WILDCARD_BY_NAME)
+ {
+ if (isi1.relobj()->name() != isi2.relobj()->name())
+ return (isi1.relobj()->name() < isi2.relobj()->name());
+ }
+
+ // Otherwise we leave them in the same order.
+ return false;
+}
+
+// Set the section address. Look in INPUT_SECTIONS for sections which
+// match this spec, sort them as specified, and add them to the output
+// section.
+
+void
+Output_section_element_input::set_section_addresses(
+ Symbol_table*,
+ Layout* layout,
+ Output_section* output_section,
+ uint64_t subalign,
+ uint64_t* dot_value,
+ uint64_t*,
+ Output_section** dot_section,
+ std::string* fill,
+ Input_section_list* input_sections)
+{
+ // We build a list of sections which match each
+ // Input_section_pattern.
+
+ typedef std::vector<std::vector<Input_section_info> > Matching_sections;
+ size_t input_pattern_count = this->input_section_patterns_.size();
+ if (input_pattern_count == 0)
+ input_pattern_count = 1;
+ Matching_sections matching_sections(input_pattern_count);
+
+ // Look through the list of sections for this output section. Add
+ // each one which matches to one of the elements of
+ // MATCHING_SECTIONS.
+
+ Input_section_list::iterator p = input_sections->begin();
+ while (p != input_sections->end())
+ {
+ Relobj* relobj = p->relobj();
+ unsigned int shndx = p->shndx();
+ Input_section_info isi(*p);
+
+ // Calling section_name and section_addralign is not very
+ // efficient.
+
+ // Lock the object so that we can get information about the
+ // section. This is OK since we know we are single-threaded
+ // here.
+ {
+ const Task* task = reinterpret_cast<const Task*>(-1);
+ Task_lock_obj<Object> tl(task, relobj);
+
+ isi.set_section_name(relobj->section_name(shndx));
+ if (p->is_relaxed_input_section())
+ {
+ // We use current data size because relaxed section sizes may not
+ // have finalized yet.
+ isi.set_size(p->relaxed_input_section()->current_data_size());
+ isi.set_addralign(p->relaxed_input_section()->addralign());
+ }
+ else
+ {
+ isi.set_size(relobj->section_size(shndx));
+ isi.set_addralign(relobj->section_addralign(shndx));
+ }
+ }
+
+ if (!this->match_file_name(relobj->name().c_str()))
+ ++p;
+ else if (this->input_section_patterns_.empty())
+ {
+ matching_sections[0].push_back(isi);
+ p = input_sections->erase(p);
+ }
+ else
+ {
+ size_t i;
+ for (i = 0; i < input_pattern_count; ++i)
+ {
+ const Input_section_pattern&
+ isp(this->input_section_patterns_[i]);
+ if (match(isi.section_name().c_str(), isp.pattern.c_str(),
+ isp.pattern_is_wildcard))
+ break;
+ }
+
+ if (i >= this->input_section_patterns_.size())
+ ++p;
+ else
+ {
+ matching_sections[i].push_back(isi);
+ p = input_sections->erase(p);
+ }
+ }
+ }
+
+ // Look through MATCHING_SECTIONS. Sort each one as specified,
+ // using a stable sort so that we get the default order when
+ // sections are otherwise equal. Add each input section to the
+ // output section.
+
+ uint64_t dot = *dot_value;
+ for (size_t i = 0; i < input_pattern_count; ++i)
+ {
+ if (matching_sections[i].empty())
+ continue;
+
+ gold_assert(output_section != NULL);
+
+ const Input_section_pattern& isp(this->input_section_patterns_[i]);
+ if (isp.sort != SORT_WILDCARD_NONE
+ || this->filename_sort_ != SORT_WILDCARD_NONE)
+ std::stable_sort(matching_sections[i].begin(),
+ matching_sections[i].end(),
+ Input_section_sorter(this->filename_sort_,
+ isp.sort));
+
+ for (std::vector<Input_section_info>::const_iterator p =
+ matching_sections[i].begin();
+ p != matching_sections[i].end();
+ ++p)
+ {
+ // Override the original address alignment if SUBALIGN is specified
+ // and is greater than the original alignment. We need to make a
+ // copy of the input section to modify the alignment.
+ Output_section::Input_section sis(p->input_section());
+
+ uint64_t this_subalign = sis.addralign();
+ if (!sis.is_input_section())
+ sis.output_section_data()->finalize_data_size();
+ uint64_t data_size = sis.data_size();
+ if (this_subalign < subalign)
+ {
+ this_subalign = subalign;
+ sis.set_addralign(subalign);
+ }
+
+ uint64_t address = align_address(dot, this_subalign);
+
+ if (address > dot && !fill->empty())
+ {
+ section_size_type length =
+ convert_to_section_size_type(address - dot);
+ std::string this_fill = this->get_fill_string(fill, length);
+ Output_section_data* posd = new Output_data_const(this_fill, 0);
+ output_section->add_output_section_data(posd);
+ layout->new_output_section_data_from_script(posd);
+ }
+
+ output_section->add_script_input_section(sis);
+ dot = address + data_size;
+ }
+ }
+
+ // An SHF_TLS/SHT_NOBITS section does not take up any
+ // address space.
+ if (output_section == NULL
+ || (output_section->flags() & elfcpp::SHF_TLS) == 0
+ || output_section->type() != elfcpp::SHT_NOBITS)
+ *dot_value = dot;
+
+ this->final_dot_value_ = *dot_value;
+ this->final_dot_section_ = *dot_section;
+}
+
+// Print for debugging.
+
+void
+Output_section_element_input::print(FILE* f) const
+{
+ fprintf(f, " ");
+
+ if (this->keep_)
+ fprintf(f, "KEEP(");
+
+ if (!this->filename_pattern_.empty())
+ {
+ bool need_close_paren = false;
+ switch (this->filename_sort_)
+ {
+ case SORT_WILDCARD_NONE:
+ break;
+ case SORT_WILDCARD_BY_NAME:
+ fprintf(f, "SORT_BY_NAME(");
+ need_close_paren = true;
+ break;
+ default:
+ gold_unreachable();
+ }
+
+ fprintf(f, "%s", this->filename_pattern_.c_str());
+
+ if (need_close_paren)
+ fprintf(f, ")");
+ }
+
+ if (!this->input_section_patterns_.empty()
+ || !this->filename_exclusions_.empty())
+ {
+ fprintf(f, "(");
+
+ bool need_space = false;
+ if (!this->filename_exclusions_.empty())
+ {
+ fprintf(f, "EXCLUDE_FILE(");
+ bool need_comma = false;
+ for (Filename_exclusions::const_iterator p =
+ this->filename_exclusions_.begin();
+ p != this->filename_exclusions_.end();
+ ++p)
+ {
+ if (need_comma)
+ fprintf(f, ", ");
+ fprintf(f, "%s", p->first.c_str());
+ need_comma = true;
+ }
+ fprintf(f, ")");
+ need_space = true;
+ }
+
+ for (Input_section_patterns::const_iterator p =
+ this->input_section_patterns_.begin();
+ p != this->input_section_patterns_.end();
+ ++p)
+ {
+ if (need_space)
+ fprintf(f, " ");
+
+ int close_parens = 0;
+ switch (p->sort)
+ {
+ case SORT_WILDCARD_NONE:
+ break;
+ case SORT_WILDCARD_BY_NAME:
+ fprintf(f, "SORT_BY_NAME(");
+ close_parens = 1;
+ break;
+ case SORT_WILDCARD_BY_ALIGNMENT:
+ fprintf(f, "SORT_BY_ALIGNMENT(");
+ close_parens = 1;
+ break;
+ case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT:
+ fprintf(f, "SORT_BY_NAME(SORT_BY_ALIGNMENT(");
+ close_parens = 2;
+ break;
+ case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME:
+ fprintf(f, "SORT_BY_ALIGNMENT(SORT_BY_NAME(");
+ close_parens = 2;
+ break;
+ default:
+ gold_unreachable();
+ }
+
+ fprintf(f, "%s", p->pattern.c_str());
+
+ for (int i = 0; i < close_parens; ++i)
+ fprintf(f, ")");
+
+ need_space = true;
+ }
+
+ fprintf(f, ")");
+ }
+
+ if (this->keep_)
+ fprintf(f, ")");
+
+ fprintf(f, "\n");
+}
+
+// An output section.
+
+class Output_section_definition : public Sections_element
+{
+ public:
+ typedef Output_section_element::Input_section_list Input_section_list;
+
+ Output_section_definition(const char* name, size_t namelen,
+ const Parser_output_section_header* header);
+
+ // Finish the output section with the information in the trailer.
+ void
+ finish(const Parser_output_section_trailer* trailer);
+
+ // Add a symbol to be defined.
+ void
+ add_symbol_assignment(const char* name, size_t length, Expression* value,
+ bool provide, bool hidden);
+
+ // Add an assignment to the special dot symbol.
+ void
+ add_dot_assignment(Expression* value);
+
+ // Add an assertion.
+ void
+ add_assertion(Expression* check, const char* message, size_t messagelen);
+
+ // Add a data item to the current output section.
+ void
+ add_data(int size, bool is_signed, Expression* val);
+
+ // Add a setting for the fill value.
+ void
+ add_fill(Expression* val);
+
+ // Add an input section specification.
+ void
+ add_input_section(const Input_section_spec* spec, bool keep);
+
+ // Return whether the output section is relro.
+ bool
+ is_relro() const
+ { return this->is_relro_; }
+
+ // Record that the output section is relro.
+ void
+ set_is_relro()
+ { this->is_relro_ = true; }
+
+ // Create any required output sections.
+ void
+ create_sections(Layout*);
+
+ // Add any symbols being defined to the symbol table.
+ void
+ add_symbols_to_table(Symbol_table* symtab);
+
+ // Finalize symbols and check assertions.
+ void
+ finalize_symbols(Symbol_table*, const Layout*, uint64_t*);
+
+ // Return the output section name to use for an input file name and
+ // section name.
+ const char*
+ output_section_name(const char* file_name, const char* section_name,
+ Output_section***, Script_sections::Section_type*,
+ bool*);
+
+ // Initialize OSP with an output section.
+ void
+ orphan_section_init(Orphan_section_placement* osp,
+ Script_sections::Elements_iterator p)
+ { osp->output_section_init(this->name_, this->output_section_, p); }
+
+ // Set the section address.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout,
+ uint64_t* dot_value, uint64_t*,
+ uint64_t* load_address);
+
+ // Check a constraint (ONLY_IF_RO, etc.) on an output section. If
+ // this section is constrained, and the input sections do not match,
+ // return the constraint, and set *POSD.
+ Section_constraint
+ check_constraint(Output_section_definition** posd);
+
+ // See if this is the alternate output section for a constrained
+ // output section. If it is, transfer the Output_section and return
+ // true. Otherwise return false.
+ bool
+ alternate_constraint(Output_section_definition*, Section_constraint);
+
+ // Get the list of segments to use for an allocated section when
+ // using a PHDRS clause.
+ Output_section*
+ allocate_to_segment(String_list** phdrs_list, bool* orphan);
+
+ // Look for an output section by name and return the address, the
+ // load address, the alignment, and the size. This is used when an
+ // expression refers to an output section which was not actually
+ // created. This returns true if the section was found, false
+ // otherwise.
+ bool
+ get_output_section_info(const char*, uint64_t*, uint64_t*, uint64_t*,
+ uint64_t*) const;
+
+ // Return the associated Output_section if there is one.
+ Output_section*
+ get_output_section() const
+ { return this->output_section_; }
+
+ // Print the contents to the FILE. This is for debugging.
+ void
+ print(FILE*) const;
+
+ // Return the output section type if specified or Script_sections::ST_NONE.
+ Script_sections::Section_type
+ section_type() const;
+
+ // Store the memory region to use.
+ void
+ set_memory_region(Memory_region*, bool set_vma);
+
+ void
+ set_section_vma(Expression* address)
+ { this->address_ = address; }
+
+ void
+ set_section_lma(Expression* address)
+ { this->load_address_ = address; }
+
+ const std::string&
+ get_section_name() const
+ { return this->name_; }
+
+ private:
+ static const char*
+ script_section_type_name(Script_section_type);
+
+ typedef std::vector<Output_section_element*> Output_section_elements;
+
+ // The output section name.
+ std::string name_;
+ // The address. This may be NULL.
+ Expression* address_;
+ // The load address. This may be NULL.
+ Expression* load_address_;
+ // The alignment. This may be NULL.
+ Expression* align_;
+ // The input section alignment. This may be NULL.
+ Expression* subalign_;
+ // The constraint, if any.
+ Section_constraint constraint_;
+ // The fill value. This may be NULL.
+ Expression* fill_;
+ // The list of segments this section should go into. This may be
+ // NULL.
+ String_list* phdrs_;
+ // The list of elements defining the section.
+ Output_section_elements elements_;
+ // The Output_section created for this definition. This will be
+ // NULL if none was created.
+ Output_section* output_section_;
+ // The address after it has been evaluated.
+ uint64_t evaluated_address_;
+ // The load address after it has been evaluated.
+ uint64_t evaluated_load_address_;
+ // The alignment after it has been evaluated.
+ uint64_t evaluated_addralign_;
+ // The output section is relro.
+ bool is_relro_;
+ // The output section type if specified.
+ enum Script_section_type script_section_type_;
+};
+
+// Constructor.
+
+Output_section_definition::Output_section_definition(
+ const char* name,
+ size_t namelen,
+ const Parser_output_section_header* header)
+ : name_(name, namelen),
+ address_(header->address),
+ load_address_(header->load_address),
+ align_(header->align),
+ subalign_(header->subalign),
+ constraint_(header->constraint),
+ fill_(NULL),
+ phdrs_(NULL),
+ elements_(),
+ output_section_(NULL),
+ evaluated_address_(0),
+ evaluated_load_address_(0),
+ evaluated_addralign_(0),
+ is_relro_(false),
+ script_section_type_(header->section_type)
+{
+}
+
+// Finish an output section.
+
+void
+Output_section_definition::finish(const Parser_output_section_trailer* trailer)
+{
+ this->fill_ = trailer->fill;
+ this->phdrs_ = trailer->phdrs;
+}
+
+// Add a symbol to be defined.
+
+void
+Output_section_definition::add_symbol_assignment(const char* name,
+ size_t length,
+ Expression* value,
+ bool provide,
+ bool hidden)
+{
+ Output_section_element* p = new Output_section_element_assignment(name,
+ length,
+ value,
+ provide,
+ hidden);
+ this->elements_.push_back(p);
+}
+
+// Add an assignment to the special dot symbol.
+
+void
+Output_section_definition::add_dot_assignment(Expression* value)
+{
+ Output_section_element* p = new Output_section_element_dot_assignment(value);
+ this->elements_.push_back(p);
+}
+
+// Add an assertion.
+
+void
+Output_section_definition::add_assertion(Expression* check,
+ const char* message,
+ size_t messagelen)
+{
+ Output_section_element* p = new Output_section_element_assertion(check,
+ message,
+ messagelen);
+ this->elements_.push_back(p);
+}
+
+// Add a data item to the current output section.
+
+void
+Output_section_definition::add_data(int size, bool is_signed, Expression* val)
+{
+ Output_section_element* p = new Output_section_element_data(size, is_signed,
+ val);
+ this->elements_.push_back(p);
+}
+
+// Add a setting for the fill value.
+
+void
+Output_section_definition::add_fill(Expression* val)
+{
+ Output_section_element* p = new Output_section_element_fill(val);
+ this->elements_.push_back(p);
+}
+
+// Add an input section specification.
+
+void
+Output_section_definition::add_input_section(const Input_section_spec* spec,
+ bool keep)
+{
+ Output_section_element* p = new Output_section_element_input(spec, keep);
+ this->elements_.push_back(p);
+}
+
+// Create any required output sections. We need an output section if
+// there is a data statement here.
+
+void
+Output_section_definition::create_sections(Layout* layout)
+{
+ if (this->output_section_ != NULL)
+ return;
+ for (Output_section_elements::const_iterator p = this->elements_.begin();
+ p != this->elements_.end();
+ ++p)
+ {
+ if ((*p)->needs_output_section())
+ {
+ const char* name = this->name_.c_str();
+ this->output_section_ =
+ layout->make_output_section_for_script(name, this->section_type());
+ return;
+ }
+ }
+}
+
+// Add any symbols being defined to the symbol table.
+
+void
+Output_section_definition::add_symbols_to_table(Symbol_table* symtab)
+{
+ for (Output_section_elements::iterator p = this->elements_.begin();
+ p != this->elements_.end();
+ ++p)
+ (*p)->add_symbols_to_table(symtab);
+}
+
+// Finalize symbols and check assertions.
+
+void
+Output_section_definition::finalize_symbols(Symbol_table* symtab,
+ const Layout* layout,
+ uint64_t* dot_value)
+{
+ if (this->output_section_ != NULL)
+ *dot_value = this->output_section_->address();
+ else
+ {
+ uint64_t address = *dot_value;
+ if (this->address_ != NULL)
+ {
+ address = this->address_->eval_with_dot(symtab, layout, true,
+ *dot_value, NULL,
+ NULL, NULL, false);
+ }
+ if (this->align_ != NULL)
+ {
+ uint64_t align = this->align_->eval_with_dot(symtab, layout, true,
+ *dot_value, NULL,
+ NULL, NULL, false);
+ address = align_address(address, align);
+ }
+ *dot_value = address;
+ }
+
+ Output_section* dot_section = this->output_section_;
+ for (Output_section_elements::iterator p = this->elements_.begin();
+ p != this->elements_.end();
+ ++p)
+ (*p)->finalize_symbols(symtab, layout, dot_value, &dot_section);
+}
+
+// Return the output section name to use for an input section name.
+
+const char*
+Output_section_definition::output_section_name(
+ const char* file_name,
+ const char* section_name,
+ Output_section*** slot,
+ Script_sections::Section_type* psection_type,
+ bool* keep)
+{
+ // Ask each element whether it matches NAME.
+ for (Output_section_elements::const_iterator p = this->elements_.begin();
+ p != this->elements_.end();
+ ++p)
+ {
+ if ((*p)->match_name(file_name, section_name, keep))
+ {
+ // We found a match for NAME, which means that it should go
+ // into this output section.
+ *slot = &this->output_section_;
+ *psection_type = this->section_type();
+ return this->name_.c_str();
+ }
+ }
+
+ // We don't know about this section name.
+ return NULL;
+}
+
+// Return true if memory from START to START + LENGTH is contained
+// within a memory region.
+
+bool
+Script_sections::block_in_region(Symbol_table* symtab, Layout* layout,
+ uint64_t start, uint64_t length) const
+{
+ if (this->memory_regions_ == NULL)
+ return false;
+
+ for (Memory_regions::const_iterator mr = this->memory_regions_->begin();
+ mr != this->memory_regions_->end();
+ ++mr)
+ {
+ uint64_t s = (*mr)->start_address()->eval(symtab, layout, false);
+ uint64_t l = (*mr)->length()->eval(symtab, layout, false);
+
+ if (s <= start
+ && (s + l) >= (start + length))
+ return true;
+ }
+
+ return false;
+}
+
+// Find a memory region that should be used by a given output SECTION.
+// If provided set PREVIOUS_SECTION_RETURN to point to the last section
+// that used the return memory region.
+
+Memory_region*
+Script_sections::find_memory_region(
+ Output_section_definition* section,
+ bool find_vma_region,
+ Output_section_definition** previous_section_return)
+{
+ if (previous_section_return != NULL)
+ * previous_section_return = NULL;
+
+ // Walk the memory regions specified in this script, if any.
+ if (this->memory_regions_ == NULL)
+ return NULL;
+
+ // The /DISCARD/ section never gets assigned to any region.
+ if (section->get_section_name() == "/DISCARD/")
+ return NULL;
+
+ Memory_region* first_match = NULL;
+
+ // First check to see if a region has been assigned to this section.
+ for (Memory_regions::const_iterator mr = this->memory_regions_->begin();
+ mr != this->memory_regions_->end();
+ ++mr)
+ {
+ if (find_vma_region)
+ {
+ for (Memory_region::Section_list::const_iterator s =
+ (*mr)->get_vma_section_list_start();
+ s != (*mr)->get_vma_section_list_end();
+ ++s)
+ if ((*s) == section)
+ {
+ (*mr)->set_last_section(section);
+ return *mr;
+ }
+ }
+ else
+ {
+ for (Memory_region::Section_list::const_iterator s =
+ (*mr)->get_lma_section_list_start();
+ s != (*mr)->get_lma_section_list_end();
+ ++s)
+ if ((*s) == section)
+ {
+ (*mr)->set_last_section(section);
+ return *mr;
+ }
+ }
+
+ // Make a note of the first memory region whose attributes
+ // are compatible with the section. If we do not find an
+ // explicit region assignment, then we will return this region.
+ Output_section* out_sec = section->get_output_section();
+ if (first_match == NULL
+ && out_sec != NULL
+ && (*mr)->attributes_compatible(out_sec->flags(),
+ out_sec->type()))
+ first_match = *mr;
+ }
+
+ // With LMA computations, if an explicit region has not been specified then
+ // we will want to set the difference between the VMA and the LMA of the
+ // section were searching for to be the same as the difference between the
+ // VMA and LMA of the last section to be added to first matched region.
+ // Hence, if it was asked for, we return a pointer to the last section
+ // known to be used by the first matched region.
+ if (first_match != NULL
+ && previous_section_return != NULL)
+ *previous_section_return = first_match->get_last_section();
+
+ return first_match;
+}
+
+// Set the section address. Note that the OUTPUT_SECTION_ field will
+// be NULL if no input sections were mapped to this output section.
+// We still have to adjust dot and process symbol assignments.
+
+void
+Output_section_definition::set_section_addresses(Symbol_table* symtab,
+ Layout* layout,
+ uint64_t* dot_value,
+ uint64_t* dot_alignment,
+ uint64_t* load_address)
+{
+ Memory_region* vma_region = NULL;
+ Memory_region* lma_region = NULL;
+ Script_sections* script_sections =
+ layout->script_options()->script_sections();
+ uint64_t address;
+ uint64_t old_dot_value = *dot_value;
+ uint64_t old_load_address = *load_address;
+
+ // If input section sorting is requested via --section-ordering-file or
+ // linker plugins, then do it here. This is important because we want
+ // any sorting specified in the linker scripts, which will be done after
+ // this, to take precedence. The final order of input sections is then
+ // guaranteed to be according to the linker script specification.
+ if (this->output_section_ != NULL
+ && this->output_section_->input_section_order_specified())
+ this->output_section_->sort_attached_input_sections();
+
+ // Decide the start address for the section. The algorithm is:
+ // 1) If an address has been specified in a linker script, use that.
+ // 2) Otherwise if a memory region has been specified for the section,
+ // use the next free address in the region.
+ // 3) Otherwise if memory regions have been specified find the first
+ // region whose attributes are compatible with this section and
+ // install it into that region.
+ // 4) Otherwise use the current location counter.
+
+ if (this->output_section_ != NULL
+ // Check for --section-start.
+ && parameters->options().section_start(this->output_section_->name(),
+ &address))
+ ;
+ else if (this->address_ == NULL)
+ {
+ vma_region = script_sections->find_memory_region(this, true, NULL);
+
+ if (vma_region != NULL)
+ address = vma_region->get_current_address()->eval(symtab, layout,
+ false);
+ else
+ address = *dot_value;
+ }
+ else
+ address = this->address_->eval_with_dot(symtab, layout, true,
+ *dot_value, NULL, NULL,
+ dot_alignment, false);
+ uint64_t align;
+ if (this->align_ == NULL)
+ {
+ if (this->output_section_ == NULL)
+ align = 0;
+ else
+ align = this->output_section_->addralign();
+ }
+ else
+ {
+ Output_section* align_section;
+ align = this->align_->eval_with_dot(symtab, layout, true, *dot_value,
+ NULL, &align_section, NULL, false);
+ if (align_section != NULL)
+ gold_warning(_("alignment of section %s is not absolute"),
+ this->name_.c_str());
+ if (this->output_section_ != NULL)
+ this->output_section_->set_addralign(align);
+ }
+
+ address = align_address(address, align);
+
+ uint64_t start_address = address;
+
+ *dot_value = address;
+
+ // Except for NOLOAD sections, the address of non-SHF_ALLOC sections is
+ // forced to zero, regardless of what the linker script wants.
+ if (this->output_section_ != NULL
+ && ((this->output_section_->flags() & elfcpp::SHF_ALLOC) != 0
+ || this->output_section_->is_noload()))
+ this->output_section_->set_address(address);
+
+ this->evaluated_address_ = address;
+ this->evaluated_addralign_ = align;
+
+ uint64_t laddr;
+
+ if (this->load_address_ == NULL)
+ {
+ Output_section_definition* previous_section;
+
+ // Determine if an LMA region has been set for this section.
+ lma_region = script_sections->find_memory_region(this, false,
+ &previous_section);
+
+ if (lma_region != NULL)
+ {
+ if (previous_section == NULL)
+ // The LMA address was explicitly set to the given region.
+ laddr = lma_region->get_current_address()->eval(symtab, layout,
+ false);
+ else
+ {
+ // We are not going to use the discovered lma_region, so
+ // make sure that we do not update it in the code below.
+ lma_region = NULL;
+
+ if (this->address_ != NULL || previous_section == this)
+ {
+ // Either an explicit VMA address has been set, or an
+ // explicit VMA region has been set, so set the LMA equal to
+ // the VMA.
+ laddr = address;
+ }
+ else
+ {
+ // The LMA address was not explicitly or implicitly set.
+ //
+ // We have been given the first memory region that is
+ // compatible with the current section and a pointer to the
+ // last section to use this region. Set the LMA of this
+ // section so that the difference between its' VMA and LMA
+ // is the same as the difference between the VMA and LMA of
+ // the last section in the given region.
+ laddr = address + (previous_section->evaluated_load_address_
+ - previous_section->evaluated_address_);
+ }
+ }
+
+ if (this->output_section_ != NULL)
+ this->output_section_->set_load_address(laddr);
+ }
+ else
+ {
+ // Do not set the load address of the output section, if one exists.
+ // This allows future sections to determine what the load address
+ // should be. If none is ever set, it will default to being the
+ // same as the vma address.
+ laddr = address;
+ }
+ }
+ else
+ {
+ laddr = this->load_address_->eval_with_dot(symtab, layout, true,
+ *dot_value,
+ this->output_section_,
+ NULL, NULL, false);
+ if (this->output_section_ != NULL)
+ this->output_section_->set_load_address(laddr);
+ }
+
+ this->evaluated_load_address_ = laddr;
+
+ uint64_t subalign;
+ if (this->subalign_ == NULL)
+ subalign = 0;
+ else
+ {
+ Output_section* subalign_section;
+ subalign = this->subalign_->eval_with_dot(symtab, layout, true,
+ *dot_value, NULL,
+ &subalign_section, NULL,
+ false);
+ if (subalign_section != NULL)
+ gold_warning(_("subalign of section %s is not absolute"),
+ this->name_.c_str());
+ }
+
+ std::string fill;
+ if (this->fill_ != NULL)
+ {
+ // FIXME: The GNU linker supports fill values of arbitrary
+ // length.
+ Output_section* fill_section;
+ uint64_t fill_val = this->fill_->eval_with_dot(symtab, layout, true,
+ *dot_value,
+ NULL, &fill_section,
+ NULL, false);
+ if (fill_section != NULL)
+ gold_warning(_("fill of section %s is not absolute"),
+ this->name_.c_str());
+ unsigned char fill_buff[4];
+ elfcpp::Swap_unaligned<32, true>::writeval(fill_buff, fill_val);
+ fill.assign(reinterpret_cast<char*>(fill_buff), 4);
+ }
+
+ Input_section_list input_sections;
+ if (this->output_section_ != NULL)
+ {
+ // Get the list of input sections attached to this output
+ // section. This will leave the output section with only
+ // Output_section_data entries.
+ address += this->output_section_->get_input_sections(address,
+ fill,
+ &input_sections);
+ *dot_value = address;
+ }
+
+ Output_section* dot_section = this->output_section_;
+ for (Output_section_elements::iterator p = this->elements_.begin();
+ p != this->elements_.end();
+ ++p)
+ (*p)->set_section_addresses(symtab, layout, this->output_section_,
+ subalign, dot_value, dot_alignment,
+ &dot_section, &fill, &input_sections);
+
+ gold_assert(input_sections.empty());
+
+ if (vma_region != NULL)
+ {
+ // Update the VMA region being used by the section now that we know how
+ // big it is. Use the current address in the region, rather than
+ // start_address because that might have been aligned upwards and we
+ // need to allow for the padding.
+ Expression* addr = vma_region->get_current_address();
+ uint64_t size = *dot_value - addr->eval(symtab, layout, false);
+
+ vma_region->increment_offset(this->get_section_name(), size,
+ symtab, layout);
+ }
+
+ // If the LMA region is different from the VMA region, then increment the
+ // offset there as well. Note that we use the same "dot_value -
+ // start_address" formula that is used in the load_address assignment below.
+ if (lma_region != NULL && lma_region != vma_region)
+ lma_region->increment_offset(this->get_section_name(),
+ *dot_value - start_address,
+ symtab, layout);
+
+ // Compute the load address for the following section.
+ if (this->output_section_ == NULL)
+ *load_address = *dot_value;
+ else if (this->load_address_ == NULL)
+ {
+ if (lma_region == NULL)
+ *load_address = *dot_value;
+ else
+ *load_address =
+ lma_region->get_current_address()->eval(symtab, layout, false);
+ }
+ else
+ *load_address = (this->output_section_->load_address()
+ + (*dot_value - start_address));
+
+ if (this->output_section_ != NULL)
+ {
+ if (this->is_relro_)
+ this->output_section_->set_is_relro();
+ else
+ this->output_section_->clear_is_relro();
+
+ // If this is a NOLOAD section, keep dot and load address unchanged.
+ if (this->output_section_->is_noload())
+ {
+ *dot_value = old_dot_value;
+ *load_address = old_load_address;
+ }
+ }
+}
+
+// Check a constraint (ONLY_IF_RO, etc.) on an output section. If
+// this section is constrained, and the input sections do not match,
+// return the constraint, and set *POSD.
+
+Section_constraint
+Output_section_definition::check_constraint(Output_section_definition** posd)
+{
+ switch (this->constraint_)
+ {
+ case CONSTRAINT_NONE:
+ return CONSTRAINT_NONE;
+
+ case CONSTRAINT_ONLY_IF_RO:
+ if (this->output_section_ != NULL
+ && (this->output_section_->flags() & elfcpp::SHF_WRITE) != 0)
+ {
+ *posd = this;
+ return CONSTRAINT_ONLY_IF_RO;
+ }
+ return CONSTRAINT_NONE;
+
+ case CONSTRAINT_ONLY_IF_RW:
+ if (this->output_section_ != NULL
+ && (this->output_section_->flags() & elfcpp::SHF_WRITE) == 0)
+ {
+ *posd = this;
+ return CONSTRAINT_ONLY_IF_RW;
+ }
+ return CONSTRAINT_NONE;
+
+ case CONSTRAINT_SPECIAL:
+ if (this->output_section_ != NULL)
+ gold_error(_("SPECIAL constraints are not implemented"));
+ return CONSTRAINT_NONE;
+
+ default:
+ gold_unreachable();
+ }
+}
+
+// See if this is the alternate output section for a constrained
+// output section. If it is, transfer the Output_section and return
+// true. Otherwise return false.
+
+bool
+Output_section_definition::alternate_constraint(
+ Output_section_definition* posd,
+ Section_constraint constraint)
+{
+ if (this->name_ != posd->name_)
+ return false;
+
+ switch (constraint)
+ {
+ case CONSTRAINT_ONLY_IF_RO:
+ if (this->constraint_ != CONSTRAINT_ONLY_IF_RW)
+ return false;
+ break;
+
+ case CONSTRAINT_ONLY_IF_RW:
+ if (this->constraint_ != CONSTRAINT_ONLY_IF_RO)
+ return false;
+ break;
+
+ default:
+ gold_unreachable();
+ }
+
+ // We have found the alternate constraint. We just need to move
+ // over the Output_section. When constraints are used properly,
+ // THIS should not have an output_section pointer, as all the input
+ // sections should have matched the other definition.
+
+ if (this->output_section_ != NULL)
+ gold_error(_("mismatched definition for constrained sections"));
+
+ this->output_section_ = posd->output_section_;
+ posd->output_section_ = NULL;
+
+ if (this->is_relro_)
+ this->output_section_->set_is_relro();
+ else
+ this->output_section_->clear_is_relro();
+
+ return true;
+}
+
+// Get the list of segments to use for an allocated section when using
+// a PHDRS clause.
+
+Output_section*
+Output_section_definition::allocate_to_segment(String_list** phdrs_list,
+ bool* orphan)
+{
+ // Update phdrs_list even if we don't have an output section. It
+ // might be used by the following sections.
+ if (this->phdrs_ != NULL)
+ *phdrs_list = this->phdrs_;
+
+ if (this->output_section_ == NULL)
+ return NULL;
+ if ((this->output_section_->flags() & elfcpp::SHF_ALLOC) == 0)
+ return NULL;
+ *orphan = false;
+ return this->output_section_;
+}
+
+// Look for an output section by name and return the address, the load
+// address, the alignment, and the size. This is used when an
+// expression refers to an output section which was not actually
+// created. This returns true if the section was found, false
+// otherwise.
+
+bool
+Output_section_definition::get_output_section_info(const char* name,
+ uint64_t* address,
+ uint64_t* load_address,
+ uint64_t* addralign,
+ uint64_t* size) const
+{
+ if (this->name_ != name)
+ return false;
+
+ if (this->output_section_ != NULL)
+ {
+ *address = this->output_section_->address();
+ if (this->output_section_->has_load_address())
+ *load_address = this->output_section_->load_address();
+ else
+ *load_address = *address;
+ *addralign = this->output_section_->addralign();
+ *size = this->output_section_->current_data_size();
+ }
+ else
+ {
+ *address = this->evaluated_address_;
+ *load_address = this->evaluated_load_address_;
+ *addralign = this->evaluated_addralign_;
+ *size = 0;
+ }
+
+ return true;
+}
+
+// Print for debugging.
+
+void
+Output_section_definition::print(FILE* f) const
+{
+ fprintf(f, " %s ", this->name_.c_str());
+
+ if (this->address_ != NULL)
+ {
+ this->address_->print(f);
+ fprintf(f, " ");
+ }
+
+ if (this->script_section_type_ != SCRIPT_SECTION_TYPE_NONE)
+ fprintf(f, "(%s) ",
+ this->script_section_type_name(this->script_section_type_));
+
+ fprintf(f, ": ");
+
+ if (this->load_address_ != NULL)
+ {
+ fprintf(f, "AT(");
+ this->load_address_->print(f);
+ fprintf(f, ") ");
+ }
+
+ if (this->align_ != NULL)
+ {
+ fprintf(f, "ALIGN(");
+ this->align_->print(f);
+ fprintf(f, ") ");
+ }
+
+ if (this->subalign_ != NULL)
+ {
+ fprintf(f, "SUBALIGN(");
+ this->subalign_->print(f);
+ fprintf(f, ") ");
+ }
+
+ fprintf(f, "{\n");
+
+ for (Output_section_elements::const_iterator p = this->elements_.begin();
+ p != this->elements_.end();
+ ++p)
+ (*p)->print(f);
+
+ fprintf(f, " }");
+
+ if (this->fill_ != NULL)
+ {
+ fprintf(f, " = ");
+ this->fill_->print(f);
+ }
+
+ if (this->phdrs_ != NULL)
+ {
+ for (String_list::const_iterator p = this->phdrs_->begin();
+ p != this->phdrs_->end();
+ ++p)
+ fprintf(f, " :%s", p->c_str());
+ }
+
+ fprintf(f, "\n");
+}
+
+Script_sections::Section_type
+Output_section_definition::section_type() const
+{
+ switch (this->script_section_type_)
+ {
+ case SCRIPT_SECTION_TYPE_NONE:
+ return Script_sections::ST_NONE;
+ case SCRIPT_SECTION_TYPE_NOLOAD:
+ return Script_sections::ST_NOLOAD;
+ case SCRIPT_SECTION_TYPE_COPY:
+ case SCRIPT_SECTION_TYPE_DSECT:
+ case SCRIPT_SECTION_TYPE_INFO:
+ case SCRIPT_SECTION_TYPE_OVERLAY:
+ // There are not really support so we treat them as ST_NONE. The
+ // parse should have issued errors for them already.
+ return Script_sections::ST_NONE;
+ default:
+ gold_unreachable();
+ }
+}
+
+// Return the name of a script section type.
+
+const char*
+Output_section_definition::script_section_type_name(
+ Script_section_type script_section_type)
+{
+ switch (script_section_type)
+ {
+ case SCRIPT_SECTION_TYPE_NONE:
+ return "NONE";
+ case SCRIPT_SECTION_TYPE_NOLOAD:
+ return "NOLOAD";
+ case SCRIPT_SECTION_TYPE_DSECT:
+ return "DSECT";
+ case SCRIPT_SECTION_TYPE_COPY:
+ return "COPY";
+ case SCRIPT_SECTION_TYPE_INFO:
+ return "INFO";
+ case SCRIPT_SECTION_TYPE_OVERLAY:
+ return "OVERLAY";
+ default:
+ gold_unreachable();
+ }
+}
+
+void
+Output_section_definition::set_memory_region(Memory_region* mr, bool set_vma)
+{
+ gold_assert(mr != NULL);
+ // Add the current section to the specified region's list.
+ mr->add_section(this, set_vma);
+}
+
+// An output section created to hold orphaned input sections. These
+// do not actually appear in linker scripts. However, for convenience
+// when setting the output section addresses, we put a marker to these
+// sections in the appropriate place in the list of SECTIONS elements.
+
+class Orphan_output_section : public Sections_element
+{
+ public:
+ Orphan_output_section(Output_section* os)
+ : os_(os)
+ { }
+
+ // Return whether the orphan output section is relro. We can just
+ // check the output section because we always set the flag, if
+ // needed, just after we create the Orphan_output_section.
+ bool
+ is_relro() const
+ { return this->os_->is_relro(); }
+
+ // Initialize OSP with an output section. This should have been
+ // done already.
+ void
+ orphan_section_init(Orphan_section_placement*,
+ Script_sections::Elements_iterator)
+ { gold_unreachable(); }
+
+ // Set section addresses.
+ void
+ set_section_addresses(Symbol_table*, Layout*, uint64_t*, uint64_t*,
+ uint64_t*);
+
+ // Get the list of segments to use for an allocated section when
+ // using a PHDRS clause.
+ Output_section*
+ allocate_to_segment(String_list**, bool*);
+
+ // Return the associated Output_section.
+ Output_section*
+ get_output_section() const
+ { return this->os_; }
+
+ // Print for debugging.
+ void
+ print(FILE* f) const
+ {
+ fprintf(f, " marker for orphaned output section %s\n",
+ this->os_->name());
+ }
+
+ private:
+ Output_section* os_;
+};
+
+// Set section addresses.
+
+void
+Orphan_output_section::set_section_addresses(Symbol_table*, Layout*,
+ uint64_t* dot_value,
+ uint64_t*,
+ uint64_t* load_address)
+{
+ typedef std::list<Output_section::Input_section> Input_section_list;
+
+ bool have_load_address = *load_address != *dot_value;
+
+ uint64_t address = *dot_value;
+ address = align_address(address, this->os_->addralign());
+
+ // If input section sorting is requested via --section-ordering-file or
+ // linker plugins, then do it here. This is important because we want
+ // any sorting specified in the linker scripts, which will be done after
+ // this, to take precedence. The final order of input sections is then
+ // guaranteed to be according to the linker script specification.
+ if (this->os_ != NULL
+ && this->os_->input_section_order_specified())
+ this->os_->sort_attached_input_sections();
+
+ // For a relocatable link, all orphan sections are put at
+ // address 0. In general we expect all sections to be at
+ // address 0 for a relocatable link, but we permit the linker
+ // script to override that for specific output sections.
+ if (parameters->options().relocatable())
+ {
+ address = 0;
+ *load_address = 0;
+ have_load_address = false;
+ }
+
+ if ((this->os_->flags() & elfcpp::SHF_ALLOC) != 0)
+ {
+ this->os_->set_address(address);
+ if (have_load_address)
+ this->os_->set_load_address(align_address(*load_address,
+ this->os_->addralign()));
+ }
+
+ Input_section_list input_sections;
+ address += this->os_->get_input_sections(address, "", &input_sections);
+
+ for (Input_section_list::iterator p = input_sections.begin();
+ p != input_sections.end();
+ ++p)
+ {
+ uint64_t addralign = p->addralign();
+ if (!p->is_input_section())
+ p->output_section_data()->finalize_data_size();
+ uint64_t size = p->data_size();
+ address = align_address(address, addralign);
+ this->os_->add_script_input_section(*p);
+ address += size;
+ }
+
+ if (parameters->options().relocatable())
+ {
+ // For a relocatable link, reset DOT_VALUE to 0.
+ *dot_value = 0;
+ *load_address = 0;
+ }
+ else if (this->os_ == NULL
+ || (this->os_->flags() & elfcpp::SHF_TLS) == 0
+ || this->os_->type() != elfcpp::SHT_NOBITS)
+ {
+ // An SHF_TLS/SHT_NOBITS section does not take up any address space.
+ if (!have_load_address)
+ *load_address = address;
+ else
+ *load_address += address - *dot_value;
+
+ *dot_value = address;
+ }
+}
+
+// Get the list of segments to use for an allocated section when using
+// a PHDRS clause. If this is an allocated section, return the
+// Output_section. We don't change the list of segments.
+
+Output_section*
+Orphan_output_section::allocate_to_segment(String_list**, bool* orphan)
+{
+ if ((this->os_->flags() & elfcpp::SHF_ALLOC) == 0)
+ return NULL;
+ *orphan = true;
+ return this->os_;
+}
+
+// Class Phdrs_element. A program header from a PHDRS clause.
+
+class Phdrs_element
+{
+ public:
+ Phdrs_element(const char* name, size_t namelen, unsigned int type,
+ bool includes_filehdr, bool includes_phdrs,
+ bool is_flags_valid, unsigned int flags,
+ Expression* load_address)
+ : name_(name, namelen), type_(type), includes_filehdr_(includes_filehdr),
+ includes_phdrs_(includes_phdrs), is_flags_valid_(is_flags_valid),
+ flags_(flags), load_address_(load_address), load_address_value_(0),
+ segment_(NULL)
+ { }
+
+ // Return the name of this segment.
+ const std::string&
+ name() const
+ { return this->name_; }
+
+ // Return the type of the segment.
+ unsigned int
+ type() const
+ { return this->type_; }
+
+ // Whether to include the file header.
+ bool
+ includes_filehdr() const
+ { return this->includes_filehdr_; }
+
+ // Whether to include the program headers.
+ bool
+ includes_phdrs() const
+ { return this->includes_phdrs_; }
+
+ // Return whether there is a load address.
+ bool
+ has_load_address() const
+ { return this->load_address_ != NULL; }
+
+ // Evaluate the load address expression if there is one.
+ void
+ eval_load_address(Symbol_table* symtab, Layout* layout)
+ {
+ if (this->load_address_ != NULL)
+ this->load_address_value_ = this->load_address_->eval(symtab, layout,
+ true);
+ }
+
+ // Return the load address.
+ uint64_t
+ load_address() const
+ {
+ gold_assert(this->load_address_ != NULL);
+ return this->load_address_value_;
+ }
+
+ // Create the segment.
+ Output_segment*
+ create_segment(Layout* layout)
+ {
+ this->segment_ = layout->make_output_segment(this->type_, this->flags_);
+ return this->segment_;
+ }
+
+ // Return the segment.
+ Output_segment*
+ segment()
+ { return this->segment_; }
+
+ // Release the segment.
+ void
+ release_segment()
+ { this->segment_ = NULL; }
+
+ // Set the segment flags if appropriate.
+ void
+ set_flags_if_valid()
+ {
+ if (this->is_flags_valid_)
+ this->segment_->set_flags(this->flags_);
+ }
+
+ // Print for debugging.
+ void
+ print(FILE*) const;
+
+ private:
+ // The name used in the script.
+ std::string name_;
+ // The type of the segment (PT_LOAD, etc.).
+ unsigned int type_;
+ // Whether this segment includes the file header.
+ bool includes_filehdr_;
+ // Whether this segment includes the section headers.
+ bool includes_phdrs_;
+ // Whether the flags were explicitly specified.
+ bool is_flags_valid_;
+ // The flags for this segment (PF_R, etc.) if specified.
+ unsigned int flags_;
+ // The expression for the load address for this segment. This may
+ // be NULL.
+ Expression* load_address_;
+ // The actual load address from evaluating the expression.
+ uint64_t load_address_value_;
+ // The segment itself.
+ Output_segment* segment_;
+};
+
+// Print for debugging.
+
+void
+Phdrs_element::print(FILE* f) const
+{
+ fprintf(f, " %s 0x%x", this->name_.c_str(), this->type_);
+ if (this->includes_filehdr_)
+ fprintf(f, " FILEHDR");
+ if (this->includes_phdrs_)
+ fprintf(f, " PHDRS");
+ if (this->is_flags_valid_)
+ fprintf(f, " FLAGS(%u)", this->flags_);
+ if (this->load_address_ != NULL)
+ {
+ fprintf(f, " AT(");
+ this->load_address_->print(f);
+ fprintf(f, ")");
+ }
+ fprintf(f, ";\n");
+}
+
+// Add a memory region.
+
+void
+Script_sections::add_memory_region(const char* name, size_t namelen,
+ unsigned int attributes,
+ Expression* start, Expression* length)
+{
+ if (this->memory_regions_ == NULL)
+ this->memory_regions_ = new Memory_regions();
+ else if (this->find_memory_region(name, namelen))
+ {
+ gold_error(_("region '%.*s' already defined"), static_cast<int>(namelen),
+ name);
+ // FIXME: Add a GOLD extension to allow multiple regions with the same
+ // name. This would amount to a single region covering disjoint blocks
+ // of memory, which is useful for embedded devices.
+ }
+
+ // FIXME: Check the length and start values. Currently we allow
+ // non-constant expressions for these values, whereas LD does not.
+
+ // FIXME: Add a GOLD extension to allow NEGATIVE LENGTHS. This would
+ // describe a region that packs from the end address going down, rather
+ // than the start address going up. This would be useful for embedded
+ // devices.
+
+ this->memory_regions_->push_back(new Memory_region(name, namelen, attributes,
+ start, length));
+}
+
+// Find a memory region.
+
+Memory_region*
+Script_sections::find_memory_region(const char* name, size_t namelen)
+{
+ if (this->memory_regions_ == NULL)
+ return NULL;
+
+ for (Memory_regions::const_iterator m = this->memory_regions_->begin();
+ m != this->memory_regions_->end();
+ ++m)
+ if ((*m)->name_match(name, namelen))
+ return *m;
+
+ return NULL;
+}
+
+// Find a memory region's origin.
+
+Expression*
+Script_sections::find_memory_region_origin(const char* name, size_t namelen)
+{
+ Memory_region* mr = find_memory_region(name, namelen);
+ if (mr == NULL)
+ return NULL;
+
+ return mr->start_address();
+}
+
+// Find a memory region's length.
+
+Expression*
+Script_sections::find_memory_region_length(const char* name, size_t namelen)
+{
+ Memory_region* mr = find_memory_region(name, namelen);
+ if (mr == NULL)
+ return NULL;
+
+ return mr->length();
+}
+
+// Set the memory region to use for the current section.
+
+void
+Script_sections::set_memory_region(Memory_region* mr, bool set_vma)
+{
+ gold_assert(!this->sections_elements_->empty());
+ this->sections_elements_->back()->set_memory_region(mr, set_vma);
+}
+
+// Class Script_sections.
+
+Script_sections::Script_sections()
+ : saw_sections_clause_(false),
+ in_sections_clause_(false),
+ sections_elements_(NULL),
+ output_section_(NULL),
+ memory_regions_(NULL),
+ phdrs_elements_(NULL),
+ orphan_section_placement_(NULL),
+ data_segment_align_start_(),
+ saw_data_segment_align_(false),
+ saw_relro_end_(false),
+ saw_segment_start_expression_(false)
+{
+}
+
+// Start a SECTIONS clause.
+
+void
+Script_sections::start_sections()
+{
+ gold_assert(!this->in_sections_clause_ && this->output_section_ == NULL);
+ this->saw_sections_clause_ = true;
+ this->in_sections_clause_ = true;
+ if (this->sections_elements_ == NULL)
+ this->sections_elements_ = new Sections_elements;
+}
+
+// Finish a SECTIONS clause.
+
+void
+Script_sections::finish_sections()
+{
+ gold_assert(this->in_sections_clause_ && this->output_section_ == NULL);
+ this->in_sections_clause_ = false;
+}
+
+// Add a symbol to be defined.
+
+void
+Script_sections::add_symbol_assignment(const char* name, size_t length,
+ Expression* val, bool provide,
+ bool hidden)
+{
+ if (this->output_section_ != NULL)
+ this->output_section_->add_symbol_assignment(name, length, val,
+ provide, hidden);
+ else
+ {
+ Sections_element* p = new Sections_element_assignment(name, length,
+ val, provide,
+ hidden);
+ this->sections_elements_->push_back(p);
+ }
+}
+
+// Add an assignment to the special dot symbol.
+
+void
+Script_sections::add_dot_assignment(Expression* val)
+{
+ if (this->output_section_ != NULL)
+ this->output_section_->add_dot_assignment(val);
+ else
+ {
+ // The GNU linker permits assignments to . to appears outside of
+ // a SECTIONS clause, and treats it as appearing inside, so
+ // sections_elements_ may be NULL here.
+ if (this->sections_elements_ == NULL)
+ {
+ this->sections_elements_ = new Sections_elements;
+ this->saw_sections_clause_ = true;
+ }
+
+ Sections_element* p = new Sections_element_dot_assignment(val);
+ this->sections_elements_->push_back(p);
+ }
+}
+
+// Add an assertion.
+
+void
+Script_sections::add_assertion(Expression* check, const char* message,
+ size_t messagelen)
+{
+ if (this->output_section_ != NULL)
+ this->output_section_->add_assertion(check, message, messagelen);
+ else
+ {
+ Sections_element* p = new Sections_element_assertion(check, message,
+ messagelen);
+ this->sections_elements_->push_back(p);
+ }
+}
+
+// Start processing entries for an output section.
+
+void
+Script_sections::start_output_section(
+ const char* name,
+ size_t namelen,
+ const Parser_output_section_header* header)
+{
+ Output_section_definition* posd = new Output_section_definition(name,
+ namelen,
+ header);
+ this->sections_elements_->push_back(posd);
+ gold_assert(this->output_section_ == NULL);
+ this->output_section_ = posd;
+}
+
+// Stop processing entries for an output section.
+
+void
+Script_sections::finish_output_section(
+ const Parser_output_section_trailer* trailer)
+{
+ gold_assert(this->output_section_ != NULL);
+ this->output_section_->finish(trailer);
+ this->output_section_ = NULL;
+}
+
+// Add a data item to the current output section.
+
+void
+Script_sections::add_data(int size, bool is_signed, Expression* val)
+{
+ gold_assert(this->output_section_ != NULL);
+ this->output_section_->add_data(size, is_signed, val);
+}
+
+// Add a fill value setting to the current output section.
+
+void
+Script_sections::add_fill(Expression* val)
+{
+ gold_assert(this->output_section_ != NULL);
+ this->output_section_->add_fill(val);
+}
+
+// Add an input section specification to the current output section.
+
+void
+Script_sections::add_input_section(const Input_section_spec* spec, bool keep)
+{
+ gold_assert(this->output_section_ != NULL);
+ this->output_section_->add_input_section(spec, keep);
+}
+
+// This is called when we see DATA_SEGMENT_ALIGN. It means that any
+// subsequent output sections may be relro.
+
+void
+Script_sections::data_segment_align()
+{
+ if (this->saw_data_segment_align_)
+ gold_error(_("DATA_SEGMENT_ALIGN may only appear once in a linker script"));
+ gold_assert(!this->sections_elements_->empty());
+ Sections_elements::iterator p = this->sections_elements_->end();
+ --p;
+ this->data_segment_align_start_ = p;
+ this->saw_data_segment_align_ = true;
+}
+
+// This is called when we see DATA_SEGMENT_RELRO_END. It means that
+// any output sections seen since DATA_SEGMENT_ALIGN are relro.
+
+void
+Script_sections::data_segment_relro_end()
+{
+ if (this->saw_relro_end_)
+ gold_error(_("DATA_SEGMENT_RELRO_END may only appear once "
+ "in a linker script"));
+ this->saw_relro_end_ = true;
+
+ if (!this->saw_data_segment_align_)
+ gold_error(_("DATA_SEGMENT_RELRO_END must follow DATA_SEGMENT_ALIGN"));
+ else
+ {
+ Sections_elements::iterator p = this->data_segment_align_start_;
+ for (++p; p != this->sections_elements_->end(); ++p)
+ (*p)->set_is_relro();
+ }
+}
+
+// Create any required sections.
+
+void
+Script_sections::create_sections(Layout* layout)
+{
+ if (!this->saw_sections_clause_)
+ return;
+ for (Sections_elements::iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ (*p)->create_sections(layout);
+}
+
+// Add any symbols we are defining to the symbol table.
+
+void
+Script_sections::add_symbols_to_table(Symbol_table* symtab)
+{
+ if (!this->saw_sections_clause_)
+ return;
+ for (Sections_elements::iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ (*p)->add_symbols_to_table(symtab);
+}
+
+// Finalize symbols and check assertions.
+
+void
+Script_sections::finalize_symbols(Symbol_table* symtab, const Layout* layout)
+{
+ if (!this->saw_sections_clause_)
+ return;
+ uint64_t dot_value = 0;
+ for (Sections_elements::iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ (*p)->finalize_symbols(symtab, layout, &dot_value);
+}
+
+// Return the name of the output section to use for an input file name
+// and section name.
+
+const char*
+Script_sections::output_section_name(
+ const char* file_name,
+ const char* section_name,
+ Output_section*** output_section_slot,
+ Script_sections::Section_type* psection_type,
+ bool* keep)
+{
+ for (Sections_elements::const_iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ {
+ const char* ret = (*p)->output_section_name(file_name, section_name,
+ output_section_slot,
+ psection_type, keep);
+
+ if (ret != NULL)
+ {
+ // The special name /DISCARD/ means that the input section
+ // should be discarded.
+ if (strcmp(ret, "/DISCARD/") == 0)
+ {
+ *output_section_slot = NULL;
+ *psection_type = Script_sections::ST_NONE;
+ return NULL;
+ }
+ return ret;
+ }
+ }
+
+ // If we couldn't find a mapping for the name, the output section
+ // gets the name of the input section.
+
+ *output_section_slot = NULL;
+ *psection_type = Script_sections::ST_NONE;
+
+ return section_name;
+}
+
+// Place a marker for an orphan output section into the SECTIONS
+// clause.
+
+void
+Script_sections::place_orphan(Output_section* os)
+{
+ Orphan_section_placement* osp = this->orphan_section_placement_;
+ if (osp == NULL)
+ {
+ // Initialize the Orphan_section_placement structure.
+ osp = new Orphan_section_placement();
+ for (Sections_elements::iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ (*p)->orphan_section_init(osp, p);
+ gold_assert(!this->sections_elements_->empty());
+ Sections_elements::iterator last = this->sections_elements_->end();
+ --last;
+ osp->last_init(last);
+ this->orphan_section_placement_ = osp;
+ }
+
+ Orphan_output_section* orphan = new Orphan_output_section(os);
+
+ // Look for where to put ORPHAN.
+ Sections_elements::iterator* where;
+ if (osp->find_place(os, &where))
+ {
+ if ((**where)->is_relro())
+ os->set_is_relro();
+ else
+ os->clear_is_relro();
+
+ // We want to insert ORPHAN after *WHERE, and then update *WHERE
+ // so that the next one goes after this one.
+ Sections_elements::iterator p = *where;
+ gold_assert(p != this->sections_elements_->end());
+ ++p;
+ *where = this->sections_elements_->insert(p, orphan);
+ }
+ else
+ {
+ os->clear_is_relro();
+ // We don't have a place to put this orphan section. Put it,
+ // and all other sections like it, at the end, but before the
+ // sections which always come at the end.
+ Sections_elements::iterator last = osp->last_place();
+ *where = this->sections_elements_->insert(last, orphan);
+ }
+}
+
+// Set the addresses of all the output sections. Walk through all the
+// elements, tracking the dot symbol. Apply assignments which set
+// absolute symbol values, in case they are used when setting dot.
+// Fill in data statement values. As we find output sections, set the
+// address, set the address of all associated input sections, and
+// update dot. Return the segment which should hold the file header
+// and segment headers, if any.
+
+Output_segment*
+Script_sections::set_section_addresses(Symbol_table* symtab, Layout* layout)
+{
+ gold_assert(this->saw_sections_clause_);
+
+ // Implement ONLY_IF_RO/ONLY_IF_RW constraints. These are a pain
+ // for our representation.
+ for (Sections_elements::iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ {
+ Output_section_definition* posd;
+ Section_constraint failed_constraint = (*p)->check_constraint(&posd);
+ if (failed_constraint != CONSTRAINT_NONE)
+ {
+ Sections_elements::iterator q;
+ for (q = this->sections_elements_->begin();
+ q != this->sections_elements_->end();
+ ++q)
+ {
+ if (q != p)
+ {
+ if ((*q)->alternate_constraint(posd, failed_constraint))
+ break;
+ }
+ }
+
+ if (q == this->sections_elements_->end())
+ gold_error(_("no matching section constraint"));
+ }
+ }
+
+ // Force the alignment of the first TLS section to be the maximum
+ // alignment of all TLS sections.
+ Output_section* first_tls = NULL;
+ uint64_t tls_align = 0;
+ for (Sections_elements::const_iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ {
+ Output_section* os = (*p)->get_output_section();
+ if (os != NULL && (os->flags() & elfcpp::SHF_TLS) != 0)
+ {
+ if (first_tls == NULL)
+ first_tls = os;
+ if (os->addralign() > tls_align)
+ tls_align = os->addralign();
+ }
+ }
+ if (first_tls != NULL)
+ first_tls->set_addralign(tls_align);
+
+ // For a relocatable link, we implicitly set dot to zero.
+ uint64_t dot_value = 0;
+ uint64_t dot_alignment = 0;
+ uint64_t load_address = 0;
+
+ // Check to see if we want to use any of -Ttext, -Tdata and -Tbss options
+ // to set section addresses. If the script has any SEGMENT_START
+ // expression, we do not set the section addresses.
+ bool use_tsection_options =
+ (!this->saw_segment_start_expression_
+ && (parameters->options().user_set_Ttext()
+ || parameters->options().user_set_Tdata()
+ || parameters->options().user_set_Tbss()));
+
+ for (Sections_elements::iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ {
+ Output_section* os = (*p)->get_output_section();
+
+ // Handle -Ttext, -Tdata and -Tbss options. We do this by looking for
+ // the special sections by names and doing dot assignments.
+ if (use_tsection_options
+ && os != NULL
+ && (os->flags() & elfcpp::SHF_ALLOC) != 0)
+ {
+ uint64_t new_dot_value = dot_value;
+
+ if (parameters->options().user_set_Ttext()
+ && strcmp(os->name(), ".text") == 0)
+ new_dot_value = parameters->options().Ttext();
+ else if (parameters->options().user_set_Tdata()
+ && strcmp(os->name(), ".data") == 0)
+ new_dot_value = parameters->options().Tdata();
+ else if (parameters->options().user_set_Tbss()
+ && strcmp(os->name(), ".bss") == 0)
+ new_dot_value = parameters->options().Tbss();
+
+ // Update dot and load address if necessary.
+ if (new_dot_value < dot_value)
+ gold_error(_("dot may not move backward"));
+ else if (new_dot_value != dot_value)
+ {
+ dot_value = new_dot_value;
+ load_address = new_dot_value;
+ }
+ }
+
+ (*p)->set_section_addresses(symtab, layout, &dot_value, &dot_alignment,
+ &load_address);
+ }
+
+ if (this->phdrs_elements_ != NULL)
+ {
+ for (Phdrs_elements::iterator p = this->phdrs_elements_->begin();
+ p != this->phdrs_elements_->end();
+ ++p)
+ (*p)->eval_load_address(symtab, layout);
+ }
+
+ return this->create_segments(layout, dot_alignment);
+}
+
+// Sort the sections in order to put them into segments.
+
+class Sort_output_sections
+{
+ public:
+ Sort_output_sections(const Script_sections::Sections_elements* elements)
+ : elements_(elements)
+ { }
+
+ bool
+ operator()(const Output_section* os1, const Output_section* os2) const;
+
+ private:
+ int
+ script_compare(const Output_section* os1, const Output_section* os2) const;
+
+ private:
+ const Script_sections::Sections_elements* elements_;
+};
+
+bool
+Sort_output_sections::operator()(const Output_section* os1,
+ const Output_section* os2) const
+{
+ // Sort first by the load address.
+ uint64_t lma1 = (os1->has_load_address()
+ ? os1->load_address()
+ : os1->address());
+ uint64_t lma2 = (os2->has_load_address()
+ ? os2->load_address()
+ : os2->address());
+ if (lma1 != lma2)
+ return lma1 < lma2;
+
+ // Then sort by the virtual address.
+ if (os1->address() != os2->address())
+ return os1->address() < os2->address();
+
+ // If the linker script says which of these sections is first, go
+ // with what it says.
+ int i = this->script_compare(os1, os2);
+ if (i != 0)
+ return i < 0;
+
+ // Sort PROGBITS before NOBITS.
+ bool nobits1 = os1->type() == elfcpp::SHT_NOBITS;
+ bool nobits2 = os2->type() == elfcpp::SHT_NOBITS;
+ if (nobits1 != nobits2)
+ return nobits2;
+
+ // Sort PROGBITS TLS sections to the end, NOBITS TLS sections to the
+ // beginning.
+ bool tls1 = (os1->flags() & elfcpp::SHF_TLS) != 0;
+ bool tls2 = (os2->flags() & elfcpp::SHF_TLS) != 0;
+ if (tls1 != tls2)
+ return nobits1 ? tls1 : tls2;
+
+ // Sort non-NOLOAD before NOLOAD.
+ if (os1->is_noload() && !os2->is_noload())
+ return true;
+ if (!os1->is_noload() && os2->is_noload())
+ return true;
+
+ // The sections seem practically identical. Sort by name to get a
+ // stable sort.
+ return os1->name() < os2->name();
+}
+
+// Return -1 if OS1 comes before OS2 in ELEMENTS_, 1 if comes after, 0
+// if either OS1 or OS2 is not mentioned. This ensures that we keep
+// empty sections in the order in which they appear in a linker
+// script.
+
+int
+Sort_output_sections::script_compare(const Output_section* os1,
+ const Output_section* os2) const
+{
+ if (this->elements_ == NULL)
+ return 0;
+
+ bool found_os1 = false;
+ bool found_os2 = false;
+ for (Script_sections::Sections_elements::const_iterator
+ p = this->elements_->begin();
+ p != this->elements_->end();
+ ++p)
+ {
+ if (os2 == (*p)->get_output_section())
+ {
+ if (found_os1)
+ return -1;
+ found_os2 = true;
+ }
+ else if (os1 == (*p)->get_output_section())
+ {
+ if (found_os2)
+ return 1;
+ found_os1 = true;
+ }
+ }
+
+ return 0;
+}
+
+// Return whether OS is a BSS section. This is a SHT_NOBITS section.
+// We treat a section with the SHF_TLS flag set as taking up space
+// even if it is SHT_NOBITS (this is true of .tbss), as we allocate
+// space for them in the file.
+
+bool
+Script_sections::is_bss_section(const Output_section* os)
+{
+ return (os->type() == elfcpp::SHT_NOBITS
+ && (os->flags() & elfcpp::SHF_TLS) == 0);
+}
+
+// Return the size taken by the file header and the program headers.
+
+size_t
+Script_sections::total_header_size(Layout* layout) const
+{
+ size_t segment_count = layout->segment_count();
+ size_t file_header_size;
+ size_t segment_headers_size;
+ if (parameters->target().get_size() == 32)
+ {
+ file_header_size = elfcpp::Elf_sizes<32>::ehdr_size;
+ segment_headers_size = segment_count * elfcpp::Elf_sizes<32>::phdr_size;
+ }
+ else if (parameters->target().get_size() == 64)
+ {
+ file_header_size = elfcpp::Elf_sizes<64>::ehdr_size;
+ segment_headers_size = segment_count * elfcpp::Elf_sizes<64>::phdr_size;
+ }
+ else
+ gold_unreachable();
+
+ return file_header_size + segment_headers_size;
+}
+
+// Return the amount we have to subtract from the LMA to accommodate
+// headers of the given size. The complication is that the file
+// header have to be at the start of a page, as otherwise it will not
+// be at the start of the file.
+
+uint64_t
+Script_sections::header_size_adjustment(uint64_t lma,
+ size_t sizeof_headers) const
+{
+ const uint64_t abi_pagesize = parameters->target().abi_pagesize();
+ uint64_t hdr_lma = lma - sizeof_headers;
+ hdr_lma &= ~(abi_pagesize - 1);
+ return lma - hdr_lma;
+}
+
+// Create the PT_LOAD segments when using a SECTIONS clause. Returns
+// the segment which should hold the file header and segment headers,
+// if any.
+
+Output_segment*
+Script_sections::create_segments(Layout* layout, uint64_t dot_alignment)
+{
+ gold_assert(this->saw_sections_clause_);
+
+ if (parameters->options().relocatable())
+ return NULL;
+
+ if (this->saw_phdrs_clause())
+ return create_segments_from_phdrs_clause(layout, dot_alignment);
+
+ Layout::Section_list sections;
+ layout->get_allocated_sections(&sections);
+
+ // Sort the sections by address.
+ std::stable_sort(sections.begin(), sections.end(),
+ Sort_output_sections(this->sections_elements_));
+
+ this->create_note_and_tls_segments(layout, &sections);
+
+ // Walk through the sections adding them to PT_LOAD segments.
+ const uint64_t abi_pagesize = parameters->target().abi_pagesize();
+ Output_segment* first_seg = NULL;
+ Output_segment* current_seg = NULL;
+ bool is_current_seg_readonly = true;
+ Layout::Section_list::iterator plast = sections.end();
+ uint64_t last_vma = 0;
+ uint64_t last_lma = 0;
+ uint64_t last_size = 0;
+ for (Layout::Section_list::iterator p = sections.begin();
+ p != sections.end();
+ ++p)
+ {
+ const uint64_t vma = (*p)->address();
+ const uint64_t lma = ((*p)->has_load_address()
+ ? (*p)->load_address()
+ : vma);
+ const uint64_t size = (*p)->current_data_size();
+
+ bool need_new_segment;
+ if (current_seg == NULL)
+ need_new_segment = true;
+ else if (lma - vma != last_lma - last_vma)
+ {
+ // This section has a different LMA relationship than the
+ // last one; we need a new segment.
+ need_new_segment = true;
+ }
+ else if (align_address(last_lma + last_size, abi_pagesize)
+ < align_address(lma, abi_pagesize))
+ {
+ // Putting this section in the segment would require
+ // skipping a page.
+ need_new_segment = true;
+ }
+ else if (is_bss_section(*plast) && !is_bss_section(*p))
+ {
+ // A non-BSS section can not follow a BSS section in the
+ // same segment.
+ need_new_segment = true;
+ }
+ else if (is_current_seg_readonly
+ && ((*p)->flags() & elfcpp::SHF_WRITE) != 0
+ && !parameters->options().omagic())
+ {
+ // Don't put a writable section in the same segment as a
+ // non-writable section.
+ need_new_segment = true;
+ }
+ else
+ {
+ // Otherwise, reuse the existing segment.
+ need_new_segment = false;
+ }
+
+ elfcpp::Elf_Word seg_flags =
+ Layout::section_flags_to_segment((*p)->flags());
+
+ if (need_new_segment)
+ {
+ current_seg = layout->make_output_segment(elfcpp::PT_LOAD,
+ seg_flags);
+ current_seg->set_addresses(vma, lma);
+ current_seg->set_minimum_p_align(dot_alignment);
+ if (first_seg == NULL)
+ first_seg = current_seg;
+ is_current_seg_readonly = true;
+ }
+
+ current_seg->add_output_section_to_load(layout, *p, seg_flags);
+
+ if (((*p)->flags() & elfcpp::SHF_WRITE) != 0)
+ is_current_seg_readonly = false;
+
+ plast = p;
+ last_vma = vma;
+ last_lma = lma;
+ last_size = size;
+ }
+
+ // An ELF program should work even if the program headers are not in
+ // a PT_LOAD segment. However, it appears that the Linux kernel
+ // does not set the AT_PHDR auxiliary entry in that case. It sets
+ // the load address to p_vaddr - p_offset of the first PT_LOAD
+ // segment. It then sets AT_PHDR to the load address plus the
+ // offset to the program headers, e_phoff in the file header. This
+ // fails when the program headers appear in the file before the
+ // first PT_LOAD segment. Therefore, we always create a PT_LOAD
+ // segment to hold the file header and the program headers. This is
+ // effectively what the GNU linker does, and it is slightly more
+ // efficient in any case. We try to use the first PT_LOAD segment
+ // if we can, otherwise we make a new one.
+
+ if (first_seg == NULL)
+ return NULL;
+
+ // -n or -N mean that the program is not demand paged and there is
+ // no need to put the program headers in a PT_LOAD segment.
+ if (parameters->options().nmagic() || parameters->options().omagic())
+ return NULL;
+
+ size_t sizeof_headers = this->total_header_size(layout);
+
+ uint64_t vma = first_seg->vaddr();
+ uint64_t lma = first_seg->paddr();
+
+ uint64_t subtract = this->header_size_adjustment(lma, sizeof_headers);
+
+ if ((lma & (abi_pagesize - 1)) >= sizeof_headers)
+ {
+ first_seg->set_addresses(vma - subtract, lma - subtract);
+ return first_seg;
+ }
+
+ // If there is no room to squeeze in the headers, then punt. The
+ // resulting executable probably won't run on GNU/Linux, but we
+ // trust that the user knows what they are doing.
+ if (lma < subtract || vma < subtract)
+ return NULL;
+
+ // If memory regions have been specified and the address range
+ // we are about to use is not contained within any region then
+ // issue a warning message about the segment we are going to
+ // create. It will be outside of any region and so possibly
+ // using non-existent or protected memory. We test LMA rather
+ // than VMA since we assume that the headers will never be
+ // relocated.
+ if (this->memory_regions_ != NULL
+ && !this->block_in_region (NULL, layout, lma - subtract, subtract))
+ gold_warning(_("creating a segment to contain the file and program"
+ " headers outside of any MEMORY region"));
+
+ Output_segment* load_seg = layout->make_output_segment(elfcpp::PT_LOAD,
+ elfcpp::PF_R);
+ load_seg->set_addresses(vma - subtract, lma - subtract);
+
+ return load_seg;
+}
+
+// Create a PT_NOTE segment for each SHT_NOTE section and a PT_TLS
+// segment if there are any SHT_TLS sections.
+
+void
+Script_sections::create_note_and_tls_segments(
+ Layout* layout,
+ const Layout::Section_list* sections)
+{
+ gold_assert(!this->saw_phdrs_clause());
+
+ bool saw_tls = false;
+ for (Layout::Section_list::const_iterator p = sections->begin();
+ p != sections->end();
+ ++p)
+ {
+ if ((*p)->type() == elfcpp::SHT_NOTE)
+ {
+ elfcpp::Elf_Word seg_flags =
+ Layout::section_flags_to_segment((*p)->flags());
+ Output_segment* oseg = layout->make_output_segment(elfcpp::PT_NOTE,
+ seg_flags);
+ oseg->add_output_section_to_nonload(*p, seg_flags);
+
+ // Incorporate any subsequent SHT_NOTE sections, in the
+ // hopes that the script is sensible.
+ Layout::Section_list::const_iterator pnext = p + 1;
+ while (pnext != sections->end()
+ && (*pnext)->type() == elfcpp::SHT_NOTE)
+ {
+ seg_flags = Layout::section_flags_to_segment((*pnext)->flags());
+ oseg->add_output_section_to_nonload(*pnext, seg_flags);
+ p = pnext;
+ ++pnext;
+ }
+ }
+
+ if (((*p)->flags() & elfcpp::SHF_TLS) != 0)
+ {
+ if (saw_tls)
+ gold_error(_("TLS sections are not adjacent"));
+
+ elfcpp::Elf_Word seg_flags =
+ Layout::section_flags_to_segment((*p)->flags());
+ Output_segment* oseg = layout->make_output_segment(elfcpp::PT_TLS,
+ seg_flags);
+ oseg->add_output_section_to_nonload(*p, seg_flags);
+
+ Layout::Section_list::const_iterator pnext = p + 1;
+ while (pnext != sections->end()
+ && ((*pnext)->flags() & elfcpp::SHF_TLS) != 0)
+ {
+ seg_flags = Layout::section_flags_to_segment((*pnext)->flags());
+ oseg->add_output_section_to_nonload(*pnext, seg_flags);
+ p = pnext;
+ ++pnext;
+ }
+
+ saw_tls = true;
+ }
+
+ // If we are making a shared library, and we see a section named
+ // .interp then put the .interp section in a PT_INTERP segment.
+ // This is for GNU ld compatibility.
+ if (strcmp((*p)->name(), ".interp") == 0)
+ {
+ elfcpp::Elf_Word seg_flags =
+ Layout::section_flags_to_segment((*p)->flags());
+ Output_segment* oseg = layout->make_output_segment(elfcpp::PT_INTERP,
+ seg_flags);
+ oseg->add_output_section_to_nonload(*p, seg_flags);
+ }
+ }
+}
+
+// Add a program header. The PHDRS clause is syntactically distinct
+// from the SECTIONS clause, but we implement it with the SECTIONS
+// support because PHDRS is useless if there is no SECTIONS clause.
+
+void
+Script_sections::add_phdr(const char* name, size_t namelen, unsigned int type,
+ bool includes_filehdr, bool includes_phdrs,
+ bool is_flags_valid, unsigned int flags,
+ Expression* load_address)
+{
+ if (this->phdrs_elements_ == NULL)
+ this->phdrs_elements_ = new Phdrs_elements();
+ this->phdrs_elements_->push_back(new Phdrs_element(name, namelen, type,
+ includes_filehdr,
+ includes_phdrs,
+ is_flags_valid, flags,
+ load_address));
+}
+
+// Return the number of segments we expect to create based on the
+// SECTIONS clause. This is used to implement SIZEOF_HEADERS.
+
+size_t
+Script_sections::expected_segment_count(const Layout* layout) const
+{
+ if (this->saw_phdrs_clause())
+ return this->phdrs_elements_->size();
+
+ Layout::Section_list sections;
+ layout->get_allocated_sections(&sections);
+
+ // We assume that we will need two PT_LOAD segments.
+ size_t ret = 2;
+
+ bool saw_note = false;
+ bool saw_tls = false;
+ for (Layout::Section_list::const_iterator p = sections.begin();
+ p != sections.end();
+ ++p)
+ {
+ if ((*p)->type() == elfcpp::SHT_NOTE)
+ {
+ // Assume that all note sections will fit into a single
+ // PT_NOTE segment.
+ if (!saw_note)
+ {
+ ++ret;
+ saw_note = true;
+ }
+ }
+ else if (((*p)->flags() & elfcpp::SHF_TLS) != 0)
+ {
+ // There can only be one PT_TLS segment.
+ if (!saw_tls)
+ {
+ ++ret;
+ saw_tls = true;
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Create the segments from a PHDRS clause. Return the segment which
+// should hold the file header and program headers, if any.
+
+Output_segment*
+Script_sections::create_segments_from_phdrs_clause(Layout* layout,
+ uint64_t dot_alignment)
+{
+ this->attach_sections_using_phdrs_clause(layout);
+ return this->set_phdrs_clause_addresses(layout, dot_alignment);
+}
+
+// Create the segments from the PHDRS clause, and put the output
+// sections in them.
+
+void
+Script_sections::attach_sections_using_phdrs_clause(Layout* layout)
+{
+ typedef std::map<std::string, Output_segment*> Name_to_segment;
+ Name_to_segment name_to_segment;
+ for (Phdrs_elements::const_iterator p = this->phdrs_elements_->begin();
+ p != this->phdrs_elements_->end();
+ ++p)
+ name_to_segment[(*p)->name()] = (*p)->create_segment(layout);
+
+ // Walk through the output sections and attach them to segments.
+ // Output sections in the script which do not list segments are
+ // attached to the same set of segments as the immediately preceding
+ // output section.
+
+ String_list* phdr_names = NULL;
+ bool load_segments_only = false;
+ for (Sections_elements::const_iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ {
+ bool is_orphan;
+ String_list* old_phdr_names = phdr_names;
+ Output_section* os = (*p)->allocate_to_segment(&phdr_names, &is_orphan);
+ if (os == NULL)
+ continue;
+
+ elfcpp::Elf_Word seg_flags =
+ Layout::section_flags_to_segment(os->flags());
+
+ if (phdr_names == NULL)
+ {
+ // Don't worry about empty orphan sections.
+ if (is_orphan && os->current_data_size() > 0)
+ gold_error(_("allocated section %s not in any segment"),
+ os->name());
+
+ // To avoid later crashes drop this section into the first
+ // PT_LOAD segment.
+ for (Phdrs_elements::const_iterator ppe =
+ this->phdrs_elements_->begin();
+ ppe != this->phdrs_elements_->end();
+ ++ppe)
+ {
+ Output_segment* oseg = (*ppe)->segment();
+ if (oseg->type() == elfcpp::PT_LOAD)
+ {
+ oseg->add_output_section_to_load(layout, os, seg_flags);
+ break;
+ }
+ }
+
+ continue;
+ }
+
+ // We see a list of segments names. Disable PT_LOAD segment only
+ // filtering.
+ if (old_phdr_names != phdr_names)
+ load_segments_only = false;
+
+ // If this is an orphan section--one that was not explicitly
+ // mentioned in the linker script--then it should not inherit
+ // any segment type other than PT_LOAD. Otherwise, e.g., the
+ // PT_INTERP segment will pick up following orphan sections,
+ // which does not make sense. If this is not an orphan section,
+ // we trust the linker script.
+ if (is_orphan)
+ {
+ // Enable PT_LOAD segments only filtering until we see another
+ // list of segment names.
+ load_segments_only = true;
+ }
+
+ bool in_load_segment = false;
+ for (String_list::const_iterator q = phdr_names->begin();
+ q != phdr_names->end();
+ ++q)
+ {
+ Name_to_segment::const_iterator r = name_to_segment.find(*q);
+ if (r == name_to_segment.end())
+ gold_error(_("no segment %s"), q->c_str());
+ else
+ {
+ if (load_segments_only
+ && r->second->type() != elfcpp::PT_LOAD)
+ continue;
+
+ if (r->second->type() != elfcpp::PT_LOAD)
+ r->second->add_output_section_to_nonload(os, seg_flags);
+ else
+ {
+ r->second->add_output_section_to_load(layout, os, seg_flags);
+ if (in_load_segment)
+ gold_error(_("section in two PT_LOAD segments"));
+ in_load_segment = true;
+ }
+ }
+ }
+
+ if (!in_load_segment)
+ gold_error(_("allocated section not in any PT_LOAD segment"));
+ }
+}
+
+// Set the addresses for segments created from a PHDRS clause. Return
+// the segment which should hold the file header and program headers,
+// if any.
+
+Output_segment*
+Script_sections::set_phdrs_clause_addresses(Layout* layout,
+ uint64_t dot_alignment)
+{
+ Output_segment* load_seg = NULL;
+ for (Phdrs_elements::const_iterator p = this->phdrs_elements_->begin();
+ p != this->phdrs_elements_->end();
+ ++p)
+ {
+ // Note that we have to set the flags after adding the output
+ // sections to the segment, as adding an output segment can
+ // change the flags.
+ (*p)->set_flags_if_valid();
+
+ Output_segment* oseg = (*p)->segment();
+
+ if (oseg->type() != elfcpp::PT_LOAD)
+ {
+ // The addresses of non-PT_LOAD segments are set from the
+ // PT_LOAD segments.
+ if ((*p)->has_load_address())
+ gold_error(_("may only specify load address for PT_LOAD segment"));
+ continue;
+ }
+
+ oseg->set_minimum_p_align(dot_alignment);
+
+ // The output sections should have addresses from the SECTIONS
+ // clause. The addresses don't have to be in order, so find the
+ // one with the lowest load address. Use that to set the
+ // address of the segment.
+
+ Output_section* osec = oseg->section_with_lowest_load_address();
+ if (osec == NULL)
+ {
+ oseg->set_addresses(0, 0);
+ continue;
+ }
+
+ uint64_t vma = osec->address();
+ uint64_t lma = osec->has_load_address() ? osec->load_address() : vma;
+
+ // Override the load address of the section with the load
+ // address specified for the segment.
+ if ((*p)->has_load_address())
+ {
+ if (osec->has_load_address())
+ gold_warning(_("PHDRS load address overrides "
+ "section %s load address"),
+ osec->name());
+
+ lma = (*p)->load_address();
+ }
+
+ bool headers = (*p)->includes_filehdr() && (*p)->includes_phdrs();
+ if (!headers && ((*p)->includes_filehdr() || (*p)->includes_phdrs()))
+ {
+ // We could support this if we wanted to.
+ gold_error(_("using only one of FILEHDR and PHDRS is "
+ "not currently supported"));
+ }
+ if (headers)
+ {
+ size_t sizeof_headers = this->total_header_size(layout);
+ uint64_t subtract = this->header_size_adjustment(lma,
+ sizeof_headers);
+ if (lma >= subtract && vma >= subtract)
+ {
+ lma -= subtract;
+ vma -= subtract;
+ }
+ else
+ {
+ gold_error(_("sections loaded on first page without room "
+ "for file and program headers "
+ "are not supported"));
+ }
+
+ if (load_seg != NULL)
+ gold_error(_("using FILEHDR and PHDRS on more than one "
+ "PT_LOAD segment is not currently supported"));
+ load_seg = oseg;
+ }
+
+ oseg->set_addresses(vma, lma);
+ }
+
+ return load_seg;
+}
+
+// Add the file header and segment headers to non-load segments
+// specified in the PHDRS clause.
+
+void
+Script_sections::put_headers_in_phdrs(Output_data* file_header,
+ Output_data* segment_headers)
+{
+ gold_assert(this->saw_phdrs_clause());
+ for (Phdrs_elements::iterator p = this->phdrs_elements_->begin();
+ p != this->phdrs_elements_->end();
+ ++p)
+ {
+ if ((*p)->type() != elfcpp::PT_LOAD)
+ {
+ if ((*p)->includes_phdrs())
+ (*p)->segment()->add_initial_output_data(segment_headers);
+ if ((*p)->includes_filehdr())
+ (*p)->segment()->add_initial_output_data(file_header);
+ }
+ }
+}
+
+// Look for an output section by name and return the address, the load
+// address, the alignment, and the size. This is used when an
+// expression refers to an output section which was not actually
+// created. This returns true if the section was found, false
+// otherwise.
+
+bool
+Script_sections::get_output_section_info(const char* name, uint64_t* address,
+ uint64_t* load_address,
+ uint64_t* addralign,
+ uint64_t* size) const
+{
+ if (!this->saw_sections_clause_)
+ return false;
+ for (Sections_elements::const_iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ if ((*p)->get_output_section_info(name, address, load_address, addralign,
+ size))
+ return true;
+ return false;
+}
+
+// Release all Output_segments. This remove all pointers to all
+// Output_segments.
+
+void
+Script_sections::release_segments()
+{
+ if (this->saw_phdrs_clause())
+ {
+ for (Phdrs_elements::const_iterator p = this->phdrs_elements_->begin();
+ p != this->phdrs_elements_->end();
+ ++p)
+ (*p)->release_segment();
+ }
+}
+
+// Print the SECTIONS clause to F for debugging.
+
+void
+Script_sections::print(FILE* f) const
+{
+ if (this->phdrs_elements_ != NULL)
+ {
+ fprintf(f, "PHDRS {\n");
+ for (Phdrs_elements::const_iterator p = this->phdrs_elements_->begin();
+ p != this->phdrs_elements_->end();
+ ++p)
+ (*p)->print(f);
+ fprintf(f, "}\n");
+ }
+
+ if (this->memory_regions_ != NULL)
+ {
+ fprintf(f, "MEMORY {\n");
+ for (Memory_regions::const_iterator m = this->memory_regions_->begin();
+ m != this->memory_regions_->end();
+ ++m)
+ (*m)->print(f);
+ fprintf(f, "}\n");
+ }
+
+ if (!this->saw_sections_clause_)
+ return;
+
+ fprintf(f, "SECTIONS {\n");
+
+ for (Sections_elements::const_iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ (*p)->print(f);
+
+ fprintf(f, "}\n");
+}
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/script-sections.h b/binutils-2.25/gold/script-sections.h
new file mode 100644
index 00000000..9ff44ea3
--- /dev/null
+++ b/binutils-2.25/gold/script-sections.h
@@ -0,0 +1,337 @@
+// script-sections.h -- linker script SECTIONS for gold -*- C++ -*-
+
+// Copyright 2008, 2009 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 is for the support of the SECTIONS clause in linker scripts.
+
+#ifndef GOLD_SCRIPT_SECTIONS_H
+#define GOLD_SCRIPT_SECTIONS_H
+
+#include <cstdio>
+#include <list>
+#include <vector>
+
+namespace gold
+{
+
+struct Parser_output_section_header;
+struct Parser_output_section_trailer;
+struct Input_section_spec;
+class Expression;
+class Sections_element;
+class Memory_region;
+class Phdrs_element;
+class Output_data;
+class Output_section_definition;
+class Output_section;
+class Output_segment;
+class Orphan_section_placement;
+
+class Script_sections
+{
+ public:
+ // This is a list, not a vector, because we insert orphan sections
+ // in the middle.
+ typedef std::list<Sections_element*> Sections_elements;
+
+ // Logical script section types. We map section types returned by the
+ // parser into these since some section types have the same semantics.
+ enum Section_type
+ {
+ // No section type specified.
+ ST_NONE,
+ // Section is NOLOAD. We allocate space in the output but section
+ // is not loaded in runtime.
+ ST_NOLOAD,
+ // No space is allocated to section.
+ ST_NOALLOC
+ };
+
+ Script_sections();
+
+ // Start a SECTIONS clause.
+ void
+ start_sections();
+
+ // Finish a SECTIONS clause.
+ void
+ finish_sections();
+
+ // Return whether we ever saw a SECTIONS clause. If we did, then
+ // all section layout needs to go through this class.
+ bool
+ saw_sections_clause() const
+ { return this->saw_sections_clause_; }
+
+ // Return whether we are currently processing a SECTIONS clause.
+ bool
+ in_sections_clause() const
+ { return this->in_sections_clause_; }
+
+ // Return whether we ever saw a PHDRS clause. We ignore the PHDRS
+ // clause unless we also saw a SECTIONS clause.
+ bool
+ saw_phdrs_clause() const
+ { return this->saw_sections_clause_ && this->phdrs_elements_ != NULL; }
+
+ // Start processing entries for an output section.
+ void
+ start_output_section(const char* name, size_t namelen,
+ const Parser_output_section_header*);
+
+ // Finish processing entries for an output section.
+ void
+ finish_output_section(const Parser_output_section_trailer*);
+
+ // Add a data item to the current output section.
+ void
+ add_data(int size, bool is_signed, Expression* val);
+
+ // Add a symbol to be defined.
+ void
+ add_symbol_assignment(const char* name, size_t length, Expression* value,
+ bool provide, bool hidden);
+
+ // Add an assignment to the special dot symbol.
+ void
+ add_dot_assignment(Expression* value);
+
+ // Add an assertion.
+ void
+ add_assertion(Expression* check, const char* message, size_t messagelen);
+
+ // Add a setting for the fill value.
+ void
+ add_fill(Expression* val);
+
+ // Add an input section specification.
+ void
+ add_input_section(const Input_section_spec* spec, bool keep);
+
+ // Saw DATA_SEGMENT_ALIGN.
+ void
+ data_segment_align();
+
+ // Saw DATA_SEGMENT_RELRO_END.
+ void
+ data_segment_relro_end();
+
+ // Create any required sections.
+ void
+ create_sections(Layout*);
+
+ // Add any symbols we are defining to the symbol table.
+ void
+ add_symbols_to_table(Symbol_table*);
+
+ // Finalize symbol values and check assertions.
+ void
+ finalize_symbols(Symbol_table* symtab, const Layout* layout);
+
+ // Find the name of the output section to use for an input file name
+ // and section name. This returns a name, and sets
+ // *OUTPUT_SECTION_SLOT to point to the address where the actual
+ // output section may be stored.
+ // 1) If the input section should be discarded, this returns NULL
+ // and sets *OUTPUT_SECTION_SLOT to NULL.
+ // 2) If the input section is mapped by the SECTIONS clause, this
+ // returns the name to use for the output section (in permanent
+ // storage), and sets *OUTPUT_SECTION_SLOT to point to where the
+ // output section should be stored. **OUTPUT_SECTION_SLOT will be
+ // non-NULL if we have seen this output section already.
+ // 3) If the input section is not mapped by the SECTIONS clause,
+ // this returns SECTION_NAME, and sets *OUTPUT_SECTION_SLOT to
+ // NULL.
+ // PSCRIPT_SECTION_TYPE points to a location for returning the section
+ // type specified in script. This can be SCRIPT_SECTION_TYPE_NONE if
+ // no type is specified.
+ // *KEEP indicates whether the section should survive garbage collection.
+ const char*
+ output_section_name(const char* file_name, const char* section_name,
+ Output_section*** output_section_slot,
+ Section_type* pscript_section_type,
+ bool* keep);
+
+ // Place a marker for an orphan output section into the SECTIONS
+ // clause.
+ void
+ place_orphan(Output_section* os);
+
+ // Set the addresses of all the output sections. Return the segment
+ // which holds the file header and segment headers, if any.
+ Output_segment*
+ set_section_addresses(Symbol_table*, Layout*);
+
+ // Add a program header definition.
+ void
+ add_phdr(const char* name, size_t namelen, unsigned int type,
+ bool filehdr, bool phdrs, bool is_flags_valid, unsigned int flags,
+ Expression* load_address);
+
+ // Return the number of segments we expect to create based on the
+ // SECTIONS clause.
+ size_t
+ expected_segment_count(const Layout*) const;
+
+ // Add the file header and segment header to non-load segments as
+ // specified by the PHDRS clause.
+ void
+ put_headers_in_phdrs(Output_data* file_header, Output_data* segment_headers);
+
+ // Look for an output section by name and return the address, the
+ // load address, the alignment, and the size. This is used when an
+ // expression refers to an output section which was not actually
+ // created. This returns true if the section was found, false
+ // otherwise.
+ bool
+ get_output_section_info(const char* name, uint64_t* address,
+ uint64_t* load_address, uint64_t* addralign,
+ uint64_t* size) const;
+
+ // Release all Output_segments. This is used in relaxation.
+ void
+ release_segments();
+
+ // Whether we ever saw a SEGMENT_START expression, the presence of which
+ // changes the behaviour of -Ttext, -Tdata and -Tbss options.
+ bool
+ saw_segment_start_expression() const
+ { return this->saw_segment_start_expression_; }
+
+ // Set the flag which indicates whether we saw a SEGMENT_START expression.
+ void
+ set_saw_segment_start_expression(bool value)
+ { this->saw_segment_start_expression_ = value; }
+
+ // Add a memory region.
+ void
+ add_memory_region(const char*, size_t, unsigned int,
+ Expression*, Expression*);
+
+ // Find a memory region's origin.
+ Expression*
+ find_memory_region_origin(const char*, size_t);
+
+ // Find a memory region's length.
+ Expression*
+ find_memory_region_length(const char*, size_t);
+
+ // Find a memory region by name.
+ Memory_region*
+ find_memory_region(const char*, size_t);
+
+ // Find a memory region that should be used by a given output section.
+ Memory_region*
+ find_memory_region(Output_section_definition*, bool,
+ Output_section_definition**);
+
+ // Returns true if the provide block of memory is contained
+ // within a memory region.
+ bool
+ block_in_region(Symbol_table*, Layout*, uint64_t, uint64_t) const;
+
+ // Set the memory region of the section.
+ void
+ set_memory_region(Memory_region*, bool);
+
+ // Print the contents to the FILE. This is for debugging.
+ void
+ print(FILE*) const;
+
+ // Used for orphan sections.
+ typedef Sections_elements::iterator Elements_iterator;
+
+ private:
+ typedef std::vector<Memory_region*> Memory_regions;
+ typedef std::vector<Phdrs_element*> Phdrs_elements;
+
+ // Create segments.
+ Output_segment*
+ create_segments(Layout*, uint64_t);
+
+ // Create PT_NOTE and PT_TLS segments.
+ void
+ create_note_and_tls_segments(Layout*, const std::vector<Output_section*>*);
+
+ // Return whether the section is a BSS section.
+ static bool
+ is_bss_section(const Output_section*);
+
+ // Return the total size of the headers.
+ size_t
+ total_header_size(Layout* layout) const;
+
+ // Return the amount we have to subtract from the LMA to accomodate
+ // headers of the given size.
+ uint64_t
+ header_size_adjustment(uint64_t lma, size_t sizeof_headers) const;
+
+ // Create the segments from a PHDRS clause.
+ Output_segment*
+ create_segments_from_phdrs_clause(Layout* layout, uint64_t);
+
+ // Attach sections to segments from a PHDRS clause.
+ void
+ attach_sections_using_phdrs_clause(Layout*);
+
+ // Set addresses of segments from a PHDRS clause.
+ Output_segment*
+ set_phdrs_clause_addresses(Layout*, uint64_t);
+
+ // True if we ever saw a SECTIONS clause.
+ bool saw_sections_clause_;
+ // True if we are currently processing a SECTIONS clause.
+ bool in_sections_clause_;
+ // The list of elements in the SECTIONS clause.
+ Sections_elements* sections_elements_;
+ // The current output section, if there is one.
+ Output_section_definition* output_section_;
+ // The list of memory regions in the MEMORY clause.
+ Memory_regions* memory_regions_;
+ // The list of program headers in the PHDRS clause.
+ Phdrs_elements* phdrs_elements_;
+ // Where to put orphan sections.
+ Orphan_section_placement* orphan_section_placement_;
+ // A pointer to the last Sections_element when we see
+ // DATA_SEGMENT_ALIGN.
+ Sections_elements::iterator data_segment_align_start_;
+ // Whether we have seen DATA_SEGMENT_ALIGN.
+ bool saw_data_segment_align_;
+ // Whether we have seen DATA_SEGMENT_RELRO_END.
+ bool saw_relro_end_;
+ // Whether we have seen SEGMENT_START.
+ bool saw_segment_start_expression_;
+};
+
+// Attributes for memory regions.
+enum
+{
+ MEM_EXECUTABLE = (1 << 0),
+ MEM_WRITEABLE = (1 << 1),
+ MEM_READABLE = (1 << 2),
+ MEM_ALLOCATABLE = (1 << 3),
+ MEM_INITIALIZED = (1 << 4),
+ MEM_ATTR_MASK = (1 << 5) - 1
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_SCRIPT_SECTIONS_H
diff --git a/binutils-2.25/gold/script.cc b/binutils-2.25/gold/script.cc
new file mode 100644
index 00000000..6a10c40e
--- /dev/null
+++ b/binutils-2.25/gold/script.cc
@@ -0,0 +1,3409 @@
+// script.cc -- handle linker scripts for gold.
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include "gold.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fnmatch.h>
+#include <string>
+#include <vector>
+#include "filenames.h"
+
+#include "elfcpp.h"
+#include "demangle.h"
+#include "dirsearch.h"
+#include "options.h"
+#include "fileread.h"
+#include "workqueue.h"
+#include "readsyms.h"
+#include "parameters.h"
+#include "layout.h"
+#include "symtab.h"
+#include "target-select.h"
+#include "script.h"
+#include "script-c.h"
+#include "incremental.h"
+
+namespace gold
+{
+
+// A token read from a script file. We don't implement keywords here;
+// all keywords are simply represented as a string.
+
+class Token
+{
+ public:
+ // Token classification.
+ enum Classification
+ {
+ // Token is invalid.
+ TOKEN_INVALID,
+ // Token indicates end of input.
+ TOKEN_EOF,
+ // Token is a string of characters.
+ TOKEN_STRING,
+ // Token is a quoted string of characters.
+ TOKEN_QUOTED_STRING,
+ // Token is an operator.
+ TOKEN_OPERATOR,
+ // Token is a number (an integer).
+ TOKEN_INTEGER
+ };
+
+ // We need an empty constructor so that we can put this STL objects.
+ Token()
+ : classification_(TOKEN_INVALID), value_(NULL), value_length_(0),
+ opcode_(0), lineno_(0), charpos_(0)
+ { }
+
+ // A general token with no value.
+ Token(Classification classification, int lineno, int charpos)
+ : classification_(classification), value_(NULL), value_length_(0),
+ opcode_(0), lineno_(lineno), charpos_(charpos)
+ {
+ gold_assert(classification == TOKEN_INVALID
+ || classification == TOKEN_EOF);
+ }
+
+ // A general token with a value.
+ Token(Classification classification, const char* value, size_t length,
+ int lineno, int charpos)
+ : classification_(classification), value_(value), value_length_(length),
+ opcode_(0), lineno_(lineno), charpos_(charpos)
+ {
+ gold_assert(classification != TOKEN_INVALID
+ && classification != TOKEN_EOF);
+ }
+
+ // A token representing an operator.
+ Token(int opcode, int lineno, int charpos)
+ : classification_(TOKEN_OPERATOR), value_(NULL), value_length_(0),
+ opcode_(opcode), lineno_(lineno), charpos_(charpos)
+ { }
+
+ // Return whether the token is invalid.
+ bool
+ is_invalid() const
+ { return this->classification_ == TOKEN_INVALID; }
+
+ // Return whether this is an EOF token.
+ bool
+ is_eof() const
+ { return this->classification_ == TOKEN_EOF; }
+
+ // Return the token classification.
+ Classification
+ classification() const
+ { return this->classification_; }
+
+ // Return the line number at which the token starts.
+ int
+ lineno() const
+ { return this->lineno_; }
+
+ // Return the character position at this the token starts.
+ int
+ charpos() const
+ { return this->charpos_; }
+
+ // Get the value of a token.
+
+ const char*
+ string_value(size_t* length) const
+ {
+ gold_assert(this->classification_ == TOKEN_STRING
+ || this->classification_ == TOKEN_QUOTED_STRING);
+ *length = this->value_length_;
+ return this->value_;
+ }
+
+ int
+ operator_value() const
+ {
+ gold_assert(this->classification_ == TOKEN_OPERATOR);
+ return this->opcode_;
+ }
+
+ uint64_t
+ integer_value() const;
+
+ private:
+ // The token classification.
+ Classification classification_;
+ // The token value, for TOKEN_STRING or TOKEN_QUOTED_STRING or
+ // TOKEN_INTEGER.
+ const char* value_;
+ // The length of the token value.
+ size_t value_length_;
+ // The token value, for TOKEN_OPERATOR.
+ int opcode_;
+ // The line number where this token started (one based).
+ int lineno_;
+ // The character position within the line where this token started
+ // (one based).
+ int charpos_;
+};
+
+// Return the value of a TOKEN_INTEGER.
+
+uint64_t
+Token::integer_value() const
+{
+ gold_assert(this->classification_ == TOKEN_INTEGER);
+
+ size_t len = this->value_length_;
+
+ uint64_t multiplier = 1;
+ char last = this->value_[len - 1];
+ if (last == 'm' || last == 'M')
+ {
+ multiplier = 1024 * 1024;
+ --len;
+ }
+ else if (last == 'k' || last == 'K')
+ {
+ multiplier = 1024;
+ --len;
+ }
+
+ char *end;
+ uint64_t ret = strtoull(this->value_, &end, 0);
+ gold_assert(static_cast<size_t>(end - this->value_) == len);
+
+ return ret * multiplier;
+}
+
+// This class handles lexing a file into a sequence of tokens.
+
+class Lex
+{
+ public:
+ // We unfortunately have to support different lexing modes, because
+ // when reading different parts of a linker script we need to parse
+ // things differently.
+ enum Mode
+ {
+ // Reading an ordinary linker script.
+ LINKER_SCRIPT,
+ // Reading an expression in a linker script.
+ EXPRESSION,
+ // Reading a version script.
+ VERSION_SCRIPT,
+ // Reading a --dynamic-list file.
+ DYNAMIC_LIST
+ };
+
+ Lex(const char* input_string, size_t input_length, int parsing_token)
+ : input_string_(input_string), input_length_(input_length),
+ current_(input_string), mode_(LINKER_SCRIPT),
+ first_token_(parsing_token), token_(),
+ lineno_(1), linestart_(input_string)
+ { }
+
+ // Read a file into a string.
+ static void
+ read_file(Input_file*, std::string*);
+
+ // Return the next token.
+ const Token*
+ next_token();
+
+ // Return the current lexing mode.
+ Lex::Mode
+ mode() const
+ { return this->mode_; }
+
+ // Set the lexing mode.
+ void
+ set_mode(Mode mode)
+ { this->mode_ = mode; }
+
+ private:
+ Lex(const Lex&);
+ Lex& operator=(const Lex&);
+
+ // Make a general token with no value at the current location.
+ Token
+ make_token(Token::Classification c, const char* start) const
+ { return Token(c, this->lineno_, start - this->linestart_ + 1); }
+
+ // Make a general token with a value at the current location.
+ Token
+ make_token(Token::Classification c, const char* v, size_t len,
+ const char* start)
+ const
+ { return Token(c, v, len, this->lineno_, start - this->linestart_ + 1); }
+
+ // Make an operator token at the current location.
+ Token
+ make_token(int opcode, const char* start) const
+ { return Token(opcode, this->lineno_, start - this->linestart_ + 1); }
+
+ // Make an invalid token at the current location.
+ Token
+ make_invalid_token(const char* start)
+ { return this->make_token(Token::TOKEN_INVALID, start); }
+
+ // Make an EOF token at the current location.
+ Token
+ make_eof_token(const char* start)
+ { return this->make_token(Token::TOKEN_EOF, start); }
+
+ // Return whether C can be the first character in a name. C2 is the
+ // next character, since we sometimes need that.
+ inline bool
+ can_start_name(char c, char c2);
+
+ // If C can appear in a name which has already started, return a
+ // pointer to a character later in the token or just past
+ // it. Otherwise, return NULL.
+ inline const char*
+ can_continue_name(const char* c);
+
+ // Return whether C, C2, C3 can start a hex number.
+ inline bool
+ can_start_hex(char c, char c2, char c3);
+
+ // If C can appear in a hex number which has already started, return
+ // a pointer to a character later in the token or just past
+ // it. Otherwise, return NULL.
+ inline const char*
+ can_continue_hex(const char* c);
+
+ // Return whether C can start a non-hex number.
+ static inline bool
+ can_start_number(char c);
+
+ // If C can appear in a decimal number which has already started,
+ // return a pointer to a character later in the token or just past
+ // it. Otherwise, return NULL.
+ inline const char*
+ can_continue_number(const char* c)
+ { return Lex::can_start_number(*c) ? c + 1 : NULL; }
+
+ // If C1 C2 C3 form a valid three character operator, return the
+ // opcode. Otherwise return 0.
+ static inline int
+ three_char_operator(char c1, char c2, char c3);
+
+ // If C1 C2 form a valid two character operator, return the opcode.
+ // Otherwise return 0.
+ static inline int
+ two_char_operator(char c1, char c2);
+
+ // If C1 is a valid one character operator, return the opcode.
+ // Otherwise return 0.
+ static inline int
+ one_char_operator(char c1);
+
+ // Read the next token.
+ Token
+ get_token(const char**);
+
+ // Skip a C style /* */ comment. Return false if the comment did
+ // not end.
+ bool
+ skip_c_comment(const char**);
+
+ // Skip a line # comment. Return false if there was no newline.
+ bool
+ skip_line_comment(const char**);
+
+ // Build a token CLASSIFICATION from all characters that match
+ // CAN_CONTINUE_FN. The token starts at START. Start matching from
+ // MATCH. Set *PP to the character following the token.
+ inline Token
+ gather_token(Token::Classification,
+ const char* (Lex::*can_continue_fn)(const char*),
+ const char* start, const char* match, const char** pp);
+
+ // Build a token from a quoted string.
+ Token
+ gather_quoted_string(const char** pp);
+
+ // The string we are tokenizing.
+ const char* input_string_;
+ // The length of the string.
+ size_t input_length_;
+ // The current offset into the string.
+ const char* current_;
+ // The current lexing mode.
+ Mode mode_;
+ // The code to use for the first token. This is set to 0 after it
+ // is used.
+ int first_token_;
+ // The current token.
+ Token token_;
+ // The current line number.
+ int lineno_;
+ // The start of the current line in the string.
+ const char* linestart_;
+};
+
+// Read the whole file into memory. We don't expect linker scripts to
+// be large, so we just use a std::string as a buffer. We ignore the
+// data we've already read, so that we read aligned buffers.
+
+void
+Lex::read_file(Input_file* input_file, std::string* contents)
+{
+ off_t filesize = input_file->file().filesize();
+ contents->clear();
+ contents->reserve(filesize);
+
+ off_t off = 0;
+ unsigned char buf[BUFSIZ];
+ while (off < filesize)
+ {
+ off_t get = BUFSIZ;
+ if (get > filesize - off)
+ get = filesize - off;
+ input_file->file().read(off, get, buf);
+ contents->append(reinterpret_cast<char*>(&buf[0]), get);
+ off += get;
+ }
+}
+
+// Return whether C can be the start of a name, if the next character
+// is C2. A name can being with a letter, underscore, period, or
+// dollar sign. Because a name can be a file name, we also permit
+// forward slash, backslash, and tilde. Tilde is the tricky case
+// here; GNU ld also uses it as a bitwise not operator. It is only
+// recognized as the operator if it is not immediately followed by
+// some character which can appear in a symbol. That is, when we
+// don't know that we are looking at an expression, "~0" is a file
+// name, and "~ 0" is an expression using bitwise not. We are
+// compatible.
+
+inline bool
+Lex::can_start_name(char c, char c2)
+{
+ switch (c)
+ {
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+ case 'M': case 'N': case 'O': case 'Q': case 'P': case 'R':
+ case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+ case 'Y': case 'Z':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+ case 'm': case 'n': case 'o': case 'q': case 'p': case 'r':
+ case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+ case 'y': case 'z':
+ case '_': case '.': case '$':
+ return true;
+
+ case '/': case '\\':
+ return this->mode_ == LINKER_SCRIPT;
+
+ case '~':
+ return this->mode_ == LINKER_SCRIPT && can_continue_name(&c2);
+
+ case '*': case '[':
+ return (this->mode_ == VERSION_SCRIPT
+ || this->mode_ == DYNAMIC_LIST
+ || (this->mode_ == LINKER_SCRIPT
+ && can_continue_name(&c2)));
+
+ default:
+ return false;
+ }
+}
+
+// Return whether C can continue a name which has already started.
+// Subsequent characters in a name are the same as the leading
+// characters, plus digits and "=+-:[],?*". So in general the linker
+// script language requires spaces around operators, unless we know
+// that we are parsing an expression.
+
+inline const char*
+Lex::can_continue_name(const char* c)
+{
+ switch (*c)
+ {
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+ case 'M': case 'N': case 'O': case 'Q': case 'P': case 'R':
+ case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+ case 'Y': case 'Z':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+ case 'm': case 'n': case 'o': case 'q': case 'p': case 'r':
+ case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+ case 'y': case 'z':
+ case '_': case '.': case '$':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return c + 1;
+
+ // TODO(csilvers): why not allow ~ in names for version-scripts?
+ case '/': case '\\': case '~':
+ case '=': case '+':
+ case ',':
+ if (this->mode_ == LINKER_SCRIPT)
+ return c + 1;
+ return NULL;
+
+ case '[': case ']': case '*': case '?': case '-':
+ if (this->mode_ == LINKER_SCRIPT || this->mode_ == VERSION_SCRIPT
+ || this->mode_ == DYNAMIC_LIST)
+ return c + 1;
+ return NULL;
+
+ // TODO(csilvers): why allow this? ^ is meaningless in version scripts.
+ case '^':
+ if (this->mode_ == VERSION_SCRIPT || this->mode_ == DYNAMIC_LIST)
+ return c + 1;
+ return NULL;
+
+ case ':':
+ if (this->mode_ == LINKER_SCRIPT)
+ return c + 1;
+ else if ((this->mode_ == VERSION_SCRIPT || this->mode_ == DYNAMIC_LIST)
+ && (c[1] == ':'))
+ {
+ // A name can have '::' in it, as that's a c++ namespace
+ // separator. But a single colon is not part of a name.
+ return c + 2;
+ }
+ return NULL;
+
+ default:
+ return NULL;
+ }
+}
+
+// For a number we accept 0x followed by hex digits, or any sequence
+// of digits. The old linker accepts leading '$' for hex, and
+// trailing HXBOD. Those are for MRI compatibility and we don't
+// accept them.
+
+// Return whether C1 C2 C3 can start a hex number.
+
+inline bool
+Lex::can_start_hex(char c1, char c2, char c3)
+{
+ if (c1 == '0' && (c2 == 'x' || c2 == 'X'))
+ return this->can_continue_hex(&c3);
+ return false;
+}
+
+// Return whether C can appear in a hex number.
+
+inline const char*
+Lex::can_continue_hex(const char* c)
+{
+ switch (*c)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ return c + 1;
+
+ default:
+ return NULL;
+ }
+}
+
+// Return whether C can start a non-hex number.
+
+inline bool
+Lex::can_start_number(char c)
+{
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+// If C1 C2 C3 form a valid three character operator, return the
+// opcode (defined in the yyscript.h file generated from yyscript.y).
+// Otherwise return 0.
+
+inline int
+Lex::three_char_operator(char c1, char c2, char c3)
+{
+ switch (c1)
+ {
+ case '<':
+ if (c2 == '<' && c3 == '=')
+ return LSHIFTEQ;
+ break;
+ case '>':
+ if (c2 == '>' && c3 == '=')
+ return RSHIFTEQ;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+// If C1 C2 form a valid two character operator, return the opcode
+// (defined in the yyscript.h file generated from yyscript.y).
+// Otherwise return 0.
+
+inline int
+Lex::two_char_operator(char c1, char c2)
+{
+ switch (c1)
+ {
+ case '=':
+ if (c2 == '=')
+ return EQ;
+ break;
+ case '!':
+ if (c2 == '=')
+ return NE;
+ break;
+ case '+':
+ if (c2 == '=')
+ return PLUSEQ;
+ break;
+ case '-':
+ if (c2 == '=')
+ return MINUSEQ;
+ break;
+ case '*':
+ if (c2 == '=')
+ return MULTEQ;
+ break;
+ case '/':
+ if (c2 == '=')
+ return DIVEQ;
+ break;
+ case '|':
+ if (c2 == '=')
+ return OREQ;
+ if (c2 == '|')
+ return OROR;
+ break;
+ case '&':
+ if (c2 == '=')
+ return ANDEQ;
+ if (c2 == '&')
+ return ANDAND;
+ break;
+ case '>':
+ if (c2 == '=')
+ return GE;
+ if (c2 == '>')
+ return RSHIFT;
+ break;
+ case '<':
+ if (c2 == '=')
+ return LE;
+ if (c2 == '<')
+ return LSHIFT;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+// If C1 is a valid operator, return the opcode. Otherwise return 0.
+
+inline int
+Lex::one_char_operator(char c1)
+{
+ switch (c1)
+ {
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case '!':
+ case '&':
+ case '|':
+ case '^':
+ case '~':
+ case '<':
+ case '>':
+ case '=':
+ case '?':
+ case ',':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ case ':':
+ case ';':
+ return c1;
+ default:
+ return 0;
+ }
+}
+
+// Skip a C style comment. *PP points to just after the "/*". Return
+// false if the comment did not end.
+
+bool
+Lex::skip_c_comment(const char** pp)
+{
+ const char* p = *pp;
+ while (p[0] != '*' || p[1] != '/')
+ {
+ if (*p == '\0')
+ {
+ *pp = p;
+ return false;
+ }
+
+ if (*p == '\n')
+ {
+ ++this->lineno_;
+ this->linestart_ = p + 1;
+ }
+ ++p;
+ }
+
+ *pp = p + 2;
+ return true;
+}
+
+// Skip a line # comment. Return false if there was no newline.
+
+bool
+Lex::skip_line_comment(const char** pp)
+{
+ const char* p = *pp;
+ size_t skip = strcspn(p, "\n");
+ if (p[skip] == '\0')
+ {
+ *pp = p + skip;
+ return false;
+ }
+
+ p += skip + 1;
+ ++this->lineno_;
+ this->linestart_ = p;
+ *pp = p;
+
+ return true;
+}
+
+// Build a token CLASSIFICATION from all characters that match
+// CAN_CONTINUE_FN. Update *PP.
+
+inline Token
+Lex::gather_token(Token::Classification classification,
+ const char* (Lex::*can_continue_fn)(const char*),
+ const char* start,
+ const char* match,
+ const char** pp)
+{
+ const char* new_match = NULL;
+ while ((new_match = (this->*can_continue_fn)(match)) != NULL)
+ match = new_match;
+
+ // A special case: integers may be followed by a single M or K,
+ // case-insensitive.
+ if (classification == Token::TOKEN_INTEGER
+ && (*match == 'm' || *match == 'M' || *match == 'k' || *match == 'K'))
+ ++match;
+
+ *pp = match;
+ return this->make_token(classification, start, match - start, start);
+}
+
+// Build a token from a quoted string.
+
+Token
+Lex::gather_quoted_string(const char** pp)
+{
+ const char* start = *pp;
+ const char* p = start;
+ ++p;
+ size_t skip = strcspn(p, "\"\n");
+ if (p[skip] != '"')
+ return this->make_invalid_token(start);
+ *pp = p + skip + 1;
+ return this->make_token(Token::TOKEN_QUOTED_STRING, p, skip, start);
+}
+
+// Return the next token at *PP. Update *PP. General guideline: we
+// require linker scripts to be simple ASCII. No unicode linker
+// scripts. In particular we can assume that any '\0' is the end of
+// the input.
+
+Token
+Lex::get_token(const char** pp)
+{
+ const char* p = *pp;
+
+ while (true)
+ {
+ if (*p == '\0')
+ {
+ *pp = p;
+ return this->make_eof_token(p);
+ }
+
+ // Skip whitespace quickly.
+ while (*p == ' ' || *p == '\t' || *p == '\r')
+ ++p;
+
+ if (*p == '\n')
+ {
+ ++p;
+ ++this->lineno_;
+ this->linestart_ = p;
+ continue;
+ }
+
+ // Skip C style comments.
+ if (p[0] == '/' && p[1] == '*')
+ {
+ int lineno = this->lineno_;
+ int charpos = p - this->linestart_ + 1;
+
+ *pp = p + 2;
+ if (!this->skip_c_comment(pp))
+ return Token(Token::TOKEN_INVALID, lineno, charpos);
+ p = *pp;
+
+ continue;
+ }
+
+ // Skip line comments.
+ if (*p == '#')
+ {
+ *pp = p + 1;
+ if (!this->skip_line_comment(pp))
+ return this->make_eof_token(p);
+ p = *pp;
+ continue;
+ }
+
+ // Check for a name.
+ if (this->can_start_name(p[0], p[1]))
+ return this->gather_token(Token::TOKEN_STRING,
+ &Lex::can_continue_name,
+ p, p + 1, pp);
+
+ // We accept any arbitrary name in double quotes, as long as it
+ // does not cross a line boundary.
+ if (*p == '"')
+ {
+ *pp = p;
+ return this->gather_quoted_string(pp);
+ }
+
+ // Check for a number.
+
+ if (this->can_start_hex(p[0], p[1], p[2]))
+ return this->gather_token(Token::TOKEN_INTEGER,
+ &Lex::can_continue_hex,
+ p, p + 3, pp);
+
+ if (Lex::can_start_number(p[0]))
+ return this->gather_token(Token::TOKEN_INTEGER,
+ &Lex::can_continue_number,
+ p, p + 1, pp);
+
+ // Check for operators.
+
+ int opcode = Lex::three_char_operator(p[0], p[1], p[2]);
+ if (opcode != 0)
+ {
+ *pp = p + 3;
+ return this->make_token(opcode, p);
+ }
+
+ opcode = Lex::two_char_operator(p[0], p[1]);
+ if (opcode != 0)
+ {
+ *pp = p + 2;
+ return this->make_token(opcode, p);
+ }
+
+ opcode = Lex::one_char_operator(p[0]);
+ if (opcode != 0)
+ {
+ *pp = p + 1;
+ return this->make_token(opcode, p);
+ }
+
+ return this->make_token(Token::TOKEN_INVALID, p);
+ }
+}
+
+// Return the next token.
+
+const Token*
+Lex::next_token()
+{
+ // The first token is special.
+ if (this->first_token_ != 0)
+ {
+ this->token_ = Token(this->first_token_, 0, 0);
+ this->first_token_ = 0;
+ return &this->token_;
+ }
+
+ this->token_ = this->get_token(&this->current_);
+
+ // Don't let an early null byte fool us into thinking that we've
+ // reached the end of the file.
+ if (this->token_.is_eof()
+ && (static_cast<size_t>(this->current_ - this->input_string_)
+ < this->input_length_))
+ this->token_ = this->make_invalid_token(this->current_);
+
+ return &this->token_;
+}
+
+// class Symbol_assignment.
+
+// Add the symbol to the symbol table. This makes sure the symbol is
+// there and defined. The actual value is stored later. We can't
+// determine the actual value at this point, because we can't
+// necessarily evaluate the expression until all ordinary symbols have
+// been finalized.
+
+// The GNU linker lets symbol assignments in the linker script
+// silently override defined symbols in object files. We are
+// compatible. FIXME: Should we issue a warning?
+
+void
+Symbol_assignment::add_to_table(Symbol_table* symtab)
+{
+ elfcpp::STV vis = this->hidden_ ? elfcpp::STV_HIDDEN : elfcpp::STV_DEFAULT;
+ this->sym_ = symtab->define_as_constant(this->name_.c_str(),
+ NULL, // version
+ (this->is_defsym_
+ ? Symbol_table::DEFSYM
+ : Symbol_table::SCRIPT),
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE,
+ elfcpp::STB_GLOBAL,
+ vis,
+ 0, // nonvis
+ this->provide_,
+ true); // force_override
+}
+
+// Finalize a symbol value.
+
+void
+Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout)
+{
+ this->finalize_maybe_dot(symtab, layout, false, 0, NULL);
+}
+
+// Finalize a symbol value which can refer to the dot symbol.
+
+void
+Symbol_assignment::finalize_with_dot(Symbol_table* symtab,
+ const Layout* layout,
+ uint64_t dot_value,
+ Output_section* dot_section)
+{
+ this->finalize_maybe_dot(symtab, layout, true, dot_value, dot_section);
+}
+
+// Finalize a symbol value, internal version.
+
+void
+Symbol_assignment::finalize_maybe_dot(Symbol_table* symtab,
+ const Layout* layout,
+ bool is_dot_available,
+ uint64_t dot_value,
+ Output_section* dot_section)
+{
+ // If we were only supposed to provide this symbol, the sym_ field
+ // will be NULL if the symbol was not referenced.
+ if (this->sym_ == NULL)
+ {
+ gold_assert(this->provide_);
+ return;
+ }
+
+ if (parameters->target().get_size() == 32)
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+ this->sized_finalize<32>(symtab, layout, is_dot_available, dot_value,
+ dot_section);
+#else
+ gold_unreachable();
+#endif
+ }
+ else if (parameters->target().get_size() == 64)
+ {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+ this->sized_finalize<64>(symtab, layout, is_dot_available, dot_value,
+ dot_section);
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ gold_unreachable();
+}
+
+template<int size>
+void
+Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout,
+ bool is_dot_available, uint64_t dot_value,
+ Output_section* dot_section)
+{
+ Output_section* section;
+ uint64_t final_val = this->val_->eval_maybe_dot(symtab, layout, true,
+ is_dot_available,
+ dot_value, dot_section,
+ &section, NULL, false);
+ Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(this->sym_);
+ ssym->set_value(final_val);
+ if (section != NULL)
+ ssym->set_output_section(section);
+}
+
+// Set the symbol value if the expression yields an absolute value or
+// a value relative to DOT_SECTION.
+
+void
+Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout,
+ bool is_dot_available, uint64_t dot_value,
+ Output_section* dot_section)
+{
+ if (this->sym_ == NULL)
+ return;
+
+ Output_section* val_section;
+ uint64_t val = this->val_->eval_maybe_dot(symtab, layout, false,
+ is_dot_available, dot_value,
+ dot_section, &val_section, NULL,
+ false);
+ if (val_section != NULL && val_section != dot_section)
+ return;
+
+ if (parameters->target().get_size() == 32)
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+ Sized_symbol<32>* ssym = symtab->get_sized_symbol<32>(this->sym_);
+ ssym->set_value(val);
+#else
+ gold_unreachable();
+#endif
+ }
+ else if (parameters->target().get_size() == 64)
+ {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+ Sized_symbol<64>* ssym = symtab->get_sized_symbol<64>(this->sym_);
+ ssym->set_value(val);
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ gold_unreachable();
+ if (val_section != NULL)
+ this->sym_->set_output_section(val_section);
+}
+
+// Print for debugging.
+
+void
+Symbol_assignment::print(FILE* f) const
+{
+ if (this->provide_ && this->hidden_)
+ fprintf(f, "PROVIDE_HIDDEN(");
+ else if (this->provide_)
+ fprintf(f, "PROVIDE(");
+ else if (this->hidden_)
+ gold_unreachable();
+
+ fprintf(f, "%s = ", this->name_.c_str());
+ this->val_->print(f);
+
+ if (this->provide_ || this->hidden_)
+ fprintf(f, ")");
+
+ fprintf(f, "\n");
+}
+
+// Class Script_assertion.
+
+// Check the assertion.
+
+void
+Script_assertion::check(const Symbol_table* symtab, const Layout* layout)
+{
+ if (!this->check_->eval(symtab, layout, true))
+ gold_error("%s", this->message_.c_str());
+}
+
+// Print for debugging.
+
+void
+Script_assertion::print(FILE* f) const
+{
+ fprintf(f, "ASSERT(");
+ this->check_->print(f);
+ fprintf(f, ", \"%s\")\n", this->message_.c_str());
+}
+
+// Class Script_options.
+
+Script_options::Script_options()
+ : entry_(), symbol_assignments_(), symbol_definitions_(),
+ symbol_references_(), version_script_info_(), script_sections_()
+{
+}
+
+// Returns true if NAME is on the list of symbol assignments waiting
+// to be processed.
+
+bool
+Script_options::is_pending_assignment(const char* name)
+{
+ for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
+ p != this->symbol_assignments_.end();
+ ++p)
+ if ((*p)->name() == name)
+ return true;
+ return false;
+}
+
+// Add a symbol to be defined.
+
+void
+Script_options::add_symbol_assignment(const char* name, size_t length,
+ bool is_defsym, Expression* value,
+ bool provide, bool hidden)
+{
+ if (length != 1 || name[0] != '.')
+ {
+ if (this->script_sections_.in_sections_clause())
+ {
+ gold_assert(!is_defsym);
+ this->script_sections_.add_symbol_assignment(name, length, value,
+ provide, hidden);
+ }
+ else
+ {
+ Symbol_assignment* p = new Symbol_assignment(name, length, is_defsym,
+ value, provide, hidden);
+ this->symbol_assignments_.push_back(p);
+ }
+
+ if (!provide)
+ {
+ std::string n(name, length);
+ this->symbol_definitions_.insert(n);
+ this->symbol_references_.erase(n);
+ }
+ }
+ else
+ {
+ if (provide || hidden)
+ gold_error(_("invalid use of PROVIDE for dot symbol"));
+
+ // The GNU linker permits assignments to dot outside of SECTIONS
+ // clauses and treats them as occurring inside, so we don't
+ // check in_sections_clause here.
+ this->script_sections_.add_dot_assignment(value);
+ }
+}
+
+// Add a reference to a symbol.
+
+void
+Script_options::add_symbol_reference(const char* name, size_t length)
+{
+ if (length != 1 || name[0] != '.')
+ {
+ std::string n(name, length);
+ if (this->symbol_definitions_.find(n) == this->symbol_definitions_.end())
+ this->symbol_references_.insert(n);
+ }
+}
+
+// Add an assertion.
+
+void
+Script_options::add_assertion(Expression* check, const char* message,
+ size_t messagelen)
+{
+ if (this->script_sections_.in_sections_clause())
+ this->script_sections_.add_assertion(check, message, messagelen);
+ else
+ {
+ Script_assertion* p = new Script_assertion(check, message, messagelen);
+ this->assertions_.push_back(p);
+ }
+}
+
+// Create sections required by any linker scripts.
+
+void
+Script_options::create_script_sections(Layout* layout)
+{
+ if (this->saw_sections_clause())
+ this->script_sections_.create_sections(layout);
+}
+
+// Add any symbols we are defining to the symbol table.
+
+void
+Script_options::add_symbols_to_table(Symbol_table* symtab)
+{
+ for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
+ p != this->symbol_assignments_.end();
+ ++p)
+ (*p)->add_to_table(symtab);
+ this->script_sections_.add_symbols_to_table(symtab);
+}
+
+// Finalize symbol values. Also check assertions.
+
+void
+Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
+{
+ // We finalize the symbols defined in SECTIONS first, because they
+ // are the ones which may have changed. This way if symbol outside
+ // SECTIONS are defined in terms of symbols inside SECTIONS, they
+ // will get the right value.
+ this->script_sections_.finalize_symbols(symtab, layout);
+
+ for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
+ p != this->symbol_assignments_.end();
+ ++p)
+ (*p)->finalize(symtab, layout);
+
+ for (Assertions::iterator p = this->assertions_.begin();
+ p != this->assertions_.end();
+ ++p)
+ (*p)->check(symtab, layout);
+}
+
+// Set section addresses. We set all the symbols which have absolute
+// values. Then we let the SECTIONS clause do its thing. This
+// returns the segment which holds the file header and segment
+// headers, if any.
+
+Output_segment*
+Script_options::set_section_addresses(Symbol_table* symtab, Layout* layout)
+{
+ for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
+ p != this->symbol_assignments_.end();
+ ++p)
+ (*p)->set_if_absolute(symtab, layout, false, 0, NULL);
+
+ return this->script_sections_.set_section_addresses(symtab, layout);
+}
+
+// This class holds data passed through the parser to the lexer and to
+// the parser support functions. This avoids global variables. We
+// can't use global variables because we need not be called by a
+// singleton thread.
+
+class Parser_closure
+{
+ public:
+ Parser_closure(const char* filename,
+ const Position_dependent_options& posdep_options,
+ bool parsing_defsym, bool in_group, bool is_in_sysroot,
+ Command_line* command_line,
+ Script_options* script_options,
+ Lex* lex,
+ bool skip_on_incompatible_target,
+ Script_info* script_info)
+ : filename_(filename), posdep_options_(posdep_options),
+ parsing_defsym_(parsing_defsym), in_group_(in_group),
+ is_in_sysroot_(is_in_sysroot),
+ skip_on_incompatible_target_(skip_on_incompatible_target),
+ found_incompatible_target_(false),
+ command_line_(command_line), script_options_(script_options),
+ version_script_info_(script_options->version_script_info()),
+ lex_(lex), lineno_(0), charpos_(0), lex_mode_stack_(), inputs_(NULL),
+ script_info_(script_info)
+ {
+ // We start out processing C symbols in the default lex mode.
+ this->language_stack_.push_back(Version_script_info::LANGUAGE_C);
+ this->lex_mode_stack_.push_back(lex->mode());
+ }
+
+ // Return the file name.
+ const char*
+ filename() const
+ { return this->filename_; }
+
+ // Return the position dependent options. The caller may modify
+ // this.
+ Position_dependent_options&
+ position_dependent_options()
+ { return this->posdep_options_; }
+
+ // Whether we are parsing a --defsym.
+ bool
+ parsing_defsym() const
+ { return this->parsing_defsym_; }
+
+ // Return whether this script is being run in a group.
+ bool
+ in_group() const
+ { return this->in_group_; }
+
+ // Return whether this script was found using a directory in the
+ // sysroot.
+ bool
+ is_in_sysroot() const
+ { return this->is_in_sysroot_; }
+
+ // Whether to skip to the next file with the same name if we find an
+ // incompatible target in an OUTPUT_FORMAT statement.
+ bool
+ skip_on_incompatible_target() const
+ { return this->skip_on_incompatible_target_; }
+
+ // Stop skipping to the next file on an incompatible target. This
+ // is called when we make some unrevocable change to the data
+ // structures.
+ void
+ clear_skip_on_incompatible_target()
+ { this->skip_on_incompatible_target_ = false; }
+
+ // Whether we found an incompatible target in an OUTPUT_FORMAT
+ // statement.
+ bool
+ found_incompatible_target() const
+ { return this->found_incompatible_target_; }
+
+ // Note that we found an incompatible target.
+ void
+ set_found_incompatible_target()
+ { this->found_incompatible_target_ = true; }
+
+ // Returns the Command_line structure passed in at constructor time.
+ // This value may be NULL. The caller may modify this, which modifies
+ // the passed-in Command_line object (not a copy).
+ Command_line*
+ command_line()
+ { return this->command_line_; }
+
+ // Return the options which may be set by a script.
+ Script_options*
+ script_options()
+ { return this->script_options_; }
+
+ // Return the object in which version script information should be stored.
+ Version_script_info*
+ version_script()
+ { return this->version_script_info_; }
+
+ // Return the next token, and advance.
+ const Token*
+ next_token()
+ {
+ const Token* token = this->lex_->next_token();
+ this->lineno_ = token->lineno();
+ this->charpos_ = token->charpos();
+ return token;
+ }
+
+ // Set a new lexer mode, pushing the current one.
+ void
+ push_lex_mode(Lex::Mode mode)
+ {
+ this->lex_mode_stack_.push_back(this->lex_->mode());
+ this->lex_->set_mode(mode);
+ }
+
+ // Pop the lexer mode.
+ void
+ pop_lex_mode()
+ {
+ gold_assert(!this->lex_mode_stack_.empty());
+ this->lex_->set_mode(this->lex_mode_stack_.back());
+ this->lex_mode_stack_.pop_back();
+ }
+
+ // Return the current lexer mode.
+ Lex::Mode
+ lex_mode() const
+ { return this->lex_mode_stack_.back(); }
+
+ // Return the line number of the last token.
+ int
+ lineno() const
+ { return this->lineno_; }
+
+ // Return the character position in the line of the last token.
+ int
+ charpos() const
+ { return this->charpos_; }
+
+ // Return the list of input files, creating it if necessary. This
+ // is a space leak--we never free the INPUTS_ pointer.
+ Input_arguments*
+ inputs()
+ {
+ if (this->inputs_ == NULL)
+ this->inputs_ = new Input_arguments();
+ return this->inputs_;
+ }
+
+ // Return whether we saw any input files.
+ bool
+ saw_inputs() const
+ { return this->inputs_ != NULL && !this->inputs_->empty(); }
+
+ // Return the current language being processed in a version script
+ // (eg, "C++"). The empty string represents unmangled C names.
+ Version_script_info::Language
+ get_current_language() const
+ { return this->language_stack_.back(); }
+
+ // Push a language onto the stack when entering an extern block.
+ void
+ push_language(Version_script_info::Language lang)
+ { this->language_stack_.push_back(lang); }
+
+ // Pop a language off of the stack when exiting an extern block.
+ void
+ pop_language()
+ {
+ gold_assert(!this->language_stack_.empty());
+ this->language_stack_.pop_back();
+ }
+
+ // Return a pointer to the incremental info.
+ Script_info*
+ script_info()
+ { return this->script_info_; }
+
+ private:
+ // The name of the file we are reading.
+ const char* filename_;
+ // The position dependent options.
+ Position_dependent_options posdep_options_;
+ // True if we are parsing a --defsym.
+ bool parsing_defsym_;
+ // Whether we are currently in a --start-group/--end-group.
+ bool in_group_;
+ // Whether the script was found in a sysrooted directory.
+ bool is_in_sysroot_;
+ // If this is true, then if we find an OUTPUT_FORMAT with an
+ // incompatible target, then we tell the parser to abort so that we
+ // can search for the next file with the same name.
+ bool skip_on_incompatible_target_;
+ // True if we found an OUTPUT_FORMAT with an incompatible target.
+ bool found_incompatible_target_;
+ // May be NULL if the user chooses not to pass one in.
+ Command_line* command_line_;
+ // Options which may be set from any linker script.
+ Script_options* script_options_;
+ // Information parsed from a version script.
+ Version_script_info* version_script_info_;
+ // The lexer.
+ Lex* lex_;
+ // The line number of the last token returned by next_token.
+ int lineno_;
+ // The column number of the last token returned by next_token.
+ int charpos_;
+ // A stack of lexer modes.
+ std::vector<Lex::Mode> lex_mode_stack_;
+ // A stack of which extern/language block we're inside. Can be C++,
+ // java, or empty for C.
+ std::vector<Version_script_info::Language> language_stack_;
+ // New input files found to add to the link.
+ Input_arguments* inputs_;
+ // Pointer to incremental linking info.
+ Script_info* script_info_;
+};
+
+// FILE was found as an argument on the command line. Try to read it
+// as a script. Return true if the file was handled.
+
+bool
+read_input_script(Workqueue* workqueue, Symbol_table* symtab, Layout* layout,
+ Dirsearch* dirsearch, int dirindex,
+ Input_objects* input_objects, Mapfile* mapfile,
+ Input_group* input_group,
+ const Input_argument* input_argument,
+ Input_file* input_file, Task_token* next_blocker,
+ bool* used_next_blocker)
+{
+ *used_next_blocker = false;
+
+ std::string input_string;
+ Lex::read_file(input_file, &input_string);
+
+ Lex lex(input_string.c_str(), input_string.length(), PARSING_LINKER_SCRIPT);
+
+ Script_info* script_info = NULL;
+ if (layout->incremental_inputs() != NULL)
+ {
+ const std::string& filename = input_file->filename();
+ Timespec mtime = input_file->file().get_mtime();
+ unsigned int arg_serial = input_argument->file().arg_serial();
+ script_info = new Script_info(filename);
+ layout->incremental_inputs()->report_script(script_info, arg_serial,
+ mtime);
+ }
+
+ Parser_closure closure(input_file->filename().c_str(),
+ input_argument->file().options(),
+ false,
+ input_group != NULL,
+ input_file->is_in_sysroot(),
+ NULL,
+ layout->script_options(),
+ &lex,
+ input_file->will_search_for(),
+ script_info);
+
+ bool old_saw_sections_clause =
+ layout->script_options()->saw_sections_clause();
+
+ if (yyparse(&closure) != 0)
+ {
+ if (closure.found_incompatible_target())
+ {
+ Read_symbols::incompatible_warning(input_argument, input_file);
+ Read_symbols::requeue(workqueue, input_objects, symtab, layout,
+ dirsearch, dirindex, mapfile, input_argument,
+ input_group, next_blocker);
+ return true;
+ }
+ return false;
+ }
+
+ if (!old_saw_sections_clause
+ && layout->script_options()->saw_sections_clause()
+ && layout->have_added_input_section())
+ gold_error(_("%s: SECTIONS seen after other input files; try -T/--script"),
+ input_file->filename().c_str());
+
+ if (!closure.saw_inputs())
+ return true;
+
+ Task_token* this_blocker = NULL;
+ for (Input_arguments::const_iterator p = closure.inputs()->begin();
+ p != closure.inputs()->end();
+ ++p)
+ {
+ Task_token* nb;
+ if (p + 1 == closure.inputs()->end())
+ nb = next_blocker;
+ else
+ {
+ nb = new Task_token(true);
+ nb->add_blocker();
+ }
+ workqueue->queue_soon(new Read_symbols(input_objects, symtab,
+ layout, dirsearch, 0, mapfile, &*p,
+ input_group, NULL, this_blocker, nb));
+ this_blocker = nb;
+ }
+
+ *used_next_blocker = true;
+
+ return true;
+}
+
+// Helper function for read_version_script(), read_commandline_script() and
+// script_include_directive(). Processes the given file in the mode indicated
+// by first_token and lex_mode.
+
+static bool
+read_script_file(const char* filename, Command_line* cmdline,
+ Script_options* script_options,
+ int first_token, Lex::Mode lex_mode)
+{
+ Dirsearch dirsearch;
+ std::string name = filename;
+
+ // If filename is a relative filename, search for it manually using "." +
+ // cmdline->options()->library_path() -- not dirsearch.
+ if (!IS_ABSOLUTE_PATH(filename))
+ {
+ const General_options::Dir_list& search_path =
+ cmdline->options().library_path();
+ name = Dirsearch::find_file_in_dir_list(name, search_path, ".");
+ }
+
+ // The file locking code wants to record a Task, but we haven't
+ // started the workqueue yet. This is only for debugging purposes,
+ // so we invent a fake value.
+ const Task* task = reinterpret_cast<const Task*>(-1);
+
+ // We don't want this file to be opened in binary mode.
+ Position_dependent_options posdep = cmdline->position_dependent_options();
+ if (posdep.format_enum() == General_options::OBJECT_FORMAT_BINARY)
+ posdep.set_format_enum(General_options::OBJECT_FORMAT_ELF);
+ Input_file_argument input_argument(name.c_str(),
+ Input_file_argument::INPUT_FILE_TYPE_FILE,
+ "", false, posdep);
+ Input_file input_file(&input_argument);
+ int dummy = 0;
+ if (!input_file.open(dirsearch, task, &dummy))
+ return false;
+
+ std::string input_string;
+ Lex::read_file(&input_file, &input_string);
+
+ Lex lex(input_string.c_str(), input_string.length(), first_token);
+ lex.set_mode(lex_mode);
+
+ Parser_closure closure(filename,
+ cmdline->position_dependent_options(),
+ first_token == Lex::DYNAMIC_LIST,
+ false,
+ input_file.is_in_sysroot(),
+ cmdline,
+ script_options,
+ &lex,
+ false,
+ NULL);
+ if (yyparse(&closure) != 0)
+ {
+ input_file.file().unlock(task);
+ return false;
+ }
+
+ input_file.file().unlock(task);
+
+ gold_assert(!closure.saw_inputs());
+
+ return true;
+}
+
+// FILENAME was found as an argument to --script (-T).
+// Read it as a script, and execute its contents immediately.
+
+bool
+read_commandline_script(const char* filename, Command_line* cmdline)
+{
+ return read_script_file(filename, cmdline, &cmdline->script_options(),
+ PARSING_LINKER_SCRIPT, Lex::LINKER_SCRIPT);
+}
+
+// FILENAME was found as an argument to --version-script. Read it as
+// a version script, and store its contents in
+// cmdline->script_options()->version_script_info().
+
+bool
+read_version_script(const char* filename, Command_line* cmdline)
+{
+ return read_script_file(filename, cmdline, &cmdline->script_options(),
+ PARSING_VERSION_SCRIPT, Lex::VERSION_SCRIPT);
+}
+
+// FILENAME was found as an argument to --dynamic-list. Read it as a
+// list of symbols, and store its contents in DYNAMIC_LIST.
+
+bool
+read_dynamic_list(const char* filename, Command_line* cmdline,
+ Script_options* dynamic_list)
+{
+ return read_script_file(filename, cmdline, dynamic_list,
+ PARSING_DYNAMIC_LIST, Lex::DYNAMIC_LIST);
+}
+
+// Implement the --defsym option on the command line. Return true if
+// all is well.
+
+bool
+Script_options::define_symbol(const char* definition)
+{
+ Lex lex(definition, strlen(definition), PARSING_DEFSYM);
+ lex.set_mode(Lex::EXPRESSION);
+
+ // Dummy value.
+ Position_dependent_options posdep_options;
+
+ Parser_closure closure("command line", posdep_options, true,
+ false, false, NULL, this, &lex, false, NULL);
+
+ if (yyparse(&closure) != 0)
+ return false;
+
+ gold_assert(!closure.saw_inputs());
+
+ return true;
+}
+
+// Print the script to F for debugging.
+
+void
+Script_options::print(FILE* f) const
+{
+ fprintf(f, "%s: Dumping linker script\n", program_name);
+
+ if (!this->entry_.empty())
+ fprintf(f, "ENTRY(%s)\n", this->entry_.c_str());
+
+ for (Symbol_assignments::const_iterator p =
+ this->symbol_assignments_.begin();
+ p != this->symbol_assignments_.end();
+ ++p)
+ (*p)->print(f);
+
+ for (Assertions::const_iterator p = this->assertions_.begin();
+ p != this->assertions_.end();
+ ++p)
+ (*p)->print(f);
+
+ this->script_sections_.print(f);
+
+ this->version_script_info_.print(f);
+}
+
+// Manage mapping from keywords to the codes expected by the bison
+// parser. We construct one global object for each lex mode with
+// keywords.
+
+class Keyword_to_parsecode
+{
+ public:
+ // The structure which maps keywords to parsecodes.
+ struct Keyword_parsecode
+ {
+ // Keyword.
+ const char* keyword;
+ // Corresponding parsecode.
+ int parsecode;
+ };
+
+ Keyword_to_parsecode(const Keyword_parsecode* keywords,
+ int keyword_count)
+ : keyword_parsecodes_(keywords), keyword_count_(keyword_count)
+ { }
+
+ // Return the parsecode corresponding KEYWORD, or 0 if it is not a
+ // keyword.
+ int
+ keyword_to_parsecode(const char* keyword, size_t len) const;
+
+ private:
+ const Keyword_parsecode* keyword_parsecodes_;
+ const int keyword_count_;
+};
+
+// Mapping from keyword string to keyword parsecode. This array must
+// be kept in sorted order. Parsecodes are looked up using bsearch.
+// This array must correspond to the list of parsecodes in yyscript.y.
+
+static const Keyword_to_parsecode::Keyword_parsecode
+script_keyword_parsecodes[] =
+{
+ { "ABSOLUTE", ABSOLUTE },
+ { "ADDR", ADDR },
+ { "ALIGN", ALIGN_K },
+ { "ALIGNOF", ALIGNOF },
+ { "ASSERT", ASSERT_K },
+ { "AS_NEEDED", AS_NEEDED },
+ { "AT", AT },
+ { "BIND", BIND },
+ { "BLOCK", BLOCK },
+ { "BYTE", BYTE },
+ { "CONSTANT", CONSTANT },
+ { "CONSTRUCTORS", CONSTRUCTORS },
+ { "COPY", COPY },
+ { "CREATE_OBJECT_SYMBOLS", CREATE_OBJECT_SYMBOLS },
+ { "DATA_SEGMENT_ALIGN", DATA_SEGMENT_ALIGN },
+ { "DATA_SEGMENT_END", DATA_SEGMENT_END },
+ { "DATA_SEGMENT_RELRO_END", DATA_SEGMENT_RELRO_END },
+ { "DEFINED", DEFINED },
+ { "DSECT", DSECT },
+ { "ENTRY", ENTRY },
+ { "EXCLUDE_FILE", EXCLUDE_FILE },
+ { "EXTERN", EXTERN },
+ { "FILL", FILL },
+ { "FLOAT", FLOAT },
+ { "FORCE_COMMON_ALLOCATION", FORCE_COMMON_ALLOCATION },
+ { "GROUP", GROUP },
+ { "HLL", HLL },
+ { "INCLUDE", INCLUDE },
+ { "INFO", INFO },
+ { "INHIBIT_COMMON_ALLOCATION", INHIBIT_COMMON_ALLOCATION },
+ { "INPUT", INPUT },
+ { "KEEP", KEEP },
+ { "LENGTH", LENGTH },
+ { "LOADADDR", LOADADDR },
+ { "LONG", LONG },
+ { "MAP", MAP },
+ { "MAX", MAX_K },
+ { "MEMORY", MEMORY },
+ { "MIN", MIN_K },
+ { "NEXT", NEXT },
+ { "NOCROSSREFS", NOCROSSREFS },
+ { "NOFLOAT", NOFLOAT },
+ { "NOLOAD", NOLOAD },
+ { "ONLY_IF_RO", ONLY_IF_RO },
+ { "ONLY_IF_RW", ONLY_IF_RW },
+ { "OPTION", OPTION },
+ { "ORIGIN", ORIGIN },
+ { "OUTPUT", OUTPUT },
+ { "OUTPUT_ARCH", OUTPUT_ARCH },
+ { "OUTPUT_FORMAT", OUTPUT_FORMAT },
+ { "OVERLAY", OVERLAY },
+ { "PHDRS", PHDRS },
+ { "PROVIDE", PROVIDE },
+ { "PROVIDE_HIDDEN", PROVIDE_HIDDEN },
+ { "QUAD", QUAD },
+ { "SEARCH_DIR", SEARCH_DIR },
+ { "SECTIONS", SECTIONS },
+ { "SEGMENT_START", SEGMENT_START },
+ { "SHORT", SHORT },
+ { "SIZEOF", SIZEOF },
+ { "SIZEOF_HEADERS", SIZEOF_HEADERS },
+ { "SORT", SORT_BY_NAME },
+ { "SORT_BY_ALIGNMENT", SORT_BY_ALIGNMENT },
+ { "SORT_BY_NAME", SORT_BY_NAME },
+ { "SPECIAL", SPECIAL },
+ { "SQUAD", SQUAD },
+ { "STARTUP", STARTUP },
+ { "SUBALIGN", SUBALIGN },
+ { "SYSLIB", SYSLIB },
+ { "TARGET", TARGET_K },
+ { "TRUNCATE", TRUNCATE },
+ { "VERSION", VERSIONK },
+ { "global", GLOBAL },
+ { "l", LENGTH },
+ { "len", LENGTH },
+ { "local", LOCAL },
+ { "o", ORIGIN },
+ { "org", ORIGIN },
+ { "sizeof_headers", SIZEOF_HEADERS },
+};
+
+static const Keyword_to_parsecode
+script_keywords(&script_keyword_parsecodes[0],
+ (sizeof(script_keyword_parsecodes)
+ / sizeof(script_keyword_parsecodes[0])));
+
+static const Keyword_to_parsecode::Keyword_parsecode
+version_script_keyword_parsecodes[] =
+{
+ { "extern", EXTERN },
+ { "global", GLOBAL },
+ { "local", LOCAL },
+};
+
+static const Keyword_to_parsecode
+version_script_keywords(&version_script_keyword_parsecodes[0],
+ (sizeof(version_script_keyword_parsecodes)
+ / sizeof(version_script_keyword_parsecodes[0])));
+
+static const Keyword_to_parsecode::Keyword_parsecode
+dynamic_list_keyword_parsecodes[] =
+{
+ { "extern", EXTERN },
+};
+
+static const Keyword_to_parsecode
+dynamic_list_keywords(&dynamic_list_keyword_parsecodes[0],
+ (sizeof(dynamic_list_keyword_parsecodes)
+ / sizeof(dynamic_list_keyword_parsecodes[0])));
+
+
+
+// Comparison function passed to bsearch.
+
+extern "C"
+{
+
+struct Ktt_key
+{
+ const char* str;
+ size_t len;
+};
+
+static int
+ktt_compare(const void* keyv, const void* kttv)
+{
+ const Ktt_key* key = static_cast<const Ktt_key*>(keyv);
+ const Keyword_to_parsecode::Keyword_parsecode* ktt =
+ static_cast<const Keyword_to_parsecode::Keyword_parsecode*>(kttv);
+ int i = strncmp(key->str, ktt->keyword, key->len);
+ if (i != 0)
+ return i;
+ if (ktt->keyword[key->len] != '\0')
+ return -1;
+ return 0;
+}
+
+} // End extern "C".
+
+int
+Keyword_to_parsecode::keyword_to_parsecode(const char* keyword,
+ size_t len) const
+{
+ Ktt_key key;
+ key.str = keyword;
+ key.len = len;
+ void* kttv = bsearch(&key,
+ this->keyword_parsecodes_,
+ this->keyword_count_,
+ sizeof(this->keyword_parsecodes_[0]),
+ ktt_compare);
+ if (kttv == NULL)
+ return 0;
+ Keyword_parsecode* ktt = static_cast<Keyword_parsecode*>(kttv);
+ return ktt->parsecode;
+}
+
+// The following structs are used within the VersionInfo class as well
+// as in the bison helper functions. They store the information
+// parsed from the version script.
+
+// A single version expression.
+// For example, pattern="std::map*" and language="C++".
+struct Version_expression
+{
+ Version_expression(const std::string& a_pattern,
+ Version_script_info::Language a_language,
+ bool a_exact_match)
+ : pattern(a_pattern), language(a_language), exact_match(a_exact_match),
+ was_matched_by_symbol(false)
+ { }
+
+ std::string pattern;
+ Version_script_info::Language language;
+ // If false, we use glob() to match pattern. If true, we use strcmp().
+ bool exact_match;
+ // True if --no-undefined-version is in effect and we found this
+ // version in get_symbol_version. We use mutable because this
+ // struct is generally not modifiable after it has been created.
+ mutable bool was_matched_by_symbol;
+};
+
+// A list of expressions.
+struct Version_expression_list
+{
+ std::vector<struct Version_expression> expressions;
+};
+
+// A list of which versions upon which another version depends.
+// Strings should be from the Stringpool.
+struct Version_dependency_list
+{
+ std::vector<std::string> dependencies;
+};
+
+// The total definition of a version. It includes the tag for the
+// version, its global and local expressions, and any dependencies.
+struct Version_tree
+{
+ Version_tree()
+ : tag(), global(NULL), local(NULL), dependencies(NULL)
+ { }
+
+ std::string tag;
+ const struct Version_expression_list* global;
+ const struct Version_expression_list* local;
+ const struct Version_dependency_list* dependencies;
+};
+
+// Helper class that calls cplus_demangle when needed and takes care of freeing
+// the result.
+
+class Lazy_demangler
+{
+ public:
+ Lazy_demangler(const char* symbol, int options)
+ : symbol_(symbol), options_(options), demangled_(NULL), did_demangle_(false)
+ { }
+
+ ~Lazy_demangler()
+ { free(this->demangled_); }
+
+ // Return the demangled name. The actual demangling happens on the first call,
+ // and the result is later cached.
+ inline char*
+ get();
+
+ private:
+ // The symbol to demangle.
+ const char* symbol_;
+ // Option flags to pass to cplus_demagle.
+ const int options_;
+ // The cached demangled value, or NULL if demangling didn't happen yet or
+ // failed.
+ char* demangled_;
+ // Whether we already called cplus_demangle
+ bool did_demangle_;
+};
+
+// Return the demangled name. The actual demangling happens on the first call,
+// and the result is later cached. Returns NULL if the symbol cannot be
+// demangled.
+
+inline char*
+Lazy_demangler::get()
+{
+ if (!this->did_demangle_)
+ {
+ this->demangled_ = cplus_demangle(this->symbol_, this->options_);
+ this->did_demangle_ = true;
+ }
+ return this->demangled_;
+}
+
+// Class Version_script_info.
+
+Version_script_info::Version_script_info()
+ : dependency_lists_(), expression_lists_(), version_trees_(), globs_(),
+ default_version_(NULL), default_is_global_(false), is_finalized_(false)
+{
+ for (int i = 0; i < LANGUAGE_COUNT; ++i)
+ this->exact_[i] = NULL;
+}
+
+Version_script_info::~Version_script_info()
+{
+}
+
+// Forget all the known version script information.
+
+void
+Version_script_info::clear()
+{
+ for (size_t k = 0; k < this->dependency_lists_.size(); ++k)
+ delete this->dependency_lists_[k];
+ this->dependency_lists_.clear();
+ for (size_t k = 0; k < this->version_trees_.size(); ++k)
+ delete this->version_trees_[k];
+ this->version_trees_.clear();
+ for (size_t k = 0; k < this->expression_lists_.size(); ++k)
+ delete this->expression_lists_[k];
+ this->expression_lists_.clear();
+}
+
+// Finalize the version script information.
+
+void
+Version_script_info::finalize()
+{
+ if (!this->is_finalized_)
+ {
+ this->build_lookup_tables();
+ this->is_finalized_ = true;
+ }
+}
+
+// Return all the versions.
+
+std::vector<std::string>
+Version_script_info::get_versions() const
+{
+ std::vector<std::string> ret;
+ for (size_t j = 0; j < this->version_trees_.size(); ++j)
+ if (!this->version_trees_[j]->tag.empty())
+ ret.push_back(this->version_trees_[j]->tag);
+ return ret;
+}
+
+// Return the dependencies of VERSION.
+
+std::vector<std::string>
+Version_script_info::get_dependencies(const char* version) const
+{
+ std::vector<std::string> ret;
+ for (size_t j = 0; j < this->version_trees_.size(); ++j)
+ if (this->version_trees_[j]->tag == version)
+ {
+ const struct Version_dependency_list* deps =
+ this->version_trees_[j]->dependencies;
+ if (deps != NULL)
+ for (size_t k = 0; k < deps->dependencies.size(); ++k)
+ ret.push_back(deps->dependencies[k]);
+ return ret;
+ }
+ return ret;
+}
+
+// A version script essentially maps a symbol name to a version tag
+// and an indication of whether symbol is global or local within that
+// version tag. Each symbol maps to at most one version tag.
+// Unfortunately, in practice, version scripts are ambiguous, and list
+// symbols multiple times. Thus, we have to document the matching
+// process.
+
+// This is a description of what the GNU linker does as of 2010-01-11.
+// It walks through the version tags in the order in which they appear
+// in the version script. For each tag, it first walks through the
+// global patterns for that tag, then the local patterns. When
+// looking at a single pattern, it first applies any language specific
+// demangling as specified for the pattern, and then matches the
+// resulting symbol name to the pattern. If it finds an exact match
+// for a literal pattern (a pattern enclosed in quotes or with no
+// wildcard characters), then that is the match that it uses. If
+// finds a match with a wildcard pattern, then it saves it and
+// continues searching. Wildcard patterns that are exactly "*" are
+// saved separately.
+
+// If no exact match with a literal pattern is ever found, then if a
+// wildcard match with a global pattern was found it is used,
+// otherwise if a wildcard match with a local pattern was found it is
+// used.
+
+// This is the result:
+// * If there is an exact match, then we use the first tag in the
+// version script where it matches.
+// + If the exact match in that tag is global, it is used.
+// + Otherwise the exact match in that tag is local, and is used.
+// * Otherwise, if there is any match with a global wildcard pattern:
+// + If there is any match with a wildcard pattern which is not
+// "*", then we use the tag in which the *last* such pattern
+// appears.
+// + Otherwise, we matched "*". If there is no match with a local
+// wildcard pattern which is not "*", then we use the *last*
+// match with a global "*". Otherwise, continue.
+// * Otherwise, if there is any match with a local wildcard pattern:
+// + If there is any match with a wildcard pattern which is not
+// "*", then we use the tag in which the *last* such pattern
+// appears.
+// + Otherwise, we matched "*", and we use the tag in which the
+// *last* such match occurred.
+
+// There is an additional wrinkle. When the GNU linker finds a symbol
+// with a version defined in an object file due to a .symver
+// directive, it looks up that symbol name in that version tag. If it
+// finds it, it matches the symbol name against the patterns for that
+// version. If there is no match with a global pattern, but there is
+// a match with a local pattern, then the GNU linker marks the symbol
+// as local.
+
+// We want gold to be generally compatible, but we also want gold to
+// be fast. These are the rules that gold implements:
+// * If there is an exact match for the mangled name, we use it.
+// + If there is more than one exact match, we give a warning, and
+// we use the first tag in the script which matches.
+// + If a symbol has an exact match as both global and local for
+// the same version tag, we give an error.
+// * Otherwise, we look for an extern C++ or an extern Java exact
+// match. If we find an exact match, we use it.
+// + If there is more than one exact match, we give a warning, and
+// we use the first tag in the script which matches.
+// + If a symbol has an exact match as both global and local for
+// the same version tag, we give an error.
+// * Otherwise, we look through the wildcard patterns, ignoring "*"
+// patterns. We look through the version tags in reverse order.
+// For each version tag, we look through the global patterns and
+// then the local patterns. We use the first match we find (i.e.,
+// the last matching version tag in the file).
+// * Otherwise, we use the "*" pattern if there is one. We give an
+// error if there are multiple "*" patterns.
+
+// At least for now, gold does not look up the version tag for a
+// symbol version found in an object file to see if it should be
+// forced local. There are other ways to force a symbol to be local,
+// and I don't understand why this one is useful.
+
+// Build a set of fast lookup tables for a version script.
+
+void
+Version_script_info::build_lookup_tables()
+{
+ size_t size = this->version_trees_.size();
+ for (size_t j = 0; j < size; ++j)
+ {
+ const Version_tree* v = this->version_trees_[j];
+ this->build_expression_list_lookup(v->local, v, false);
+ this->build_expression_list_lookup(v->global, v, true);
+ }
+}
+
+// If a pattern has backlashes but no unquoted wildcard characters,
+// then we apply backslash unquoting and look for an exact match.
+// Otherwise we treat it as a wildcard pattern. This function returns
+// true for a wildcard pattern. Otherwise, it does backslash
+// unquoting on *PATTERN and returns false. If this returns true,
+// *PATTERN may have been partially unquoted.
+
+bool
+Version_script_info::unquote(std::string* pattern) const
+{
+ bool saw_backslash = false;
+ size_t len = pattern->length();
+ size_t j = 0;
+ for (size_t i = 0; i < len; ++i)
+ {
+ if (saw_backslash)
+ saw_backslash = false;
+ else
+ {
+ switch ((*pattern)[i])
+ {
+ case '?': case '[': case '*':
+ return true;
+ case '\\':
+ saw_backslash = true;
+ continue;
+ default:
+ break;
+ }
+ }
+
+ if (i != j)
+ (*pattern)[j] = (*pattern)[i];
+ ++j;
+ }
+ return false;
+}
+
+// Add an exact match for MATCH to *PE. The result of the match is
+// V/IS_GLOBAL.
+
+void
+Version_script_info::add_exact_match(const std::string& match,
+ const Version_tree* v, bool is_global,
+ const Version_expression* ve,
+ Exact* pe)
+{
+ std::pair<Exact::iterator, bool> ins =
+ pe->insert(std::make_pair(match, Version_tree_match(v, is_global, ve)));
+ if (ins.second)
+ {
+ // This is the first time we have seen this match.
+ return;
+ }
+
+ Version_tree_match& vtm(ins.first->second);
+ if (vtm.real->tag != v->tag)
+ {
+ // This is an ambiguous match. We still return the
+ // first version that we found in the script, but we
+ // record the new version to issue a warning if we
+ // wind up looking up this symbol.
+ if (vtm.ambiguous == NULL)
+ vtm.ambiguous = v;
+ }
+ else if (is_global != vtm.is_global)
+ {
+ // We have a match for both the global and local entries for a
+ // version tag. That's got to be wrong.
+ gold_error(_("'%s' appears as both a global and a local symbol "
+ "for version '%s' in script"),
+ match.c_str(), v->tag.c_str());
+ }
+}
+
+// Build fast lookup information for EXPLIST and store it in LOOKUP.
+// All matches go to V, and IS_GLOBAL is true if they are global
+// matches.
+
+void
+Version_script_info::build_expression_list_lookup(
+ const Version_expression_list* explist,
+ const Version_tree* v,
+ bool is_global)
+{
+ if (explist == NULL)
+ return;
+ size_t size = explist->expressions.size();
+ for (size_t i = 0; i < size; ++i)
+ {
+ const Version_expression& exp(explist->expressions[i]);
+
+ if (exp.pattern.length() == 1 && exp.pattern[0] == '*')
+ {
+ if (this->default_version_ != NULL
+ && this->default_version_->tag != v->tag)
+ gold_warning(_("wildcard match appears in both version '%s' "
+ "and '%s' in script"),
+ this->default_version_->tag.c_str(), v->tag.c_str());
+ else if (this->default_version_ != NULL
+ && this->default_is_global_ != is_global)
+ gold_error(_("wildcard match appears as both global and local "
+ "in version '%s' in script"),
+ v->tag.c_str());
+ this->default_version_ = v;
+ this->default_is_global_ = is_global;
+ continue;
+ }
+
+ std::string pattern = exp.pattern;
+ if (!exp.exact_match)
+ {
+ if (this->unquote(&pattern))
+ {
+ this->globs_.push_back(Glob(&exp, v, is_global));
+ continue;
+ }
+ }
+
+ if (this->exact_[exp.language] == NULL)
+ this->exact_[exp.language] = new Exact();
+ this->add_exact_match(pattern, v, is_global, &exp,
+ this->exact_[exp.language]);
+ }
+}
+
+// Return the name to match given a name, a language code, and two
+// lazy demanglers.
+
+const char*
+Version_script_info::get_name_to_match(const char* name,
+ int language,
+ Lazy_demangler* cpp_demangler,
+ Lazy_demangler* java_demangler) const
+{
+ switch (language)
+ {
+ case LANGUAGE_C:
+ return name;
+ case LANGUAGE_CXX:
+ return cpp_demangler->get();
+ case LANGUAGE_JAVA:
+ return java_demangler->get();
+ default:
+ gold_unreachable();
+ }
+}
+
+// Look up SYMBOL_NAME in the list of versions. Return true if the
+// symbol is found, false if not. If the symbol is found, then if
+// PVERSION is not NULL, set *PVERSION to the version tag, and if
+// P_IS_GLOBAL is not NULL, set *P_IS_GLOBAL according to whether the
+// symbol is global or not.
+
+bool
+Version_script_info::get_symbol_version(const char* symbol_name,
+ std::string* pversion,
+ bool* p_is_global) const
+{
+ Lazy_demangler cpp_demangled_name(symbol_name, DMGL_ANSI | DMGL_PARAMS);
+ Lazy_demangler java_demangled_name(symbol_name,
+ DMGL_ANSI | DMGL_PARAMS | DMGL_JAVA);
+
+ gold_assert(this->is_finalized_);
+ for (int i = 0; i < LANGUAGE_COUNT; ++i)
+ {
+ Exact* exact = this->exact_[i];
+ if (exact == NULL)
+ continue;
+
+ const char* name_to_match = this->get_name_to_match(symbol_name, i,
+ &cpp_demangled_name,
+ &java_demangled_name);
+ if (name_to_match == NULL)
+ {
+ // If the name can not be demangled, the GNU linker goes
+ // ahead and tries to match it anyhow. That does not
+ // make sense to me and I have not implemented it.
+ continue;
+ }
+
+ Exact::const_iterator pe = exact->find(name_to_match);
+ if (pe != exact->end())
+ {
+ const Version_tree_match& vtm(pe->second);
+ if (vtm.ambiguous != NULL)
+ gold_warning(_("using '%s' as version for '%s' which is also "
+ "named in version '%s' in script"),
+ vtm.real->tag.c_str(), name_to_match,
+ vtm.ambiguous->tag.c_str());
+
+ if (pversion != NULL)
+ *pversion = vtm.real->tag;
+ if (p_is_global != NULL)
+ *p_is_global = vtm.is_global;
+
+ // If we are using --no-undefined-version, and this is a
+ // global symbol, we have to record that we have found this
+ // symbol, so that we don't warn about it. We have to do
+ // this now, because otherwise we have no way to get from a
+ // non-C language back to the demangled name that we
+ // matched.
+ if (p_is_global != NULL && vtm.is_global)
+ vtm.expression->was_matched_by_symbol = true;
+
+ return true;
+ }
+ }
+
+ // Look through the glob patterns in reverse order.
+
+ for (Globs::const_reverse_iterator p = this->globs_.rbegin();
+ p != this->globs_.rend();
+ ++p)
+ {
+ int language = p->expression->language;
+ const char* name_to_match = this->get_name_to_match(symbol_name,
+ language,
+ &cpp_demangled_name,
+ &java_demangled_name);
+ if (name_to_match == NULL)
+ continue;
+
+ if (fnmatch(p->expression->pattern.c_str(), name_to_match,
+ FNM_NOESCAPE) == 0)
+ {
+ if (pversion != NULL)
+ *pversion = p->version->tag;
+ if (p_is_global != NULL)
+ *p_is_global = p->is_global;
+ return true;
+ }
+ }
+
+ // Finally, there may be a wildcard.
+ if (this->default_version_ != NULL)
+ {
+ if (pversion != NULL)
+ *pversion = this->default_version_->tag;
+ if (p_is_global != NULL)
+ *p_is_global = this->default_is_global_;
+ return true;
+ }
+
+ return false;
+}
+
+// Give an error if any exact symbol names (not wildcards) appear in a
+// version script, but there is no such symbol.
+
+void
+Version_script_info::check_unmatched_names(const Symbol_table* symtab) const
+{
+ for (size_t i = 0; i < this->version_trees_.size(); ++i)
+ {
+ const Version_tree* vt = this->version_trees_[i];
+ if (vt->global == NULL)
+ continue;
+ for (size_t j = 0; j < vt->global->expressions.size(); ++j)
+ {
+ const Version_expression& expression(vt->global->expressions[j]);
+
+ // Ignore cases where we used the version because we saw a
+ // symbol that we looked up. Note that
+ // WAS_MATCHED_BY_SYMBOL will be true even if the symbol was
+ // not a definition. That's OK as in that case we most
+ // likely gave an undefined symbol error anyhow.
+ if (expression.was_matched_by_symbol)
+ continue;
+
+ // Just ignore names which are in languages other than C.
+ // We have no way to look them up in the symbol table.
+ if (expression.language != LANGUAGE_C)
+ continue;
+
+ // Remove backslash quoting, and ignore wildcard patterns.
+ std::string pattern = expression.pattern;
+ if (!expression.exact_match)
+ {
+ if (this->unquote(&pattern))
+ continue;
+ }
+
+ if (symtab->lookup(pattern.c_str(), vt->tag.c_str()) == NULL)
+ gold_error(_("version script assignment of %s to symbol %s "
+ "failed: symbol not defined"),
+ vt->tag.c_str(), pattern.c_str());
+ }
+ }
+}
+
+struct Version_dependency_list*
+Version_script_info::allocate_dependency_list()
+{
+ dependency_lists_.push_back(new Version_dependency_list);
+ return dependency_lists_.back();
+}
+
+struct Version_expression_list*
+Version_script_info::allocate_expression_list()
+{
+ expression_lists_.push_back(new Version_expression_list);
+ return expression_lists_.back();
+}
+
+struct Version_tree*
+Version_script_info::allocate_version_tree()
+{
+ version_trees_.push_back(new Version_tree);
+ return version_trees_.back();
+}
+
+// Print for debugging.
+
+void
+Version_script_info::print(FILE* f) const
+{
+ if (this->empty())
+ return;
+
+ fprintf(f, "VERSION {");
+
+ for (size_t i = 0; i < this->version_trees_.size(); ++i)
+ {
+ const Version_tree* vt = this->version_trees_[i];
+
+ if (vt->tag.empty())
+ fprintf(f, " {\n");
+ else
+ fprintf(f, " %s {\n", vt->tag.c_str());
+
+ if (vt->global != NULL)
+ {
+ fprintf(f, " global :\n");
+ this->print_expression_list(f, vt->global);
+ }
+
+ if (vt->local != NULL)
+ {
+ fprintf(f, " local :\n");
+ this->print_expression_list(f, vt->local);
+ }
+
+ fprintf(f, " }");
+ if (vt->dependencies != NULL)
+ {
+ const Version_dependency_list* deps = vt->dependencies;
+ for (size_t j = 0; j < deps->dependencies.size(); ++j)
+ {
+ if (j < deps->dependencies.size() - 1)
+ fprintf(f, "\n");
+ fprintf(f, " %s", deps->dependencies[j].c_str());
+ }
+ }
+ fprintf(f, ";\n");
+ }
+
+ fprintf(f, "}\n");
+}
+
+void
+Version_script_info::print_expression_list(
+ FILE* f,
+ const Version_expression_list* vel) const
+{
+ Version_script_info::Language current_language = LANGUAGE_C;
+ for (size_t i = 0; i < vel->expressions.size(); ++i)
+ {
+ const Version_expression& ve(vel->expressions[i]);
+
+ if (ve.language != current_language)
+ {
+ if (current_language != LANGUAGE_C)
+ fprintf(f, " }\n");
+ switch (ve.language)
+ {
+ case LANGUAGE_C:
+ break;
+ case LANGUAGE_CXX:
+ fprintf(f, " extern \"C++\" {\n");
+ break;
+ case LANGUAGE_JAVA:
+ fprintf(f, " extern \"Java\" {\n");
+ break;
+ default:
+ gold_unreachable();
+ }
+ current_language = ve.language;
+ }
+
+ fprintf(f, " ");
+ if (current_language != LANGUAGE_C)
+ fprintf(f, " ");
+
+ if (ve.exact_match)
+ fprintf(f, "\"");
+ fprintf(f, "%s", ve.pattern.c_str());
+ if (ve.exact_match)
+ fprintf(f, "\"");
+
+ fprintf(f, "\n");
+ }
+
+ if (current_language != LANGUAGE_C)
+ fprintf(f, " }\n");
+}
+
+} // End namespace gold.
+
+// The remaining functions are extern "C", so it's clearer to not put
+// them in namespace gold.
+
+using namespace gold;
+
+// This function is called by the bison parser to return the next
+// token.
+
+extern "C" int
+yylex(YYSTYPE* lvalp, void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ const Token* token = closure->next_token();
+ switch (token->classification())
+ {
+ default:
+ gold_unreachable();
+
+ case Token::TOKEN_INVALID:
+ yyerror(closurev, "invalid character");
+ return 0;
+
+ case Token::TOKEN_EOF:
+ return 0;
+
+ case Token::TOKEN_STRING:
+ {
+ // This is either a keyword or a STRING.
+ size_t len;
+ const char* str = token->string_value(&len);
+ int parsecode = 0;
+ switch (closure->lex_mode())
+ {
+ case Lex::LINKER_SCRIPT:
+ parsecode = script_keywords.keyword_to_parsecode(str, len);
+ break;
+ case Lex::VERSION_SCRIPT:
+ parsecode = version_script_keywords.keyword_to_parsecode(str, len);
+ break;
+ case Lex::DYNAMIC_LIST:
+ parsecode = dynamic_list_keywords.keyword_to_parsecode(str, len);
+ break;
+ default:
+ break;
+ }
+ if (parsecode != 0)
+ return parsecode;
+ lvalp->string.value = str;
+ lvalp->string.length = len;
+ return STRING;
+ }
+
+ case Token::TOKEN_QUOTED_STRING:
+ lvalp->string.value = token->string_value(&lvalp->string.length);
+ return QUOTED_STRING;
+
+ case Token::TOKEN_OPERATOR:
+ return token->operator_value();
+
+ case Token::TOKEN_INTEGER:
+ lvalp->integer = token->integer_value();
+ return INTEGER;
+ }
+}
+
+// This function is called by the bison parser to report an error.
+
+extern "C" void
+yyerror(void* closurev, const char* message)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ gold_error(_("%s:%d:%d: %s"), closure->filename(), closure->lineno(),
+ closure->charpos(), message);
+}
+
+// Called by the bison parser to add an external symbol to the link.
+
+extern "C" void
+script_add_extern(void* closurev, const char* name, size_t length)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->script_options()->add_symbol_reference(name, length);
+}
+
+// Called by the bison parser to add a file to the link.
+
+extern "C" void
+script_add_file(void* closurev, const char* name, size_t length)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+
+ // If this is an absolute path, and we found the script in the
+ // sysroot, then we want to prepend the sysroot to the file name.
+ // For example, this is how we handle a cross link to the x86_64
+ // libc.so, which refers to /lib/libc.so.6.
+ std::string name_string(name, length);
+ const char* extra_search_path = ".";
+ std::string script_directory;
+ if (IS_ABSOLUTE_PATH(name_string.c_str()))
+ {
+ if (closure->is_in_sysroot())
+ {
+ const std::string& sysroot(parameters->options().sysroot());
+ gold_assert(!sysroot.empty());
+ name_string = sysroot + name_string;
+ }
+ }
+ else
+ {
+ // In addition to checking the normal library search path, we
+ // also want to check in the script-directory.
+ const char* slash = strrchr(closure->filename(), '/');
+ if (slash != NULL)
+ {
+ script_directory.assign(closure->filename(),
+ slash - closure->filename() + 1);
+ extra_search_path = script_directory.c_str();
+ }
+ }
+
+ Input_file_argument file(name_string.c_str(),
+ Input_file_argument::INPUT_FILE_TYPE_FILE,
+ extra_search_path, false,
+ closure->position_dependent_options());
+ Input_argument& arg = closure->inputs()->add_file(file);
+ arg.set_script_info(closure->script_info());
+}
+
+// Called by the bison parser to add a library to the link.
+
+extern "C" void
+script_add_library(void* closurev, const char* name, size_t length)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ std::string name_string(name, length);
+
+ if (name_string[0] != 'l')
+ gold_error(_("library name must be prefixed with -l"));
+
+ Input_file_argument file(name_string.c_str() + 1,
+ Input_file_argument::INPUT_FILE_TYPE_LIBRARY,
+ "", false,
+ closure->position_dependent_options());
+ Input_argument& arg = closure->inputs()->add_file(file);
+ arg.set_script_info(closure->script_info());
+}
+
+// Called by the bison parser to start a group. If we are already in
+// a group, that means that this script was invoked within a
+// --start-group --end-group sequence on the command line, or that
+// this script was found in a GROUP of another script. In that case,
+// we simply continue the existing group, rather than starting a new
+// one. It is possible to construct a case in which this will do
+// something other than what would happen if we did a recursive group,
+// but it's hard to imagine why the different behaviour would be
+// useful for a real program. Avoiding recursive groups is simpler
+// and more efficient.
+
+extern "C" void
+script_start_group(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ if (!closure->in_group())
+ closure->inputs()->start_group();
+}
+
+// Called by the bison parser at the end of a group.
+
+extern "C" void
+script_end_group(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ if (!closure->in_group())
+ closure->inputs()->end_group();
+}
+
+// Called by the bison parser to start an AS_NEEDED list.
+
+extern "C" void
+script_start_as_needed(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->position_dependent_options().set_as_needed(true);
+}
+
+// Called by the bison parser at the end of an AS_NEEDED list.
+
+extern "C" void
+script_end_as_needed(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->position_dependent_options().set_as_needed(false);
+}
+
+// Called by the bison parser to set the entry symbol.
+
+extern "C" void
+script_set_entry(void* closurev, const char* entry, size_t length)
+{
+ // We'll parse this exactly the same as --entry=ENTRY on the commandline
+ // TODO(csilvers): FIXME -- call set_entry directly.
+ std::string arg("--entry=");
+ arg.append(entry, length);
+ script_parse_option(closurev, arg.c_str(), arg.size());
+}
+
+// Called by the bison parser to set whether to define common symbols.
+
+extern "C" void
+script_set_common_allocation(void* closurev, int set)
+{
+ const char* arg = set != 0 ? "--define-common" : "--no-define-common";
+ script_parse_option(closurev, arg, strlen(arg));
+}
+
+// Called by the bison parser to refer to a symbol.
+
+extern "C" Expression*
+script_symbol(void* closurev, const char* name, size_t length)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ if (length != 1 || name[0] != '.')
+ closure->script_options()->add_symbol_reference(name, length);
+ return script_exp_string(name, length);
+}
+
+// Called by the bison parser to define a symbol.
+
+extern "C" void
+script_set_symbol(void* closurev, const char* name, size_t length,
+ Expression* value, int providei, int hiddeni)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ const bool provide = providei != 0;
+ const bool hidden = hiddeni != 0;
+ closure->script_options()->add_symbol_assignment(name, length,
+ closure->parsing_defsym(),
+ value, provide, hidden);
+ closure->clear_skip_on_incompatible_target();
+}
+
+// Called by the bison parser to add an assertion.
+
+extern "C" void
+script_add_assertion(void* closurev, Expression* check, const char* message,
+ size_t messagelen)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->script_options()->add_assertion(check, message, messagelen);
+ closure->clear_skip_on_incompatible_target();
+}
+
+// Called by the bison parser to parse an OPTION.
+
+extern "C" void
+script_parse_option(void* closurev, const char* option, size_t length)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ // We treat the option as a single command-line option, even if
+ // it has internal whitespace.
+ if (closure->command_line() == NULL)
+ {
+ // There are some options that we could handle here--e.g.,
+ // -lLIBRARY. Should we bother?
+ gold_warning(_("%s:%d:%d: ignoring command OPTION; OPTION is only valid"
+ " for scripts specified via -T/--script"),
+ closure->filename(), closure->lineno(), closure->charpos());
+ }
+ else
+ {
+ bool past_a_double_dash_option = false;
+ const char* mutable_option = strndup(option, length);
+ gold_assert(mutable_option != NULL);
+ closure->command_line()->process_one_option(1, &mutable_option, 0,
+ &past_a_double_dash_option);
+ // The General_options class will quite possibly store a pointer
+ // into mutable_option, so we can't free it. In cases the class
+ // does not store such a pointer, this is a memory leak. Alas. :(
+ }
+ closure->clear_skip_on_incompatible_target();
+}
+
+// Called by the bison parser to handle OUTPUT_FORMAT. OUTPUT_FORMAT
+// takes either one or three arguments. In the three argument case,
+// the format depends on the endianness option, which we don't
+// currently support (FIXME). If we see an OUTPUT_FORMAT for the
+// wrong format, then we want to search for a new file. Returning 0
+// here will cause the parser to immediately abort.
+
+extern "C" int
+script_check_output_format(void* closurev,
+ const char* default_name, size_t default_length,
+ const char*, size_t, const char*, size_t)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ std::string name(default_name, default_length);
+ Target* target = select_target_by_bfd_name(name.c_str());
+ if (target == NULL || !parameters->is_compatible_target(target))
+ {
+ if (closure->skip_on_incompatible_target())
+ {
+ closure->set_found_incompatible_target();
+ return 0;
+ }
+ // FIXME: Should we warn about the unknown target?
+ }
+ return 1;
+}
+
+// Called by the bison parser to handle TARGET.
+
+extern "C" void
+script_set_target(void* closurev, const char* target, size_t len)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ std::string s(target, len);
+ General_options::Object_format format_enum;
+ format_enum = General_options::string_to_object_format(s.c_str());
+ closure->position_dependent_options().set_format_enum(format_enum);
+}
+
+// Called by the bison parser to handle SEARCH_DIR. This is handled
+// exactly like a -L option.
+
+extern "C" void
+script_add_search_dir(void* closurev, const char* option, size_t length)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ if (closure->command_line() == NULL)
+ gold_warning(_("%s:%d:%d: ignoring SEARCH_DIR; SEARCH_DIR is only valid"
+ " for scripts specified via -T/--script"),
+ closure->filename(), closure->lineno(), closure->charpos());
+ else if (!closure->command_line()->options().nostdlib())
+ {
+ std::string s = "-L" + std::string(option, length);
+ script_parse_option(closurev, s.c_str(), s.size());
+ }
+}
+
+/* Called by the bison parser to push the lexer into expression
+ mode. */
+
+extern "C" void
+script_push_lex_into_expression_mode(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->push_lex_mode(Lex::EXPRESSION);
+}
+
+/* Called by the bison parser to push the lexer into version
+ mode. */
+
+extern "C" void
+script_push_lex_into_version_mode(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ if (closure->version_script()->is_finalized())
+ gold_error(_("%s:%d:%d: invalid use of VERSION in input file"),
+ closure->filename(), closure->lineno(), closure->charpos());
+ closure->push_lex_mode(Lex::VERSION_SCRIPT);
+}
+
+/* Called by the bison parser to pop the lexer mode. */
+
+extern "C" void
+script_pop_lex_mode(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->pop_lex_mode();
+}
+
+// Register an entire version node. For example:
+//
+// GLIBC_2.1 {
+// global: foo;
+// } GLIBC_2.0;
+//
+// - tag is "GLIBC_2.1"
+// - tree contains the information "global: foo"
+// - deps contains "GLIBC_2.0"
+
+extern "C" void
+script_register_vers_node(void*,
+ const char* tag,
+ int taglen,
+ struct Version_tree* tree,
+ struct Version_dependency_list* deps)
+{
+ gold_assert(tree != NULL);
+ tree->dependencies = deps;
+ if (tag != NULL)
+ tree->tag = std::string(tag, taglen);
+}
+
+// Add a dependencies to the list of existing dependencies, if any,
+// and return the expanded list.
+
+extern "C" struct Version_dependency_list*
+script_add_vers_depend(void* closurev,
+ struct Version_dependency_list* all_deps,
+ const char* depend_to_add, int deplen)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ if (all_deps == NULL)
+ all_deps = closure->version_script()->allocate_dependency_list();
+ all_deps->dependencies.push_back(std::string(depend_to_add, deplen));
+ return all_deps;
+}
+
+// Add a pattern expression to an existing list of expressions, if any.
+
+extern "C" struct Version_expression_list*
+script_new_vers_pattern(void* closurev,
+ struct Version_expression_list* expressions,
+ const char* pattern, int patlen, int exact_match)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ if (expressions == NULL)
+ expressions = closure->version_script()->allocate_expression_list();
+ expressions->expressions.push_back(
+ Version_expression(std::string(pattern, patlen),
+ closure->get_current_language(),
+ static_cast<bool>(exact_match)));
+ return expressions;
+}
+
+// Attaches b to the end of a, and clears b. So a = a + b and b = {}.
+
+extern "C" struct Version_expression_list*
+script_merge_expressions(struct Version_expression_list* a,
+ struct Version_expression_list* b)
+{
+ a->expressions.insert(a->expressions.end(),
+ b->expressions.begin(), b->expressions.end());
+ // We could delete b and remove it from expressions_lists_, but
+ // that's a lot of work. This works just as well.
+ b->expressions.clear();
+ return a;
+}
+
+// Combine the global and local expressions into a a Version_tree.
+
+extern "C" struct Version_tree*
+script_new_vers_node(void* closurev,
+ struct Version_expression_list* global,
+ struct Version_expression_list* local)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ Version_tree* tree = closure->version_script()->allocate_version_tree();
+ tree->global = global;
+ tree->local = local;
+ return tree;
+}
+
+// Handle a transition in language, such as at the
+// start or end of 'extern "C++"'
+
+extern "C" void
+version_script_push_lang(void* closurev, const char* lang, int langlen)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ std::string language(lang, langlen);
+ Version_script_info::Language code;
+ if (language.empty() || language == "C")
+ code = Version_script_info::LANGUAGE_C;
+ else if (language == "C++")
+ code = Version_script_info::LANGUAGE_CXX;
+ else if (language == "Java")
+ code = Version_script_info::LANGUAGE_JAVA;
+ else
+ {
+ char* buf = new char[langlen + 100];
+ snprintf(buf, langlen + 100,
+ _("unrecognized version script language '%s'"),
+ language.c_str());
+ yyerror(closurev, buf);
+ delete[] buf;
+ code = Version_script_info::LANGUAGE_C;
+ }
+ closure->push_language(code);
+}
+
+extern "C" void
+version_script_pop_lang(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->pop_language();
+}
+
+// Called by the bison parser to start a SECTIONS clause.
+
+extern "C" void
+script_start_sections(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->script_options()->script_sections()->start_sections();
+ closure->clear_skip_on_incompatible_target();
+}
+
+// Called by the bison parser to finish a SECTIONS clause.
+
+extern "C" void
+script_finish_sections(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->script_options()->script_sections()->finish_sections();
+}
+
+// Start processing entries for an output section.
+
+extern "C" void
+script_start_output_section(void* closurev, const char* name, size_t namelen,
+ const struct Parser_output_section_header* header)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->script_options()->script_sections()->start_output_section(name,
+ namelen,
+ header);
+}
+
+// Finish processing entries for an output section.
+
+extern "C" void
+script_finish_output_section(void* closurev,
+ const struct Parser_output_section_trailer* trail)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->script_options()->script_sections()->finish_output_section(trail);
+}
+
+// Add a data item (e.g., "WORD (0)") to the current output section.
+
+extern "C" void
+script_add_data(void* closurev, int data_token, Expression* val)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ int size;
+ bool is_signed = true;
+ switch (data_token)
+ {
+ case QUAD:
+ size = 8;
+ is_signed = false;
+ break;
+ case SQUAD:
+ size = 8;
+ break;
+ case LONG:
+ size = 4;
+ break;
+ case SHORT:
+ size = 2;
+ break;
+ case BYTE:
+ size = 1;
+ break;
+ default:
+ gold_unreachable();
+ }
+ closure->script_options()->script_sections()->add_data(size, is_signed, val);
+}
+
+// Add a clause setting the fill value to the current output section.
+
+extern "C" void
+script_add_fill(void* closurev, Expression* val)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->script_options()->script_sections()->add_fill(val);
+}
+
+// Add a new input section specification to the current output
+// section.
+
+extern "C" void
+script_add_input_section(void* closurev,
+ const struct Input_section_spec* spec,
+ int keepi)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ bool keep = keepi != 0;
+ closure->script_options()->script_sections()->add_input_section(spec, keep);
+}
+
+// When we see DATA_SEGMENT_ALIGN we record that following output
+// sections may be relro.
+
+extern "C" void
+script_data_segment_align(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ if (!closure->script_options()->saw_sections_clause())
+ gold_error(_("%s:%d:%d: DATA_SEGMENT_ALIGN not in SECTIONS clause"),
+ closure->filename(), closure->lineno(), closure->charpos());
+ else
+ closure->script_options()->script_sections()->data_segment_align();
+}
+
+// When we see DATA_SEGMENT_RELRO_END we know that all output sections
+// since DATA_SEGMENT_ALIGN should be relro.
+
+extern "C" void
+script_data_segment_relro_end(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ if (!closure->script_options()->saw_sections_clause())
+ gold_error(_("%s:%d:%d: DATA_SEGMENT_ALIGN not in SECTIONS clause"),
+ closure->filename(), closure->lineno(), closure->charpos());
+ else
+ closure->script_options()->script_sections()->data_segment_relro_end();
+}
+
+// Create a new list of string/sort pairs.
+
+extern "C" String_sort_list_ptr
+script_new_string_sort_list(const struct Wildcard_section* string_sort)
+{
+ return new String_sort_list(1, *string_sort);
+}
+
+// Add an entry to a list of string/sort pairs. The way the parser
+// works permits us to simply modify the first parameter, rather than
+// copy the vector.
+
+extern "C" String_sort_list_ptr
+script_string_sort_list_add(String_sort_list_ptr pv,
+ const struct Wildcard_section* string_sort)
+{
+ if (pv == NULL)
+ return script_new_string_sort_list(string_sort);
+ else
+ {
+ pv->push_back(*string_sort);
+ return pv;
+ }
+}
+
+// Create a new list of strings.
+
+extern "C" String_list_ptr
+script_new_string_list(const char* str, size_t len)
+{
+ return new String_list(1, std::string(str, len));
+}
+
+// Add an element to a list of strings. The way the parser works
+// permits us to simply modify the first parameter, rather than copy
+// the vector.
+
+extern "C" String_list_ptr
+script_string_list_push_back(String_list_ptr pv, const char* str, size_t len)
+{
+ if (pv == NULL)
+ return script_new_string_list(str, len);
+ else
+ {
+ pv->push_back(std::string(str, len));
+ return pv;
+ }
+}
+
+// Concatenate two string lists. Either or both may be NULL. The way
+// the parser works permits us to modify the parameters, rather than
+// copy the vector.
+
+extern "C" String_list_ptr
+script_string_list_append(String_list_ptr pv1, String_list_ptr pv2)
+{
+ if (pv1 == NULL)
+ return pv2;
+ if (pv2 == NULL)
+ return pv1;
+ pv1->insert(pv1->end(), pv2->begin(), pv2->end());
+ return pv1;
+}
+
+// Add a new program header.
+
+extern "C" void
+script_add_phdr(void* closurev, const char* name, size_t namelen,
+ unsigned int type, const Phdr_info* info)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ bool includes_filehdr = info->includes_filehdr != 0;
+ bool includes_phdrs = info->includes_phdrs != 0;
+ bool is_flags_valid = info->is_flags_valid != 0;
+ Script_sections* ss = closure->script_options()->script_sections();
+ ss->add_phdr(name, namelen, type, includes_filehdr, includes_phdrs,
+ is_flags_valid, info->flags, info->load_address);
+ closure->clear_skip_on_incompatible_target();
+}
+
+// Convert a program header string to a type.
+
+#define PHDR_TYPE(NAME) { #NAME, sizeof(#NAME) - 1, elfcpp::NAME }
+
+static struct
+{
+ const char* name;
+ size_t namelen;
+ unsigned int val;
+} phdr_type_names[] =
+{
+ PHDR_TYPE(PT_NULL),
+ PHDR_TYPE(PT_LOAD),
+ PHDR_TYPE(PT_DYNAMIC),
+ PHDR_TYPE(PT_INTERP),
+ PHDR_TYPE(PT_NOTE),
+ PHDR_TYPE(PT_SHLIB),
+ PHDR_TYPE(PT_PHDR),
+ PHDR_TYPE(PT_TLS),
+ PHDR_TYPE(PT_GNU_EH_FRAME),
+ PHDR_TYPE(PT_GNU_STACK),
+ PHDR_TYPE(PT_GNU_RELRO)
+};
+
+extern "C" unsigned int
+script_phdr_string_to_type(void* closurev, const char* name, size_t namelen)
+{
+ for (unsigned int i = 0;
+ i < sizeof(phdr_type_names) / sizeof(phdr_type_names[0]);
+ ++i)
+ if (namelen == phdr_type_names[i].namelen
+ && strncmp(name, phdr_type_names[i].name, namelen) == 0)
+ return phdr_type_names[i].val;
+ yyerror(closurev, _("unknown PHDR type (try integer)"));
+ return elfcpp::PT_NULL;
+}
+
+extern "C" void
+script_saw_segment_start_expression(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ Script_sections* ss = closure->script_options()->script_sections();
+ ss->set_saw_segment_start_expression(true);
+}
+
+extern "C" void
+script_set_section_region(void* closurev, const char* name, size_t namelen,
+ int set_vma)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ if (!closure->script_options()->saw_sections_clause())
+ {
+ gold_error(_("%s:%d:%d: MEMORY region '%.*s' referred to outside of "
+ "SECTIONS clause"),
+ closure->filename(), closure->lineno(), closure->charpos(),
+ static_cast<int>(namelen), name);
+ return;
+ }
+
+ Script_sections* ss = closure->script_options()->script_sections();
+ Memory_region* mr = ss->find_memory_region(name, namelen);
+ if (mr == NULL)
+ {
+ gold_error(_("%s:%d:%d: MEMORY region '%.*s' not declared"),
+ closure->filename(), closure->lineno(), closure->charpos(),
+ static_cast<int>(namelen), name);
+ return;
+ }
+
+ ss->set_memory_region(mr, set_vma);
+}
+
+extern "C" void
+script_add_memory(void* closurev, const char* name, size_t namelen,
+ unsigned int attrs, Expression* origin, Expression* length)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ Script_sections* ss = closure->script_options()->script_sections();
+ ss->add_memory_region(name, namelen, attrs, origin, length);
+}
+
+extern "C" unsigned int
+script_parse_memory_attr(void* closurev, const char* attrs, size_t attrlen,
+ int invert)
+{
+ int attributes = 0;
+
+ while (attrlen--)
+ switch (*attrs++)
+ {
+ case 'R':
+ case 'r':
+ attributes |= MEM_READABLE; break;
+ case 'W':
+ case 'w':
+ attributes |= MEM_READABLE | MEM_WRITEABLE; break;
+ case 'X':
+ case 'x':
+ attributes |= MEM_EXECUTABLE; break;
+ case 'A':
+ case 'a':
+ attributes |= MEM_ALLOCATABLE; break;
+ case 'I':
+ case 'i':
+ case 'L':
+ case 'l':
+ attributes |= MEM_INITIALIZED; break;
+ default:
+ yyerror(closurev, _("unknown MEMORY attribute"));
+ }
+
+ if (invert)
+ attributes = (~ attributes) & MEM_ATTR_MASK;
+
+ return attributes;
+}
+
+extern "C" void
+script_include_directive(void* closurev, const char* filename, size_t length)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ std::string name(filename, length);
+ Command_line* cmdline = closure->command_line();
+ read_script_file(name.c_str(), cmdline, &cmdline->script_options(),
+ PARSING_LINKER_SCRIPT, Lex::LINKER_SCRIPT);
+}
+
+// Functions for memory regions.
+
+extern "C" Expression*
+script_exp_function_origin(void* closurev, const char* name, size_t namelen)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ Script_sections* ss = closure->script_options()->script_sections();
+ Expression* origin = ss->find_memory_region_origin(name, namelen);
+
+ if (origin == NULL)
+ {
+ gold_error(_("undefined memory region '%s' referenced "
+ "in ORIGIN expression"),
+ name);
+ // Create a dummy expression to prevent crashes later on.
+ origin = script_exp_integer(0);
+ }
+
+ return origin;
+}
+
+extern "C" Expression*
+script_exp_function_length(void* closurev, const char* name, size_t namelen)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ Script_sections* ss = closure->script_options()->script_sections();
+ Expression* length = ss->find_memory_region_length(name, namelen);
+
+ if (length == NULL)
+ {
+ gold_error(_("undefined memory region '%s' referenced "
+ "in LENGTH expression"),
+ name);
+ // Create a dummy expression to prevent crashes later on.
+ length = script_exp_integer(0);
+ }
+
+ return length;
+}
diff --git a/binutils-2.25/gold/script.h b/binutils-2.25/gold/script.h
new file mode 100644
index 00000000..f41f4383
--- /dev/null
+++ b/binutils-2.25/gold/script.h
@@ -0,0 +1,594 @@
+// script.h -- handle linker scripts for gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 implement a subset of the original GNU ld linker script language
+// for compatibility. The goal is not to implement the entire
+// language. It is merely to implement enough to handle common uses.
+// In particular we need to handle /usr/lib/libc.so on a typical
+// GNU/Linux system, and we want to handle linker scripts used by the
+// Linux kernel build.
+
+#ifndef GOLD_SCRIPT_H
+#define GOLD_SCRIPT_H
+
+#include <cstdio>
+#include <string>
+#include <vector>
+
+#include "script-sections.h"
+
+namespace gold
+{
+
+class General_options;
+class Command_line;
+class Symbol_table;
+class Layout;
+class Mapfile;
+class Input_argument;
+class Input_arguments;
+class Input_objects;
+class Input_group;
+class Input_file;
+class Output_segment;
+class Task_token;
+class Workqueue;
+struct Version_dependency_list;
+struct Version_expression_list;
+struct Version_tree;
+struct Version_expression;
+class Lazy_demangler;
+class Incremental_script_entry;
+
+// This class represents an expression in a linker script.
+
+class Expression
+{
+ protected:
+ // These should only be created by child classes.
+ Expression()
+ { }
+
+ public:
+ virtual ~Expression()
+ { }
+
+ // Return the value of the expression which is not permitted to
+ // refer to the dot symbol. CHECK_ASSERTIONS is true if we should
+ // check whether assertions are true.
+ uint64_t
+ eval(const Symbol_table*, const Layout*, bool check_assertions);
+
+ // Return the value of an expression which is permitted to refer to
+ // the dot symbol. DOT_VALUE is the absolute value of the dot
+ // symbol. DOT_SECTION is the section in which dot is defined; it
+ // should be NULL if the dot symbol has an absolute value (e.g., is
+ // defined in a SECTIONS clause outside of any output section
+ // definition). This sets *RESULT_SECTION to indicate where the
+ // value is defined. If the value is absolute *RESULT_SECTION will
+ // be NULL. Note that the returned value is still an absolute
+ // value; to get a section relative value the caller must subtract
+ // the section address. If RESULT_ALIGNMENT is not NULL, this sets
+ // *RESULT_ALIGNMENT to the alignment of the value of that alignment
+ // is larger than *RESULT_ALIGNMENT; this will only be non-zero if
+ // this is an ALIGN expression. If IS_SECTION_DOT_ASSIGMENT is true,
+ // we are evaluating an assignment to dot within an output section,
+ // and an absolute value should be interpreted as an offset within
+ // the section.
+ uint64_t
+ eval_with_dot(const Symbol_table*, const Layout*, bool check_assertions,
+ uint64_t dot_value, Output_section* dot_section,
+ Output_section** result_section, uint64_t* result_alignment,
+ bool is_section_dot_assignment);
+
+ // Return the value of an expression which may or may not be
+ // permitted to refer to the dot symbol, depending on
+ // is_dot_available. If IS_SECTION_DOT_ASSIGMENT is true,
+ // we are evaluating an assignment to dot within an output section,
+ // and an absolute value should be interpreted as an offset within
+ // the section.
+ uint64_t
+ eval_maybe_dot(const Symbol_table*, const Layout*, bool check_assertions,
+ bool is_dot_available, uint64_t dot_value,
+ Output_section* dot_section,
+ Output_section** result_section, uint64_t* result_alignment,
+ bool is_section_dot_assignment);
+
+ // Print the expression to the FILE. This is for debugging.
+ virtual void
+ print(FILE*) const = 0;
+
+ protected:
+ struct Expression_eval_info;
+
+ public:
+ // Compute the value of the expression (implemented by child class).
+ // This is public rather than protected because it is called
+ // directly by children of Expression on other Expression objects.
+ virtual uint64_t
+ value(const Expression_eval_info*) = 0;
+
+ private:
+ // May not be copied.
+ Expression(const Expression&);
+ Expression& operator=(const Expression&);
+};
+
+
+// Version_script_info stores information parsed from the version
+// script, either provided by --version-script or as part of a linker
+// script. A single Version_script_info object per target is owned by
+// Script_options.
+
+class Version_script_info
+{
+ public:
+ // The languages which can be specified in a versionn script.
+ enum Language
+ {
+ LANGUAGE_C, // No demangling.
+ LANGUAGE_CXX, // C++ demangling.
+ LANGUAGE_JAVA, // Java demangling.
+ LANGUAGE_COUNT
+ };
+
+ Version_script_info();
+
+ ~Version_script_info();
+
+ // Clear everything.
+ void
+ clear();
+
+ // Finalize the version control information.
+ void
+ finalize();
+
+ // Return whether the information is finalized.
+ bool
+ is_finalized() const
+ { return this->is_finalized_; }
+
+ // Return whether any version were defined in the version script.
+ bool
+ empty() const
+ { return this->version_trees_.empty(); }
+
+ // If there is a version associated with SYMBOL, return true, and
+ // set *VERSION to the version, and *IS_GLOBAL to whether the symbol
+ // should be global. Otherwise, return false.
+ bool
+ get_symbol_version(const char* symbol, std::string* version,
+ bool* is_global) const;
+
+ // Return whether this symbol matches the local: section of some
+ // version.
+ bool
+ symbol_is_local(const char* symbol) const
+ {
+ bool is_global;
+ return (this->get_symbol_version(symbol, NULL, &is_global)
+ && !is_global);
+ }
+
+ // Return the names of versions defined in the version script.
+ std::vector<std::string>
+ get_versions() const;
+
+ // Return the list of dependencies for this version.
+ std::vector<std::string>
+ get_dependencies(const char* version) const;
+
+ // The following functions should only be used by the bison helper
+ // functions. They allocate new structs whose memory belongs to
+ // Version_script_info. The bison functions copy the information
+ // from the version script into these structs.
+ struct Version_dependency_list*
+ allocate_dependency_list();
+
+ struct Version_expression_list*
+ allocate_expression_list();
+
+ struct Version_tree*
+ allocate_version_tree();
+
+ // Build the lookup tables after all data have been read.
+ void
+ build_lookup_tables();
+
+ // Give an error if there are any unmatched names in the version
+ // script.
+ void
+ check_unmatched_names(const Symbol_table*) const;
+
+ // Print contents to the FILE. This is for debugging.
+ void
+ print(FILE*) const;
+
+ private:
+ void
+ print_expression_list(FILE* f, const Version_expression_list*) const;
+
+ bool
+ get_symbol_version_helper(const char* symbol,
+ bool check_global,
+ std::string* pversion) const;
+
+ // Fast lookup information for a given language.
+
+ // We map from exact match strings to Version_tree's. Historically
+ // version scripts sometimes have the same symbol multiple times,
+ // which is ambiguous. We warn about that case by storing the
+ // second Version_tree we see.
+ struct Version_tree_match
+ {
+ Version_tree_match(const Version_tree* r, bool ig,
+ const Version_expression* e)
+ : real(r), is_global(ig), expression(e), ambiguous(NULL)
+ { }
+
+ // The Version_tree that we return.
+ const Version_tree* real;
+ // True if this is a global match for the REAL member, false if it
+ // is a local match.
+ bool is_global;
+ // Point back to the Version_expression for which we created this
+ // match.
+ const Version_expression* expression;
+ // If not NULL, another Version_tree that defines the symbol.
+ const Version_tree* ambiguous;
+ };
+
+ // Map from an exact match string to a Version_tree.
+
+ typedef Unordered_map<std::string, Version_tree_match> Exact;
+
+ // Fast lookup information for a glob pattern.
+ struct Glob
+ {
+ Glob()
+ : expression(NULL), version(NULL), is_global(false)
+ { }
+
+ Glob(const Version_expression* e, const Version_tree* v, bool ig)
+ : expression(e), version(v), is_global(ig)
+ { }
+
+ // A pointer to the version expression holding the pattern to
+ // match and the language to use for demangling the symbol before
+ // doing the match.
+ const Version_expression* expression;
+ // The Version_tree we use if this pattern matches.
+ const Version_tree* version;
+ // True if this is a global symbol.
+ bool is_global;
+ };
+
+ typedef std::vector<Glob> Globs;
+
+ bool
+ unquote(std::string*) const;
+
+ void
+ add_exact_match(const std::string&, const Version_tree*, bool is_global,
+ const Version_expression*, Exact*);
+
+ void
+ build_expression_list_lookup(const Version_expression_list*,
+ const Version_tree*, bool);
+
+ const char*
+ get_name_to_match(const char*, int,
+ Lazy_demangler*, Lazy_demangler*) const;
+
+ // All the version dependencies we allocate.
+ std::vector<Version_dependency_list*> dependency_lists_;
+ // All the version expressions we allocate.
+ std::vector<Version_expression_list*> expression_lists_;
+ // The list of versions.
+ std::vector<Version_tree*> version_trees_;
+ // Exact matches for global symbols, by language.
+ Exact* exact_[LANGUAGE_COUNT];
+ // A vector of glob patterns mapping to Version_trees.
+ Globs globs_;
+ // The default version to use, if there is one. This is from a
+ // pattern of "*".
+ const Version_tree* default_version_;
+ // True if the default version is global.
+ bool default_is_global_;
+ // Whether this has been finalized.
+ bool is_finalized_;
+};
+
+// This class manages assignments to symbols. These can appear in
+// three different locations in scripts: outside of a SECTIONS clause,
+// within a SECTIONS clause, and within an output section definition
+// within a SECTIONS clause. This can also appear on the command line
+// via the --defsym command line option.
+
+class Symbol_assignment
+{
+ public:
+ Symbol_assignment(const char* name, size_t namelen, bool is_defsym,
+ Expression* val, bool provide, bool hidden)
+ : name_(name, namelen), val_(val), is_defsym_(is_defsym),
+ provide_(provide), hidden_(hidden), sym_(NULL)
+ { }
+
+ // Add the symbol to the symbol table.
+ void
+ add_to_table(Symbol_table*);
+
+ // Finalize the symbol value.
+ void
+ finalize(Symbol_table*, const Layout*);
+
+ // Finalize the symbol value when it can refer to the dot symbol.
+ void
+ finalize_with_dot(Symbol_table*, const Layout*, uint64_t dot_value,
+ Output_section* dot_section);
+
+ // Set the symbol value, but only if the value is absolute or relative to
+ // DOT_SECTION. This is used while processing a SECTIONS clause.
+ // We assume that dot is an absolute value here. We do not check assertions.
+ void
+ set_if_absolute(Symbol_table*, const Layout*, bool is_dot_available,
+ uint64_t dot_value, Output_section* dot_section);
+
+ const std::string&
+ name() const
+ { return this->name_; }
+
+ // Print the assignment to the FILE. This is for debugging.
+ void
+ print(FILE*) const;
+
+ private:
+ // Shared by finalize and finalize_with_dot.
+ void
+ finalize_maybe_dot(Symbol_table*, const Layout*, bool is_dot_available,
+ uint64_t dot_value, Output_section* dot_section);
+
+ // Sized version of finalize.
+ template<int size>
+ void
+ sized_finalize(Symbol_table*, const Layout*, bool is_dot_available,
+ uint64_t dot_value, Output_section*);
+
+ // Symbol name.
+ std::string name_;
+ // Expression to assign to symbol.
+ Expression* val_;
+ // True if this symbol is defined by a --defsym, false if it is
+ // defined in a linker script.
+ bool is_defsym_;
+ // Whether the assignment should be provided (only set if there is
+ // an undefined reference to the symbol.
+ bool provide_;
+ // Whether the assignment should be hidden.
+ bool hidden_;
+ // The entry in the symbol table.
+ Symbol* sym_;
+};
+
+// This class manages assertions in linker scripts. These can appear
+// in all the places where a Symbol_assignment can appear.
+
+class Script_assertion
+{
+ public:
+ Script_assertion(Expression* check, const char* message,
+ size_t messagelen)
+ : check_(check), message_(message, messagelen)
+ { }
+
+ // Check the assertion.
+ void
+ check(const Symbol_table*, const Layout*);
+
+ // Print the assertion to the FILE. This is for debugging.
+ void
+ print(FILE*) const;
+
+ private:
+ // The expression to check.
+ Expression* check_;
+ // The message to issue if the expression fails.
+ std::string message_;
+};
+
+// We can read a linker script in two different contexts: when
+// initially parsing the command line, and when we find an input file
+// which is actually a linker script. Also some of the data which can
+// be set by a linker script can also be set via command line options
+// like -e and --defsym. This means that we have a type of data which
+// can be set both during command line option parsing and while
+// reading input files. We store that data in an instance of this
+// object. We will keep pointers to that instance in both the
+// Command_line and Layout objects.
+
+class Script_options
+{
+ public:
+ Script_options();
+
+ // Add a symbol to be defined.
+ void
+ add_symbol_assignment(const char* name, size_t length, bool is_defsym,
+ Expression* value, bool provide, bool hidden);
+
+ // Look for an assigned symbol.
+ bool
+ is_pending_assignment(const char* name);
+
+ // Add a reference to a symbol.
+ void
+ add_symbol_reference(const char* name, size_t length);
+
+ // Add an assertion.
+ void
+ add_assertion(Expression* check, const char* message, size_t messagelen);
+
+ // Define a symbol from the command line.
+ bool
+ define_symbol(const char* definition);
+
+ // Create sections required by any linker scripts.
+ void
+ create_script_sections(Layout*);
+
+ // Add all symbol definitions to the symbol table.
+ void
+ add_symbols_to_table(Symbol_table*);
+
+ // Used to iterate over symbols which are referenced in expressions
+ // but not defined.
+ typedef Unordered_set<std::string>::const_iterator referenced_const_iterator;
+
+ referenced_const_iterator
+ referenced_begin() const
+ { return this->symbol_references_.begin(); }
+
+ referenced_const_iterator
+ referenced_end() const
+ { return this->symbol_references_.end(); }
+
+ // Return whether a symbol is referenced but not defined.
+ bool
+ is_referenced(const std::string& name) const
+ {
+ return (this->symbol_references_.find(name)
+ != this->symbol_references_.end());
+ }
+
+ // Return whether there are any symbols which were referenced but
+ // not defined.
+ bool
+ any_unreferenced() const
+ { return !this->symbol_references_.empty(); }
+
+ // Finalize the symbol values. Also check assertions.
+ void
+ finalize_symbols(Symbol_table*, const Layout*);
+
+ // Version information parsed from a version script. Everything
+ // else has a pointer to this object.
+ Version_script_info*
+ version_script_info()
+ { return &this->version_script_info_; }
+
+ const Version_script_info*
+ version_script_info() const
+ { return &this->version_script_info_; }
+
+ // A SECTIONS clause parsed from a linker script. Everything else
+ // has a pointer to this object.
+ Script_sections*
+ script_sections()
+ { return &this->script_sections_; }
+
+ const Script_sections*
+ script_sections() const
+ { return &this->script_sections_; }
+
+ // Whether we saw a SECTIONS clause.
+ bool
+ saw_sections_clause() const
+ { return this->script_sections_.saw_sections_clause(); }
+
+ // Whether we saw a PHDRS clause.
+ bool
+ saw_phdrs_clause() const
+ { return this->script_sections_.saw_phdrs_clause(); }
+
+ // Set section addresses using a SECTIONS clause. Return the
+ // segment which should hold the file header and segment headers;
+ // this may return NULL, in which case the headers are not in a
+ // loadable segment.
+ Output_segment*
+ set_section_addresses(Symbol_table*, Layout*);
+
+ // Print the script to the FILE. This is for debugging.
+ void
+ print(FILE*) const;
+
+ private:
+ // We keep a list of symbol assignments which occur outside of a
+ // SECTIONS clause.
+ typedef std::vector<Symbol_assignment*> Symbol_assignments;
+
+ // We keep a list of all assertions whcih occur outside of a
+ // SECTIONS clause.
+ typedef std::vector<Script_assertion*> Assertions;
+
+ // The entry address. This will be empty if not set.
+ std::string entry_;
+ // Symbols to set.
+ Symbol_assignments symbol_assignments_;
+ // Symbols defined in an expression, for faster lookup.
+ Unordered_set<std::string> symbol_definitions_;
+ // Symbols referenced in an expression.
+ Unordered_set<std::string> symbol_references_;
+ // Assertions to check.
+ Assertions assertions_;
+ // Version information parsed from a version script.
+ Version_script_info version_script_info_;
+ // Information from any SECTIONS clauses.
+ Script_sections script_sections_;
+};
+
+// FILE was found as an argument on the command line, but was not
+// recognized as an ELF file. Try to read it as a script. Return
+// true if the file was handled. This has to handle /usr/lib/libc.so
+// on a GNU/Linux system. *USED_NEXT_BLOCKER is set to indicate
+// whether the function took over NEXT_BLOCKER.
+
+bool
+read_input_script(Workqueue*, Symbol_table*, Layout*, Dirsearch*, int,
+ Input_objects*, Mapfile*, Input_group*,
+ const Input_argument*, Input_file*,
+ Task_token* next_blocker, bool* used_next_blocker);
+
+// FILE was found as an argument to --script (-T).
+// Read it as a script, and execute its contents immediately.
+
+bool
+read_commandline_script(const char* filename, Command_line* cmdline);
+
+// FILE was found as an argument to --version-script. Read it as a
+// version script, and store its contents in
+// cmdline->script_options()->version_script_info().
+
+bool
+read_version_script(const char* filename, Command_line* cmdline);
+
+// FILENAME was found as an argument to --dynamic-list. Read it as a
+// version script (actually, a versym_node from a version script), and
+// store its contents in DYNAMIC_LIST.
+
+bool
+read_dynamic_list(const char* filename, Command_line* cmdline,
+ Script_options* dynamic_list);
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_SCRIPT_H)
diff --git a/binutils-2.25/gold/sparc.cc b/binutils-2.25/gold/sparc.cc
new file mode 100644
index 00000000..cbe95b86
--- /dev/null
+++ b/binutils-2.25/gold/sparc.cc
@@ -0,0 +1,4395 @@
+// sparc.cc -- sparc target support for gold.
+
+// Copyright 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+// Written by David S. Miller <davem@davemloft.net>.
+
+// 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 <cstdlib>
+#include <cstdio>
+#include <cstring>
+
+#include "elfcpp.h"
+#include "parameters.h"
+#include "reloc.h"
+#include "sparc.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 "errors.h"
+#include "gc.h"
+
+namespace
+{
+
+using namespace gold;
+
+template<int size, bool big_endian>
+class Output_data_plt_sparc;
+
+template<int size, bool big_endian>
+class Target_sparc : public Sized_target<size, big_endian>
+{
+ public:
+ typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian> Reloc_section;
+
+ Target_sparc()
+ : Sized_target<size, big_endian>(&sparc_info),
+ got_(NULL), plt_(NULL), rela_dyn_(NULL), rela_ifunc_(NULL),
+ copy_relocs_(elfcpp::R_SPARC_COPY),
+ got_mod_index_offset_(-1U), tls_get_addr_sym_(NULL),
+ elf_machine_(sparc_info.machine_code), elf_flags_(0),
+ elf_flags_set_(false)
+ {
+ }
+
+ // Process the relocations to determine unreferenced sections for
+ // garbage collection.
+ void
+ gc_process_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols);
+
+ // Scan the relocations to look for symbol adjustments.
+ void
+ scan_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols);
+ // 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<size, 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,
+ typename elfcpp::Elf_types<size>::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<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols,
+ Relocatable_relocs*);
+
+ // Emit relocations for a section.
+ void
+ relocate_relocs(const Relocate_info<size, big_endian>*,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ typename elfcpp::Elf_types<size>::Elf_Off
+ offset_in_output_section,
+ const Relocatable_relocs*,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+ section_size_type view_size,
+ unsigned char* reloc_view,
+ section_size_type reloc_view_size);
+
+ // Return whether SYM is defined by the ABI.
+ bool
+ do_is_defined_by_abi(const Symbol* sym) const
+ {
+ // XXX Really need to support this better...
+ if (sym->type() == elfcpp::STT_SPARC_REGISTER)
+ return 1;
+
+ return strcmp(sym->name(), "___tls_get_addr") == 0;
+ }
+
+ // 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); }
+
+ // 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->got_ == NULL)
+ return 0;
+ return this->got_size() / (size / 8);
+ }
+
+ // Return the address of the GOT.
+ uint64_t
+ got_address() const
+ {
+ if (this->got_ == NULL)
+ return 0;
+ return this->got_->address();
+ }
+
+ // 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:
+ // Make an ELF object.
+ Object*
+ do_make_elf_object(const std::string&, Input_file*, off_t,
+ const elfcpp::Ehdr<size, big_endian>& ehdr);
+
+ void
+ do_adjust_elf_header(unsigned char* view, int len);
+
+ 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_sparc* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+ const elfcpp::Sym<size, big_endian>& lsym,
+ bool is_discarded);
+
+ inline void
+ global(Symbol_table* symtab, Layout* layout, Target_sparc* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+ Symbol* gsym);
+
+ inline bool
+ local_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
+ Target_sparc* ,
+ Sized_relobj_file<size, big_endian>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<size, big_endian>& ,
+ unsigned int ,
+ const elfcpp::Sym<size, big_endian>&)
+ { return false; }
+
+ inline bool
+ global_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
+ Target_sparc* ,
+ Sized_relobj_file<size, big_endian>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<size,
+ big_endian>& ,
+ unsigned int , Symbol*)
+ { return false; }
+
+
+ private:
+ static void
+ unsupported_reloc_local(Sized_relobj_file<size, big_endian>*,
+ unsigned int r_type);
+
+ static void
+ unsupported_reloc_global(Sized_relobj_file<size, big_endian>*,
+ unsigned int r_type, Symbol*);
+
+ static void
+ generate_tls_call(Symbol_table* symtab, Layout* layout,
+ Target_sparc* target);
+
+ void
+ check_non_pic(Relobj*, unsigned int r_type);
+
+ bool
+ reloc_needs_plt_for_ifunc(Sized_relobj_file<size, big_endian>*,
+ 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()
+ : ignore_gd_add_(false), reloc_adjust_addr_(NULL)
+ { }
+
+ ~Relocate()
+ {
+ if (this->ignore_gd_add_)
+ {
+ // FIXME: This needs to specify the location somehow.
+ gold_error(_("missing expected TLS relocation"));
+ }
+ }
+
+ // Do a relocation. Return false if the caller should not issue
+ // any warnings about this relocation.
+ inline bool
+ relocate(const Relocate_info<size, big_endian>*, Target_sparc*,
+ Output_section*, size_t relnum,
+ const elfcpp::Rela<size, big_endian>&,
+ unsigned int r_type, const Sized_symbol<size>*,
+ const Symbol_value<size>*,
+ unsigned char*,
+ typename elfcpp::Elf_types<size>::Elf_Addr,
+ section_size_type);
+
+ private:
+ // Do a TLS relocation.
+ inline void
+ relocate_tls(const Relocate_info<size, big_endian>*, Target_sparc* target,
+ size_t relnum, const elfcpp::Rela<size, big_endian>&,
+ unsigned int r_type, const Sized_symbol<size>*,
+ const Symbol_value<size>*,
+ unsigned char*,
+ typename elfcpp::Elf_types<size>::Elf_Addr,
+ section_size_type);
+
+ inline void
+ relax_call(Target_sparc<size, big_endian>* target,
+ unsigned char* view,
+ const elfcpp::Rela<size, big_endian>& rela,
+ section_size_type view_size);
+
+ // Ignore the next relocation which should be R_SPARC_TLS_GD_ADD
+ bool ignore_gd_add_;
+
+ // If we hit a reloc at this view address, adjust it back by 4 bytes.
+ unsigned char *reloc_adjust_addr_;
+ };
+
+ // 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*);
+ };
+
+ // Get the GOT section, creating it if necessary.
+ Output_data_got<size, big_endian>*
+ got_section(Symbol_table*, Layout*);
+
+ // 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<size, big_endian>* relobj,
+ unsigned int local_sym_index);
+
+ // Create a GOT entry for the TLS module index.
+ unsigned int
+ got_mod_index_entry(Symbol_table* symtab, Layout* layout,
+ Sized_relobj_file<size, big_endian>* object);
+
+ // Return the gsym for "__tls_get_addr". Cache if not already
+ // cached.
+ Symbol*
+ tls_get_addr_sym(Symbol_table* symtab)
+ {
+ if (!this->tls_get_addr_sym_)
+ this->tls_get_addr_sym_ = symtab->lookup("__tls_get_addr", NULL);
+ gold_assert(this->tls_get_addr_sym_);
+ return this->tls_get_addr_sym_;
+ }
+
+ // Get the PLT section.
+ Output_data_plt_sparc<size, big_endian>*
+ plt_section() const
+ {
+ gold_assert(this->plt_ != NULL);
+ return this->plt_;
+ }
+
+ // Get the dynamic reloc section, creating it if necessary.
+ Reloc_section*
+ rela_dyn_section(Layout*);
+
+ // Get the section to use for IFUNC relocations.
+ Reloc_section*
+ rela_ifunc_section(Layout*);
+
+ // Copy a relocation against a global symbol.
+ void
+ copy_reloc(Symbol_table* symtab, Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int shndx, Output_section* output_section,
+ Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
+ {
+ this->copy_relocs_.copy_reloc(symtab, layout,
+ symtab->get_sized_symbol<size>(sym),
+ object, shndx, output_section,
+ reloc, this->rela_dyn_section(layout));
+ }
+
+ // Information about this specific target which we pass to the
+ // general Target structure.
+ static Target::Target_info sparc_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_OFFSET = 1, // GOT entry for TLS offset
+ GOT_TYPE_TLS_PAIR = 2, // GOT entry for TLS module/offset pair
+ };
+
+ // The GOT section.
+ Output_data_got<size, big_endian>* got_;
+ // The PLT section.
+ Output_data_plt_sparc<size, big_endian>* plt_;
+ // The dynamic reloc section.
+ Reloc_section* rela_dyn_;
+ // The section to use for IFUNC relocs.
+ Reloc_section* rela_ifunc_;
+ // Relocs saved to avoid a COPY reloc.
+ Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
+ // Offset of the GOT entry for the TLS module index;
+ unsigned int got_mod_index_offset_;
+ // Cached pointer to __tls_get_addr symbol
+ Symbol* tls_get_addr_sym_;
+ // Accumulated elf machine type
+ elfcpp::Elf_Half elf_machine_;
+ // Accumulated elf header flags
+ elfcpp::Elf_Word elf_flags_;
+ // Whether elf_flags_ has been set for the first time yet
+ bool elf_flags_set_;
+};
+
+template<>
+Target::Target_info Target_sparc<32, true>::sparc_info =
+{
+ 32, // size
+ true, // is_big_endian
+ elfcpp::EM_SPARC, // 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/ld.so.1", // dynamic_linker
+ 0x00010000, // default_text_segment_address
+ 64 * 1024, // abi_pagesize (overridable by -z max-page-size)
+ 8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0, // large_common_section_flags
+ NULL, // attributes_section
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
+};
+
+template<>
+Target::Target_info Target_sparc<64, true>::sparc_info =
+{
+ 64, // size
+ true, // is_big_endian
+ elfcpp::EM_SPARCV9, // 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/sparcv9/ld.so.1", // dynamic_linker
+ 0x100000, // default_text_segment_address
+ 64 * 1024, // abi_pagesize (overridable by -z max-page-size)
+ 8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0, // large_common_section_flags
+ NULL, // attributes_section
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
+};
+
+// We have to take care here, even when operating in little-endian
+// mode, sparc instructions are still big endian.
+template<int size, bool big_endian>
+class Sparc_relocate_functions
+{
+private:
+ // Do a simple relocation with the addend in the relocation.
+ template<int valsize>
+ static inline void
+ rela(unsigned char* view,
+ unsigned int right_shift,
+ typename elfcpp::Elf_types<valsize>::Elf_Addr dst_mask,
+ typename elfcpp::Swap<size, big_endian>::Valtype value,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ Valtype reloc = ((value + addend) >> right_shift);
+
+ val &= ~dst_mask;
+ reloc &= dst_mask;
+
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
+ }
+
+ // Do a simple relocation using a symbol value with the addend in
+ // the relocation.
+ template<int valsize>
+ static inline void
+ rela(unsigned char* view,
+ unsigned int right_shift,
+ typename elfcpp::Elf_types<valsize>::Elf_Addr dst_mask,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<valsize, big_endian>::Valtype addend)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ Valtype reloc = (psymval->value(object, addend) >> right_shift);
+
+ val &= ~dst_mask;
+ reloc &= dst_mask;
+
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
+ }
+
+ // Do a simple relocation using a symbol value with the addend in
+ // the relocation, unaligned.
+ template<int valsize>
+ static inline void
+ rela_ua(unsigned char* view,
+ unsigned int right_shift, elfcpp::Elf_Xword dst_mask,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend)
+ {
+ typedef typename elfcpp::Swap_unaligned<valsize,
+ big_endian>::Valtype Valtype;
+ unsigned char* wv = view;
+ Valtype val = elfcpp::Swap_unaligned<valsize, big_endian>::readval(wv);
+ Valtype reloc = (psymval->value(object, addend) >> right_shift);
+
+ val &= ~dst_mask;
+ reloc &= dst_mask;
+
+ elfcpp::Swap_unaligned<valsize, big_endian>::writeval(wv, val | reloc);
+ }
+
+ // Do a simple PC relative relocation with a Symbol_value with the
+ // addend in the relocation.
+ template<int valsize>
+ static inline void
+ pcrela(unsigned char* view,
+ unsigned int right_shift,
+ typename elfcpp::Elf_types<valsize>::Elf_Addr dst_mask,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ Valtype reloc = ((psymval->value(object, addend) - address)
+ >> right_shift);
+
+ val &= ~dst_mask;
+ reloc &= dst_mask;
+
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
+ }
+
+ template<int valsize>
+ static inline void
+ pcrela_unaligned(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ typedef typename elfcpp::Swap_unaligned<valsize,
+ big_endian>::Valtype Valtype;
+ unsigned char* wv = view;
+ Valtype reloc = (psymval->value(object, addend) - address);
+
+ elfcpp::Swap_unaligned<valsize, big_endian>::writeval(wv, reloc);
+ }
+
+ typedef Sparc_relocate_functions<size, big_endian> This;
+ typedef Sparc_relocate_functions<size, true> This_insn;
+
+public:
+ // R_SPARC_WDISP30: (Symbol + Addend - Address) >> 2
+ static inline void
+ wdisp30(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This_insn::template pcrela<32>(view, 2, 0x3fffffff, object,
+ psymval, addend, address);
+ }
+
+ // R_SPARC_WDISP22: (Symbol + Addend - Address) >> 2
+ static inline void
+ wdisp22(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This_insn::template pcrela<32>(view, 2, 0x003fffff, object,
+ psymval, addend, address);
+ }
+
+ // R_SPARC_WDISP19: (Symbol + Addend - Address) >> 2
+ static inline void
+ wdisp19(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This_insn::template pcrela<32>(view, 2, 0x0007ffff, object,
+ psymval, addend, address);
+ }
+
+ // R_SPARC_WDISP16: (Symbol + Addend - Address) >> 2
+ static inline void
+ wdisp16(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, true>::readval(wv);
+ Valtype reloc = ((psymval->value(object, addend) - address)
+ >> 2);
+
+ // The relocation value is split between the low 14 bits,
+ // and bits 20-21.
+ val &= ~((0x3 << 20) | 0x3fff);
+ reloc = (((reloc & 0xc000) << (20 - 14))
+ | (reloc & 0x3ffff));
+
+ elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+ }
+
+ // R_SPARC_WDISP10: (Symbol + Addend - Address) >> 2
+ static inline void
+ wdisp10(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, true>::readval(wv);
+ Valtype reloc = ((psymval->value(object, addend) - address)
+ >> 2);
+
+ // The relocation value is split between the low bits 5-12,
+ // and high bits 19-20.
+ val &= ~((0x3 << 19) | (0xff << 5));
+ reloc = (((reloc & 0x300) << (19 - 8))
+ | ((reloc & 0xff) << (5 - 0)));
+
+ elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+ }
+
+ // R_SPARC_PC22: (Symbol + Addend - Address) >> 10
+ static inline void
+ pc22(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This_insn::template pcrela<32>(view, 10, 0x003fffff, object,
+ psymval, addend, address);
+ }
+
+ // R_SPARC_PC10: (Symbol + Addend - Address) & 0x3ff
+ static inline void
+ pc10(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This_insn::template pcrela<32>(view, 0, 0x000003ff, object,
+ psymval, addend, address);
+ }
+
+ // R_SPARC_HI22: (Symbol + Addend) >> 10
+ static inline void
+ hi22(unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 10, 0x003fffff, value, addend);
+ }
+
+ // R_SPARC_HI22: (Symbol + Addend) >> 10
+ static inline void
+ hi22(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 10, 0x003fffff, object, psymval, addend);
+ }
+
+ // R_SPARC_PCPLT22: (Symbol + Addend - Address) >> 10
+ static inline void
+ pcplt22(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This_insn::template pcrela<32>(view, 10, 0x003fffff, object,
+ psymval, addend, address);
+ }
+
+ // R_SPARC_LO10: (Symbol + Addend) & 0x3ff
+ static inline void
+ lo10(unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 0, 0x000003ff, value, addend);
+ }
+
+ // R_SPARC_LO10: (Symbol + Addend) & 0x3ff
+ static inline void
+ lo10(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 0, 0x000003ff, object, psymval, addend);
+ }
+
+ // R_SPARC_LO10: (Symbol + Addend) & 0x3ff
+ static inline void
+ lo10(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This_insn::template pcrela<32>(view, 0, 0x000003ff, object,
+ psymval, addend, address);
+ }
+
+ // R_SPARC_OLO10: ((Symbol + Addend) & 0x3ff) + Addend2
+ static inline void
+ olo10(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend2)
+ {
+ typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, true>::readval(wv);
+ Valtype reloc = psymval->value(object, addend);
+
+ val &= ~0x1fff;
+ reloc &= 0x3ff;
+ reloc += addend2;
+ reloc &= 0x1fff;
+
+ elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+ }
+
+ // R_SPARC_22: (Symbol + Addend)
+ static inline void
+ rela32_22(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 0, 0x003fffff, object, psymval, addend);
+ }
+
+ // R_SPARC_13: (Symbol + Addend)
+ static inline void
+ rela32_13(unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 0, 0x00001fff, value, addend);
+ }
+
+ // R_SPARC_13: (Symbol + Addend)
+ static inline void
+ rela32_13(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 0, 0x00001fff, object, psymval, addend);
+ }
+
+ // R_SPARC_UA16: (Symbol + Addend)
+ static inline void
+ ua16(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This::template rela_ua<16>(view, 0, 0xffff, object, psymval, addend);
+ }
+
+ // R_SPARC_UA32: (Symbol + Addend)
+ static inline void
+ ua32(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This::template rela_ua<32>(view, 0, 0xffffffff, object, psymval, addend);
+ }
+
+ // R_SPARC_UA64: (Symbol + Addend)
+ static inline void
+ ua64(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This::template rela_ua<64>(view, 0, ~(elfcpp::Elf_Xword) 0,
+ object, psymval, addend);
+ }
+
+ // R_SPARC_DISP8: (Symbol + Addend - Address)
+ static inline void
+ disp8(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This::template pcrela_unaligned<8>(view, object, psymval,
+ addend, address);
+ }
+
+ // R_SPARC_DISP16: (Symbol + Addend - Address)
+ static inline void
+ disp16(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This::template pcrela_unaligned<16>(view, object, psymval,
+ addend, address);
+ }
+
+ // R_SPARC_DISP32: (Symbol + Addend - Address)
+ static inline void
+ disp32(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This::template pcrela_unaligned<32>(view, object, psymval,
+ addend, address);
+ }
+
+ // R_SPARC_DISP64: (Symbol + Addend - Address)
+ static inline void
+ disp64(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ elfcpp::Elf_Xword addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This::template pcrela_unaligned<64>(view, object, psymval,
+ addend, address);
+ }
+
+ // R_SPARC_H34: (Symbol + Addend) >> 12
+ static inline void
+ h34(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 12, 0x003fffff, object, psymval, addend);
+ }
+
+ // R_SPARC_H44: (Symbol + Addend) >> 22
+ static inline void
+ h44(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 22, 0x003fffff, object, psymval, addend);
+ }
+
+ // R_SPARC_M44: ((Symbol + Addend) >> 12) & 0x3ff
+ static inline void
+ m44(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 12, 0x000003ff, object, psymval, addend);
+ }
+
+ // R_SPARC_L44: (Symbol + Addend) & 0xfff
+ static inline void
+ l44(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 0, 0x00000fff, object, psymval, addend);
+ }
+
+ // R_SPARC_HH22: (Symbol + Addend) >> 42
+ static inline void
+ hh22(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 42, 0x003fffff, object, psymval, addend);
+ }
+
+ // R_SPARC_PC_HH22: (Symbol + Addend - Address) >> 42
+ static inline void
+ pc_hh22(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This_insn::template pcrela<32>(view, 42, 0x003fffff, object,
+ psymval, addend, address);
+ }
+
+ // R_SPARC_HM10: ((Symbol + Addend) >> 32) & 0x3ff
+ static inline void
+ hm10(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 32, 0x000003ff, object, psymval, addend);
+ }
+
+ // R_SPARC_PC_HM10: ((Symbol + Addend - Address) >> 32) & 0x3ff
+ static inline void
+ pc_hm10(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This_insn::template pcrela<32>(view, 32, 0x000003ff, object,
+ psymval, addend, address);
+ }
+
+ // R_SPARC_11: (Symbol + Addend)
+ static inline void
+ rela32_11(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 0, 0x000007ff, object, psymval, addend);
+ }
+
+ // R_SPARC_10: (Symbol + Addend)
+ static inline void
+ rela32_10(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 0, 0x000003ff, object, psymval, addend);
+ }
+
+ // R_SPARC_7: (Symbol + Addend)
+ static inline void
+ rela32_7(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 0, 0x0000007f, object, psymval, addend);
+ }
+
+ // R_SPARC_6: (Symbol + Addend)
+ static inline void
+ rela32_6(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 0, 0x0000003f, object, psymval, addend);
+ }
+
+ // R_SPARC_5: (Symbol + Addend)
+ static inline void
+ rela32_5(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::template rela<32>(view, 0, 0x0000001f, object, psymval, addend);
+ }
+
+ // R_SPARC_TLS_LDO_HIX22: @dtpoff(Symbol + Addend) >> 10
+ static inline void
+ ldo_hix22(unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This_insn::hi22(view, value, addend);
+ }
+
+ // R_SPARC_TLS_LDO_LOX10: @dtpoff(Symbol + Addend) & 0x3ff
+ static inline void
+ ldo_lox10(unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, true>::readval(wv);
+ Valtype reloc = (value + addend);
+
+ val &= ~0x1fff;
+ reloc &= 0x3ff;
+
+ elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+ }
+
+ // R_SPARC_TLS_LE_HIX22: (@tpoff(Symbol + Addend) ^ 0xffffffffffffffff) >> 10
+ static inline void
+ hix22(unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, true>::readval(wv);
+ Valtype reloc = (value + addend);
+
+ val &= ~0x3fffff;
+
+ reloc ^= ~(Valtype)0;
+ reloc >>= 10;
+
+ reloc &= 0x3fffff;
+
+ elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+ }
+
+ // R_SPARC_GOTDATA_OP_HIX22: @gdopoff(Symbol + Addend) >> 10
+ static inline void
+ gdop_hix22(unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, true>::readval(wv);
+ int32_t reloc = static_cast<int32_t>(value + addend);
+
+ val &= ~0x3fffff;
+
+ if (reloc < 0)
+ reloc ^= ~static_cast<int32_t>(0);
+ reloc >>= 10;
+
+ reloc &= 0x3fffff;
+
+ elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+ }
+
+ // R_SPARC_HIX22: ((Symbol + Addend) ^ 0xffffffffffffffff) >> 10
+ static inline void
+ hix22(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, true>::readval(wv);
+ Valtype reloc = psymval->value(object, addend);
+
+ val &= ~0x3fffff;
+
+ reloc ^= ~(Valtype)0;
+ reloc >>= 10;
+
+ reloc &= 0x3fffff;
+
+ elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+ }
+
+
+ // R_SPARC_TLS_LE_LOX10: (@tpoff(Symbol + Addend) & 0x3ff) | 0x1c00
+ static inline void
+ lox10(unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, true>::readval(wv);
+ Valtype reloc = (value + addend);
+
+ val &= ~0x1fff;
+ reloc &= 0x3ff;
+ reloc |= 0x1c00;
+
+ elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+ }
+
+ // R_SPARC_GOTDATA_OP_LOX10: (@gdopoff(Symbol + Addend) & 0x3ff) | 0x1c00
+ static inline void
+ gdop_lox10(unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, true>::readval(wv);
+ int32_t reloc = static_cast<int32_t>(value + addend);
+
+ if (reloc < 0)
+ reloc = (reloc & 0x3ff) | 0x1c00;
+ else
+ reloc = (reloc & 0x3ff);
+
+ val &= ~0x1fff;
+ elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+ }
+
+ // R_SPARC_LOX10: ((Symbol + Addend) & 0x3ff) | 0x1c00
+ static inline void
+ lox10(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, true>::readval(wv);
+ Valtype reloc = psymval->value(object, addend);
+
+ val &= ~0x1fff;
+ reloc &= 0x3ff;
+ reloc |= 0x1c00;
+
+ elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+ }
+};
+
+// Get the GOT section, creating it if necessary.
+
+template<int size, bool big_endian>
+Output_data_got<size, big_endian>*
+Target_sparc<size, big_endian>::got_section(Symbol_table* symtab,
+ Layout* layout)
+{
+ if (this->got_ == NULL)
+ {
+ gold_assert(symtab != NULL && layout != NULL);
+
+ this->got_ = new Output_data_got<size, big_endian>();
+
+ layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_, ORDER_RELRO, true);
+
+ // Define _GLOBAL_OFFSET_TABLE_ at the start of the .got section.
+ symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
+ Symbol_table::PREDEFINED,
+ this->got_,
+ 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<int size, bool big_endian>
+typename Target_sparc<size, big_endian>::Reloc_section*
+Target_sparc<size, big_endian>::rela_dyn_section(Layout* layout)
+{
+ if (this->rela_dyn_ == NULL)
+ {
+ gold_assert(layout != NULL);
+ this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
+ layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
+ elfcpp::SHF_ALLOC, this->rela_dyn_,
+ ORDER_DYNAMIC_RELOCS, false);
+ }
+ return this->rela_dyn_;
+}
+
+// Get the section to use for IFUNC relocs, creating it if
+// necessary. These go in .rela.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.
+
+template<int size, bool big_endian>
+typename Target_sparc<size, big_endian>::Reloc_section*
+Target_sparc<size, big_endian>::rela_ifunc_section(Layout* layout)
+{
+ if (this->rela_ifunc_ == NULL)
+ {
+ // Make sure we have already created the dynamic reloc section.
+ this->rela_dyn_section(layout);
+ this->rela_ifunc_ = new Reloc_section(false);
+ layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
+ elfcpp::SHF_ALLOC, this->rela_ifunc_,
+ ORDER_DYNAMIC_RELOCS, false);
+ gold_assert(this->rela_dyn_->output_section()
+ == this->rela_ifunc_->output_section());
+ }
+ return this->rela_ifunc_;
+}
+
+// A class to handle the PLT data.
+
+template<int size, bool big_endian>
+class Output_data_plt_sparc : public Output_section_data
+{
+ public:
+ typedef Output_data_reloc<elfcpp::SHT_RELA, true,
+ size, big_endian> Reloc_section;
+
+ Output_data_plt_sparc(Layout*);
+
+ // Add an entry to the PLT.
+ void add_entry(Symbol_table* symtab, Layout* 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<size, big_endian>* relobj,
+ unsigned int local_sym_index);
+
+ // Return the .rela.plt section data.
+ const Reloc_section* rel_plt() const
+ {
+ return this->rel_;
+ }
+
+ // Return where the IFUNC relocations should go.
+ Reloc_section*
+ rela_ifunc(Symbol_table*, Layout*);
+
+ void
+ emit_pending_ifunc_relocs();
+
+ // Return whether we created a section for IFUNC relocations.
+ bool
+ has_ifunc_section() const
+ { return this->ifunc_rel_ != NULL; }
+
+ // Return the number of PLT entries.
+ unsigned int
+ entry_count() const
+ { return this->count_ + this->ifunc_count_; }
+
+ // Return the offset of the first non-reserved PLT entry.
+ static unsigned int
+ first_plt_entry_offset()
+ { return 4 * base_plt_entry_size; }
+
+ // Return the size of a PLT entry.
+ static unsigned int
+ get_plt_entry_size()
+ { return base_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);
+
+ protected:
+ 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:
+ // The size of an entry in the PLT.
+ static const int base_plt_entry_size = (size == 32 ? 12 : 32);
+
+ static const unsigned int plt_entries_per_block = 160;
+ static const unsigned int plt_insn_chunk_size = 24;
+ static const unsigned int plt_pointer_chunk_size = 8;
+ static const unsigned int plt_block_size =
+ (plt_entries_per_block
+ * (plt_insn_chunk_size + plt_pointer_chunk_size));
+
+ section_offset_type
+ plt_index_to_offset(unsigned int index)
+ {
+ section_offset_type offset;
+
+ if (size == 32 || index < 32768)
+ offset = index * base_plt_entry_size;
+ else
+ {
+ unsigned int ext_index = index - 32768;
+
+ offset = (32768 * base_plt_entry_size)
+ + ((ext_index / plt_entries_per_block)
+ * plt_block_size)
+ + ((ext_index % plt_entries_per_block)
+ * plt_insn_chunk_size);
+ }
+ return offset;
+ }
+
+ // Set the final size.
+ void
+ set_final_data_size()
+ {
+ unsigned int full_count = this->entry_count() + 4;
+ unsigned int extra = (size == 32 ? 4 : 0);
+ section_offset_type sz = plt_index_to_offset(full_count) + extra;
+
+ return this->set_data_size(sz);
+ }
+
+ // Write out the PLT data.
+ void
+ do_write(Output_file*);
+
+ struct Global_ifunc
+ {
+ Reloc_section* rel;
+ Symbol* gsym;
+ unsigned int plt_index;
+ };
+
+ struct Local_ifunc
+ {
+ Reloc_section* rel;
+ Sized_relobj_file<size, big_endian>* object;
+ unsigned int local_sym_index;
+ unsigned int plt_index;
+ };
+
+ // The reloc section.
+ Reloc_section* rel_;
+ // The IFUNC relocations, if necessary. These must follow the
+ // regular relocations.
+ Reloc_section* ifunc_rel_;
+ // The number of PLT entries.
+ unsigned int count_;
+ // The number of PLT entries for IFUNC symbols.
+ unsigned int ifunc_count_;
+ // Global STT_GNU_IFUNC symbols.
+ std::vector<Global_ifunc> global_ifuncs_;
+ // Local STT_GNU_IFUNC symbols.
+ std::vector<Local_ifunc> local_ifuncs_;
+};
+
+// Define the constants as required by C++ standard.
+
+template<int size, bool big_endian>
+const int Output_data_plt_sparc<size, big_endian>::base_plt_entry_size;
+
+template<int size, bool big_endian>
+const unsigned int
+Output_data_plt_sparc<size, big_endian>::plt_entries_per_block;
+
+template<int size, bool big_endian>
+const unsigned int Output_data_plt_sparc<size, big_endian>::plt_insn_chunk_size;
+
+template<int size, bool big_endian>
+const unsigned int
+Output_data_plt_sparc<size, big_endian>::plt_pointer_chunk_size;
+
+template<int size, bool big_endian>
+const unsigned int Output_data_plt_sparc<size, big_endian>::plt_block_size;
+
+// Create the PLT section. The ordinary .got section is an argument,
+// since we need to refer to the start.
+
+template<int size, bool big_endian>
+Output_data_plt_sparc<size, big_endian>::Output_data_plt_sparc(Layout* layout)
+ : Output_section_data(size == 32 ? 4 : 8), ifunc_rel_(NULL),
+ count_(0), ifunc_count_(0), global_ifuncs_(), local_ifuncs_()
+{
+ this->rel_ = new Reloc_section(false);
+ layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
+ elfcpp::SHF_ALLOC, this->rel_,
+ ORDER_DYNAMIC_PLT_RELOCS, false);
+}
+
+template<int size, bool big_endian>
+void
+Output_data_plt_sparc<size, big_endian>::do_adjust_output_section(Output_section* os)
+{
+ os->set_entsize(0);
+}
+
+// Add an entry to the PLT.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_sparc<size, big_endian>::add_entry(Symbol_table* symtab,
+ Layout* layout,
+ Symbol* gsym)
+{
+ gold_assert(!gsym->has_plt_offset());
+
+ section_offset_type plt_offset;
+ unsigned int index;
+
+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
+ && gsym->can_use_relative_reloc(false))
+ {
+ index = this->ifunc_count_;
+ plt_offset = plt_index_to_offset(index);
+ gsym->set_plt_offset(plt_offset);
+ ++this->ifunc_count_;
+ Reloc_section* rel = this->rela_ifunc(symtab, layout);
+
+ struct Global_ifunc gi;
+ gi.rel = rel;
+ gi.gsym = gsym;
+ gi.plt_index = index;
+ this->global_ifuncs_.push_back(gi);
+ }
+ else
+ {
+ plt_offset = plt_index_to_offset(this->count_ + 4);
+ gsym->set_plt_offset(plt_offset);
+ ++this->count_;
+ gsym->set_needs_dynsym_entry();
+ this->rel_->add_global(gsym, elfcpp::R_SPARC_JMP_SLOT, this,
+ plt_offset, 0);
+ }
+
+ // 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<int size, bool big_endian>
+unsigned int
+Output_data_plt_sparc<size, big_endian>::add_local_ifunc_entry(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* relobj,
+ unsigned int local_sym_index)
+{
+ unsigned int index = this->ifunc_count_;
+ section_offset_type plt_offset;
+
+ plt_offset = plt_index_to_offset(index);
+ ++this->ifunc_count_;
+
+ Reloc_section* rel = this->rela_ifunc(symtab, layout);
+
+ struct Local_ifunc li;
+ li.rel = rel;
+ li.object = relobj;
+ li.local_sym_index = local_sym_index;
+ li.plt_index = index;
+ this->local_ifuncs_.push_back(li);
+
+ return plt_offset;
+}
+
+// Emit any pending IFUNC plt relocations.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_sparc<size, big_endian>::emit_pending_ifunc_relocs()
+{
+ // Emit any pending IFUNC relocs.
+ for (typename std::vector<Global_ifunc>::const_iterator p =
+ this->global_ifuncs_.begin();
+ p != this->global_ifuncs_.end();
+ ++p)
+ {
+ section_offset_type plt_offset;
+ unsigned int index;
+
+ index = this->count_ + p->plt_index + 4;
+ plt_offset = this->plt_index_to_offset(index);
+ p->rel->add_symbolless_global_addend(p->gsym, elfcpp::R_SPARC_JMP_IREL,
+ this, plt_offset, 0);
+ }
+
+ for (typename std::vector<Local_ifunc>::const_iterator p =
+ this->local_ifuncs_.begin();
+ p != this->local_ifuncs_.end();
+ ++p)
+ {
+ section_offset_type plt_offset;
+ unsigned int index;
+
+ index = this->count_ + p->plt_index + 4;
+ plt_offset = this->plt_index_to_offset(index);
+ p->rel->add_symbolless_local_addend(p->object, p->local_sym_index,
+ elfcpp::R_SPARC_JMP_IREL,
+ this, plt_offset, 0);
+ }
+}
+
+// Return where the IFUNC relocations should go in the PLT. These
+// follow the non-IFUNC relocations.
+
+template<int size, bool big_endian>
+typename Output_data_plt_sparc<size, big_endian>::Reloc_section*
+Output_data_plt_sparc<size, big_endian>::rela_ifunc(
+ Symbol_table* symtab,
+ Layout* layout)
+{
+ if (this->ifunc_rel_ == NULL)
+ {
+ this->ifunc_rel_ = new Reloc_section(false);
+ layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
+ elfcpp::SHF_ALLOC, this->ifunc_rel_,
+ ORDER_DYNAMIC_PLT_RELOCS, false);
+ gold_assert(this->ifunc_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_SPARC_IRELATIVE and R_SPARC_JMP_IREL
+ // relocs for STT_GNU_IFUNC symbols. The library will use
+ // these symbols to locate the IRELATIVE and JMP_IREL relocs
+ // at program startup time.
+ symtab->define_in_output_data("__rela_iplt_start", NULL,
+ Symbol_table::PREDEFINED,
+ this->ifunc_rel_, 0, 0,
+ elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
+ elfcpp::STV_HIDDEN, 0, false, true);
+ symtab->define_in_output_data("__rela_iplt_end", NULL,
+ Symbol_table::PREDEFINED,
+ this->ifunc_rel_, 0, 0,
+ elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
+ elfcpp::STV_HIDDEN, 0, true, true);
+ }
+ }
+ return this->ifunc_rel_;
+}
+
+// Return the PLT address to use for a global symbol.
+
+template<int size, bool big_endian>
+uint64_t
+Output_data_plt_sparc<size, big_endian>::address_for_global(const Symbol* gsym)
+{
+ uint64_t offset = 0;
+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
+ && gsym->can_use_relative_reloc(false))
+ offset = plt_index_to_offset(this->count_ + 4);
+ return this->address() + offset + gsym->plt_offset();
+}
+
+// Return the PLT address to use for a local symbol. These are always
+// IRELATIVE relocs.
+
+template<int size, bool big_endian>
+uint64_t
+Output_data_plt_sparc<size, big_endian>::address_for_local(
+ const Relobj* object,
+ unsigned int r_sym)
+{
+ return (this->address()
+ + plt_index_to_offset(this->count_ + 4)
+ + object->local_plt_offset(r_sym));
+}
+
+static const unsigned int sparc_nop = 0x01000000;
+static const unsigned int sparc_sethi_g1 = 0x03000000;
+static const unsigned int sparc_branch_always = 0x30800000;
+static const unsigned int sparc_branch_always_pt = 0x30680000;
+static const unsigned int sparc_mov = 0x80100000;
+static const unsigned int sparc_mov_g0_o0 = 0x90100000;
+static const unsigned int sparc_mov_o7_g5 = 0x8a10000f;
+static const unsigned int sparc_call_plus_8 = 0x40000002;
+static const unsigned int sparc_ldx_o7_imm_g1 = 0xc25be000;
+static const unsigned int sparc_jmpl_o7_g1_g1 = 0x83c3c001;
+static const unsigned int sparc_mov_g5_o7 = 0x9e100005;
+
+// Write out the PLT.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_sparc<size, big_endian>::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);
+ unsigned char* pov = oview;
+
+ memset(pov, 0, base_plt_entry_size * 4);
+ pov += this->first_plt_entry_offset();
+
+ unsigned int plt_offset = base_plt_entry_size * 4;
+ const unsigned int count = this->entry_count();
+
+ if (size == 64)
+ {
+ unsigned int limit;
+
+ limit = (count > 32768 ? 32768 : count);
+
+ for (unsigned int i = 0; i < limit; ++i)
+ {
+ elfcpp::Swap<32, true>::writeval(pov + 0x00,
+ sparc_sethi_g1 + plt_offset);
+ elfcpp::Swap<32, true>::writeval(pov + 0x04,
+ sparc_branch_always_pt +
+ (((base_plt_entry_size -
+ (plt_offset + 4)) >> 2) &
+ 0x7ffff));
+ elfcpp::Swap<32, true>::writeval(pov + 0x08, sparc_nop);
+ elfcpp::Swap<32, true>::writeval(pov + 0x0c, sparc_nop);
+ elfcpp::Swap<32, true>::writeval(pov + 0x10, sparc_nop);
+ elfcpp::Swap<32, true>::writeval(pov + 0x14, sparc_nop);
+ elfcpp::Swap<32, true>::writeval(pov + 0x18, sparc_nop);
+ elfcpp::Swap<32, true>::writeval(pov + 0x1c, sparc_nop);
+
+ pov += base_plt_entry_size;
+ plt_offset += base_plt_entry_size;
+ }
+
+ if (count > 32768)
+ {
+ unsigned int ext_cnt = count - 32768;
+ unsigned int blks = ext_cnt / plt_entries_per_block;
+
+ for (unsigned int i = 0; i < blks; ++i)
+ {
+ unsigned int data_off = (plt_entries_per_block
+ * plt_insn_chunk_size) - 4;
+
+ for (unsigned int j = 0; j < plt_entries_per_block; ++j)
+ {
+ elfcpp::Swap<32, true>::writeval(pov + 0x00,
+ sparc_mov_o7_g5);
+ elfcpp::Swap<32, true>::writeval(pov + 0x04,
+ sparc_call_plus_8);
+ elfcpp::Swap<32, true>::writeval(pov + 0x08,
+ sparc_nop);
+ elfcpp::Swap<32, true>::writeval(pov + 0x0c,
+ sparc_ldx_o7_imm_g1 +
+ (data_off & 0x1fff));
+ elfcpp::Swap<32, true>::writeval(pov + 0x10,
+ sparc_jmpl_o7_g1_g1);
+ elfcpp::Swap<32, true>::writeval(pov + 0x14,
+ sparc_mov_g5_o7);
+
+ elfcpp::Swap<64, big_endian>::writeval(
+ pov + 0x4 + data_off,
+ (elfcpp::Elf_Xword) (oview - (pov + 0x04)));
+
+ pov += plt_insn_chunk_size;
+ data_off -= 16;
+ }
+ }
+
+ unsigned int sub_blk_cnt = ext_cnt % plt_entries_per_block;
+ for (unsigned int i = 0; i < sub_blk_cnt; ++i)
+ {
+ unsigned int data_off = (sub_blk_cnt
+ * plt_insn_chunk_size) - 4;
+
+ for (unsigned int j = 0; j < plt_entries_per_block; ++j)
+ {
+ elfcpp::Swap<32, true>::writeval(pov + 0x00,
+ sparc_mov_o7_g5);
+ elfcpp::Swap<32, true>::writeval(pov + 0x04,
+ sparc_call_plus_8);
+ elfcpp::Swap<32, true>::writeval(pov + 0x08,
+ sparc_nop);
+ elfcpp::Swap<32, true>::writeval(pov + 0x0c,
+ sparc_ldx_o7_imm_g1 +
+ (data_off & 0x1fff));
+ elfcpp::Swap<32, true>::writeval(pov + 0x10,
+ sparc_jmpl_o7_g1_g1);
+ elfcpp::Swap<32, true>::writeval(pov + 0x14,
+ sparc_mov_g5_o7);
+
+ elfcpp::Swap<64, big_endian>::writeval(
+ pov + 0x4 + data_off,
+ (elfcpp::Elf_Xword) (oview - (pov + 0x04)));
+
+ pov += plt_insn_chunk_size;
+ data_off -= 16;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ elfcpp::Swap<32, true>::writeval(pov + 0x00,
+ sparc_sethi_g1 + plt_offset);
+ elfcpp::Swap<32, true>::writeval(pov + 0x04,
+ sparc_branch_always +
+ (((- (plt_offset + 4)) >> 2) &
+ 0x003fffff));
+ elfcpp::Swap<32, true>::writeval(pov + 0x08, sparc_nop);
+
+ pov += base_plt_entry_size;
+ plt_offset += base_plt_entry_size;
+ }
+
+ elfcpp::Swap<32, true>::writeval(pov, sparc_nop);
+ pov += 4;
+ }
+
+ gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
+
+ of->write_output_view(offset, oview_size, oview);
+}
+
+// Create the PLT section.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::make_plt_section(Symbol_table* symtab,
+ Layout* layout)
+{
+ // Create the GOT sections first.
+ this->got_section(symtab, layout);
+
+ // Ensure that .rela.dyn always appears before .rela.plt This is
+ // necessary due to how, on Sparc and some other targets, .rela.dyn
+ // needs to include .rela.plt in it's range.
+ this->rela_dyn_section(layout);
+
+ this->plt_ = new Output_data_plt_sparc<size, big_endian>(layout);
+ layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_EXECINSTR
+ | elfcpp::SHF_WRITE),
+ this->plt_, ORDER_NON_RELRO_FIRST, false);
+
+ // Define _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section.
+ symtab->define_in_output_data("_PROCEDURE_LINKAGE_TABLE_", NULL,
+ Symbol_table::PREDEFINED,
+ this->plt_,
+ 0, 0, elfcpp::STT_OBJECT,
+ elfcpp::STB_LOCAL,
+ elfcpp::STV_HIDDEN, 0,
+ false, false);
+}
+
+// Create a PLT entry for a global symbol.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::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.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::make_local_ifunc_plt_entry(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* 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.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::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<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::first_plt_entry_offset() const
+{
+ return Output_data_plt_sparc<size, big_endian>::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::plt_entry_size() const
+{
+ return Output_data_plt_sparc<size, big_endian>::get_plt_entry_size();
+}
+
+// Create a GOT entry for the TLS module index.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::got_mod_index_entry(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object)
+{
+ if (this->got_mod_index_offset_ == -1U)
+ {
+ gold_assert(symtab != NULL && layout != NULL && object != NULL);
+ Reloc_section* rela_dyn = this->rela_dyn_section(layout);
+ Output_data_got<size, big_endian>* got;
+ unsigned int got_offset;
+
+ got = this->got_section(symtab, layout);
+ got_offset = got->add_constant(0);
+ rela_dyn->add_local(object, 0,
+ (size == 64 ?
+ elfcpp::R_SPARC_TLS_DTPMOD64 :
+ elfcpp::R_SPARC_TLS_DTPMOD32), got,
+ got_offset, 0);
+ 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.
+
+static tls::Tls_optimization
+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_SPARC_TLS_GD_HI22: // Global-dynamic
+ case elfcpp::R_SPARC_TLS_GD_LO10:
+ case elfcpp::R_SPARC_TLS_GD_ADD:
+ case elfcpp::R_SPARC_TLS_GD_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_SPARC_TLS_LDM_HI22: // Local-dynamic
+ case elfcpp::R_SPARC_TLS_LDM_LO10:
+ case elfcpp::R_SPARC_TLS_LDM_ADD:
+ case elfcpp::R_SPARC_TLS_LDM_CALL:
+ // 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_SPARC_TLS_LDO_HIX22: // Alternate local-dynamic
+ case elfcpp::R_SPARC_TLS_LDO_LOX10:
+ case elfcpp::R_SPARC_TLS_LDO_ADD:
+ // Another type of Local-Dynamic relocation.
+ return tls::TLSOPT_TO_LE;
+
+ case elfcpp::R_SPARC_TLS_IE_HI22: // Initial-exec
+ case elfcpp::R_SPARC_TLS_IE_LO10:
+ case elfcpp::R_SPARC_TLS_IE_LD:
+ case elfcpp::R_SPARC_TLS_IE_LDX:
+ case elfcpp::R_SPARC_TLS_IE_ADD:
+ // 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_SPARC_TLS_LE_HIX22: // Local-exec
+ case elfcpp::R_SPARC_TLS_LE_LOX10:
+ // 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.
+
+template<int size, bool big_endian>
+int
+Target_sparc<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
+{
+ r_type &= 0xff;
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_NONE:
+ case elfcpp::R_SPARC_REGISTER:
+ case elfcpp::R_SPARC_GNU_VTINHERIT:
+ case elfcpp::R_SPARC_GNU_VTENTRY:
+ // No symbol reference.
+ return 0;
+
+ case elfcpp::R_SPARC_UA64:
+ case elfcpp::R_SPARC_64:
+ case elfcpp::R_SPARC_HIX22:
+ case elfcpp::R_SPARC_LOX10:
+ case elfcpp::R_SPARC_H34:
+ case elfcpp::R_SPARC_H44:
+ case elfcpp::R_SPARC_M44:
+ case elfcpp::R_SPARC_L44:
+ case elfcpp::R_SPARC_HH22:
+ case elfcpp::R_SPARC_HM10:
+ case elfcpp::R_SPARC_LM22:
+ case elfcpp::R_SPARC_HI22:
+ case elfcpp::R_SPARC_LO10:
+ case elfcpp::R_SPARC_OLO10:
+ case elfcpp::R_SPARC_UA32:
+ case elfcpp::R_SPARC_32:
+ case elfcpp::R_SPARC_UA16:
+ case elfcpp::R_SPARC_16:
+ case elfcpp::R_SPARC_11:
+ case elfcpp::R_SPARC_10:
+ case elfcpp::R_SPARC_8:
+ case elfcpp::R_SPARC_7:
+ case elfcpp::R_SPARC_6:
+ case elfcpp::R_SPARC_5:
+ return Symbol::ABSOLUTE_REF;
+
+ case elfcpp::R_SPARC_DISP8:
+ case elfcpp::R_SPARC_DISP16:
+ case elfcpp::R_SPARC_DISP32:
+ case elfcpp::R_SPARC_DISP64:
+ case elfcpp::R_SPARC_PC_HH22:
+ case elfcpp::R_SPARC_PC_HM10:
+ case elfcpp::R_SPARC_PC_LM22:
+ case elfcpp::R_SPARC_PC10:
+ case elfcpp::R_SPARC_PC22:
+ case elfcpp::R_SPARC_WDISP30:
+ case elfcpp::R_SPARC_WDISP22:
+ case elfcpp::R_SPARC_WDISP19:
+ case elfcpp::R_SPARC_WDISP16:
+ case elfcpp::R_SPARC_WDISP10:
+ return Symbol::RELATIVE_REF;
+
+ case elfcpp::R_SPARC_PLT64:
+ case elfcpp::R_SPARC_PLT32:
+ case elfcpp::R_SPARC_HIPLT22:
+ case elfcpp::R_SPARC_LOPLT10:
+ case elfcpp::R_SPARC_PCPLT10:
+ return Symbol::FUNCTION_CALL | Symbol::ABSOLUTE_REF;
+
+ case elfcpp::R_SPARC_PCPLT32:
+ case elfcpp::R_SPARC_PCPLT22:
+ case elfcpp::R_SPARC_WPLT30:
+ return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+
+ case elfcpp::R_SPARC_GOTDATA_OP:
+ case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+ case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+ case elfcpp::R_SPARC_GOT10:
+ case elfcpp::R_SPARC_GOT13:
+ case elfcpp::R_SPARC_GOT22:
+ // Absolute in GOT.
+ return Symbol::ABSOLUTE_REF;
+
+ case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
+ case elfcpp::R_SPARC_TLS_GD_LO10:
+ case elfcpp::R_SPARC_TLS_GD_ADD:
+ case elfcpp::R_SPARC_TLS_GD_CALL:
+ case elfcpp::R_SPARC_TLS_LDM_HI22: // Local-dynamic
+ case elfcpp::R_SPARC_TLS_LDM_LO10:
+ case elfcpp::R_SPARC_TLS_LDM_ADD:
+ case elfcpp::R_SPARC_TLS_LDM_CALL:
+ case elfcpp::R_SPARC_TLS_LDO_HIX22: // Alternate local-dynamic
+ case elfcpp::R_SPARC_TLS_LDO_LOX10:
+ case elfcpp::R_SPARC_TLS_LDO_ADD:
+ case elfcpp::R_SPARC_TLS_LE_HIX22:
+ case elfcpp::R_SPARC_TLS_LE_LOX10:
+ case elfcpp::R_SPARC_TLS_IE_HI22: // Initial-exec
+ case elfcpp::R_SPARC_TLS_IE_LO10:
+ case elfcpp::R_SPARC_TLS_IE_LD:
+ case elfcpp::R_SPARC_TLS_IE_LDX:
+ case elfcpp::R_SPARC_TLS_IE_ADD:
+ return Symbol::TLS_REF;
+
+ case elfcpp::R_SPARC_COPY:
+ case elfcpp::R_SPARC_GLOB_DAT:
+ case elfcpp::R_SPARC_JMP_SLOT:
+ case elfcpp::R_SPARC_JMP_IREL:
+ case elfcpp::R_SPARC_RELATIVE:
+ case elfcpp::R_SPARC_IRELATIVE:
+ case elfcpp::R_SPARC_TLS_DTPMOD64:
+ case elfcpp::R_SPARC_TLS_DTPMOD32:
+ case elfcpp::R_SPARC_TLS_DTPOFF64:
+ case elfcpp::R_SPARC_TLS_DTPOFF32:
+ case elfcpp::R_SPARC_TLS_TPOFF64:
+ case elfcpp::R_SPARC_TLS_TPOFF32:
+ default:
+ // Not expected. We will give an error later.
+ return 0;
+ }
+}
+
+// Generate a PLT entry slot for a call to __tls_get_addr
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::Scan::generate_tls_call(Symbol_table* symtab,
+ Layout* layout,
+ Target_sparc<size, big_endian>* target)
+{
+ Symbol* gsym = target->tls_get_addr_sym(symtab);
+
+ target->make_plt_entry(symtab, layout, gsym);
+}
+
+// Report an unsupported relocation against a local symbol.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::Scan::unsupported_reloc_local(
+ Sized_relobj_file<size, 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.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::Scan::check_non_pic(Relobj* object, unsigned int r_type)
+{
+ gold_assert(r_type != elfcpp::R_SPARC_NONE);
+
+ if (size == 64)
+ {
+ switch (r_type)
+ {
+ // These are the relocation types supported by glibc for sparc 64-bit.
+ case elfcpp::R_SPARC_RELATIVE:
+ case elfcpp::R_SPARC_IRELATIVE:
+ case elfcpp::R_SPARC_COPY:
+ case elfcpp::R_SPARC_64:
+ case elfcpp::R_SPARC_GLOB_DAT:
+ case elfcpp::R_SPARC_JMP_SLOT:
+ case elfcpp::R_SPARC_JMP_IREL:
+ case elfcpp::R_SPARC_TLS_DTPMOD64:
+ case elfcpp::R_SPARC_TLS_DTPOFF64:
+ case elfcpp::R_SPARC_TLS_TPOFF64:
+ case elfcpp::R_SPARC_TLS_LE_HIX22:
+ case elfcpp::R_SPARC_TLS_LE_LOX10:
+ case elfcpp::R_SPARC_8:
+ case elfcpp::R_SPARC_16:
+ case elfcpp::R_SPARC_DISP8:
+ case elfcpp::R_SPARC_DISP16:
+ case elfcpp::R_SPARC_DISP32:
+ case elfcpp::R_SPARC_WDISP30:
+ case elfcpp::R_SPARC_LO10:
+ case elfcpp::R_SPARC_HI22:
+ case elfcpp::R_SPARC_OLO10:
+ case elfcpp::R_SPARC_H34:
+ case elfcpp::R_SPARC_H44:
+ case elfcpp::R_SPARC_M44:
+ case elfcpp::R_SPARC_L44:
+ case elfcpp::R_SPARC_HH22:
+ case elfcpp::R_SPARC_HM10:
+ case elfcpp::R_SPARC_LM22:
+ case elfcpp::R_SPARC_UA16:
+ case elfcpp::R_SPARC_UA32:
+ case elfcpp::R_SPARC_UA64:
+ return;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (r_type)
+ {
+ // These are the relocation types supported by glibc for sparc 32-bit.
+ case elfcpp::R_SPARC_RELATIVE:
+ case elfcpp::R_SPARC_IRELATIVE:
+ case elfcpp::R_SPARC_COPY:
+ case elfcpp::R_SPARC_GLOB_DAT:
+ case elfcpp::R_SPARC_32:
+ case elfcpp::R_SPARC_JMP_SLOT:
+ case elfcpp::R_SPARC_JMP_IREL:
+ case elfcpp::R_SPARC_TLS_DTPMOD32:
+ case elfcpp::R_SPARC_TLS_DTPOFF32:
+ case elfcpp::R_SPARC_TLS_TPOFF32:
+ case elfcpp::R_SPARC_TLS_LE_HIX22:
+ case elfcpp::R_SPARC_TLS_LE_LOX10:
+ case elfcpp::R_SPARC_8:
+ case elfcpp::R_SPARC_16:
+ case elfcpp::R_SPARC_DISP8:
+ case elfcpp::R_SPARC_DISP16:
+ case elfcpp::R_SPARC_DISP32:
+ case elfcpp::R_SPARC_LO10:
+ case elfcpp::R_SPARC_WDISP30:
+ case elfcpp::R_SPARC_HI22:
+ case elfcpp::R_SPARC_UA16:
+ case elfcpp::R_SPARC_UA32:
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ // 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;
+ gold_assert(parameters->options().output_is_position_independent());
+ object->error(_("requires unsupported dynamic reloc; "
+ "recompile with -fPIC"));
+ this->issued_non_pic_error_ = true;
+ return;
+}
+
+// Return whether we need to make a PLT entry for a relocation of the
+// given type against a STT_GNU_IFUNC symbol.
+
+template<int size, bool big_endian>
+bool
+Target_sparc<size, big_endian>::Scan::reloc_needs_plt_for_ifunc(
+ Sized_relobj_file<size, big_endian>* 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.
+
+template<int size, bool big_endian>
+inline void
+Target_sparc<size, big_endian>::Scan::local(
+ Symbol_table* symtab,
+ Layout* layout,
+ Target_sparc<size, big_endian>* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, big_endian>& reloc,
+ unsigned int r_type,
+ const elfcpp::Sym<size, big_endian>& lsym,
+ bool is_discarded)
+{
+ if (is_discarded)
+ return;
+
+ bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
+ unsigned int orig_r_type = r_type;
+ r_type &= 0xff;
+
+ if (is_ifunc
+ && this->reloc_needs_plt_for_ifunc(object, r_type))
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ target->make_local_ifunc_plt_entry(symtab, layout, object, r_sym);
+ }
+
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_NONE:
+ case elfcpp::R_SPARC_REGISTER:
+ case elfcpp::R_SPARC_GNU_VTINHERIT:
+ case elfcpp::R_SPARC_GNU_VTENTRY:
+ break;
+
+ case elfcpp::R_SPARC_64:
+ case elfcpp::R_SPARC_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_SPARC_RELATIVE relocation so the dynamic loader can
+ // relocate it easily.
+ if (parameters->options().output_is_position_independent())
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ rela_dyn->add_local_relative(object, r_sym, elfcpp::R_SPARC_RELATIVE,
+ output_section, data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend(), is_ifunc);
+ }
+ break;
+
+ case elfcpp::R_SPARC_HIX22:
+ case elfcpp::R_SPARC_LOX10:
+ case elfcpp::R_SPARC_H34:
+ case elfcpp::R_SPARC_H44:
+ case elfcpp::R_SPARC_M44:
+ case elfcpp::R_SPARC_L44:
+ case elfcpp::R_SPARC_HH22:
+ case elfcpp::R_SPARC_HM10:
+ case elfcpp::R_SPARC_LM22:
+ case elfcpp::R_SPARC_UA64:
+ case elfcpp::R_SPARC_UA32:
+ case elfcpp::R_SPARC_UA16:
+ case elfcpp::R_SPARC_HI22:
+ case elfcpp::R_SPARC_LO10:
+ case elfcpp::R_SPARC_OLO10:
+ case elfcpp::R_SPARC_16:
+ case elfcpp::R_SPARC_11:
+ case elfcpp::R_SPARC_10:
+ case elfcpp::R_SPARC_8:
+ case elfcpp::R_SPARC_7:
+ case elfcpp::R_SPARC_6:
+ case elfcpp::R_SPARC_5:
+ // If building a shared library (or a position-independent
+ // executable), we need to create a dynamic relocation for
+ // this location.
+ if (parameters->options().output_is_position_independent())
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+
+ check_non_pic(object, r_type);
+ if (lsym.get_st_type() != elfcpp::STT_SECTION)
+ {
+ rela_dyn->add_local(object, r_sym, orig_r_type, output_section,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ else
+ {
+ gold_assert(lsym.get_st_value() == 0);
+ rela_dyn->add_symbolless_local_addend(object, r_sym, orig_r_type,
+ output_section, data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ }
+ break;
+
+ case elfcpp::R_SPARC_WDISP30:
+ case elfcpp::R_SPARC_WPLT30:
+ case elfcpp::R_SPARC_WDISP22:
+ case elfcpp::R_SPARC_WDISP19:
+ case elfcpp::R_SPARC_WDISP16:
+ case elfcpp::R_SPARC_WDISP10:
+ case elfcpp::R_SPARC_DISP8:
+ case elfcpp::R_SPARC_DISP16:
+ case elfcpp::R_SPARC_DISP32:
+ case elfcpp::R_SPARC_DISP64:
+ case elfcpp::R_SPARC_PC10:
+ case elfcpp::R_SPARC_PC22:
+ break;
+
+ case elfcpp::R_SPARC_GOTDATA_OP:
+ case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+ case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+ // We will optimize this into a GOT relative relocation
+ // and code transform the GOT load into an addition.
+ break;
+
+ case elfcpp::R_SPARC_GOT10:
+ case elfcpp::R_SPARC_GOT13:
+ case elfcpp::R_SPARC_GOT22:
+ {
+ // The symbol requires a GOT entry.
+ Output_data_got<size, big_endian>* got;
+ unsigned int r_sym;
+
+ got = target->got_section(symtab, layout);
+ r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+
+ // If we are generating a shared object, we need to add a
+ // dynamic relocation for this symbol's GOT entry.
+ if (parameters->options().output_is_position_independent())
+ {
+ if (!object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD))
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ unsigned int off = got->add_constant(0);
+ object->set_local_got_offset(r_sym, GOT_TYPE_STANDARD, off);
+ rela_dyn->add_local_relative(object, r_sym,
+ elfcpp::R_SPARC_RELATIVE,
+ got, off, 0, is_ifunc);
+ }
+ }
+ else
+ got->add_local(object, r_sym, GOT_TYPE_STANDARD);
+ }
+ break;
+
+ // These are initial TLS relocs, which are expected when
+ // linking.
+ case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
+ case elfcpp::R_SPARC_TLS_GD_LO10:
+ case elfcpp::R_SPARC_TLS_GD_ADD:
+ case elfcpp::R_SPARC_TLS_GD_CALL:
+ case elfcpp::R_SPARC_TLS_LDM_HI22 : // Local-dynamic
+ case elfcpp::R_SPARC_TLS_LDM_LO10:
+ case elfcpp::R_SPARC_TLS_LDM_ADD:
+ case elfcpp::R_SPARC_TLS_LDM_CALL:
+ case elfcpp::R_SPARC_TLS_LDO_HIX22: // Alternate local-dynamic
+ case elfcpp::R_SPARC_TLS_LDO_LOX10:
+ case elfcpp::R_SPARC_TLS_LDO_ADD:
+ case elfcpp::R_SPARC_TLS_IE_HI22: // Initial-exec
+ case elfcpp::R_SPARC_TLS_IE_LO10:
+ case elfcpp::R_SPARC_TLS_IE_LD:
+ case elfcpp::R_SPARC_TLS_IE_LDX:
+ case elfcpp::R_SPARC_TLS_IE_ADD:
+ case elfcpp::R_SPARC_TLS_LE_HIX22: // Local-exec
+ case elfcpp::R_SPARC_TLS_LE_LOX10:
+ {
+ bool output_is_shared = parameters->options().shared();
+ const tls::Tls_optimization optimized_type
+ = optimize_tls_reloc(!output_is_shared, r_type);
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
+ case elfcpp::R_SPARC_TLS_GD_LO10:
+ case elfcpp::R_SPARC_TLS_GD_ADD:
+ case elfcpp::R_SPARC_TLS_GD_CALL:
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ 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,
+ lsym.get_st_shndx(),
+ GOT_TYPE_TLS_PAIR,
+ target->rela_dyn_section(layout),
+ (size == 64
+ ? elfcpp::R_SPARC_TLS_DTPMOD64
+ : elfcpp::R_SPARC_TLS_DTPMOD32));
+ if (r_type == elfcpp::R_SPARC_TLS_GD_CALL)
+ generate_tls_call(symtab, layout, target);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_local(object, r_type);
+ break;
+
+ case elfcpp::R_SPARC_TLS_LDM_HI22 : // Local-dynamic
+ case elfcpp::R_SPARC_TLS_LDM_LO10:
+ case elfcpp::R_SPARC_TLS_LDM_ADD:
+ case elfcpp::R_SPARC_TLS_LDM_CALL:
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the module index.
+ target->got_mod_index_entry(symtab, layout, object);
+
+ if (r_type == elfcpp::R_SPARC_TLS_LDM_CALL)
+ generate_tls_call(symtab, layout, target);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_local(object, r_type);
+ break;
+
+ case elfcpp::R_SPARC_TLS_LDO_HIX22: // Alternate local-dynamic
+ case elfcpp::R_SPARC_TLS_LDO_LOX10:
+ case elfcpp::R_SPARC_TLS_LDO_ADD:
+ break;
+
+ case elfcpp::R_SPARC_TLS_IE_HI22: // Initial-exec
+ case elfcpp::R_SPARC_TLS_IE_LO10:
+ case elfcpp::R_SPARC_TLS_IE_LD:
+ case elfcpp::R_SPARC_TLS_IE_LDX:
+ case elfcpp::R_SPARC_TLS_IE_ADD:
+ layout->set_has_static_tls();
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+
+ if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_OFFSET))
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ unsigned int off = got->add_constant(0);
+
+ object->set_local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET, off);
+
+ rela_dyn->add_symbolless_local_addend(object, r_sym,
+ (size == 64 ?
+ elfcpp::R_SPARC_TLS_TPOFF64 :
+ elfcpp::R_SPARC_TLS_TPOFF32),
+ got, off, 0);
+ }
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_local(object, r_type);
+ break;
+
+ case elfcpp::R_SPARC_TLS_LE_HIX22: // Local-exec
+ case elfcpp::R_SPARC_TLS_LE_LOX10:
+ layout->set_has_static_tls();
+ if (output_is_shared)
+ {
+ // We need to create a dynamic relocation.
+ gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_symbolless_local_addend(object, r_sym, r_type,
+ output_section, data_shndx,
+ reloc.get_r_offset(), 0);
+ }
+ break;
+ }
+ }
+ break;
+
+ // These are relocations which should only be seen by the
+ // dynamic linker, and should never be seen here.
+ case elfcpp::R_SPARC_COPY:
+ case elfcpp::R_SPARC_GLOB_DAT:
+ case elfcpp::R_SPARC_JMP_SLOT:
+ case elfcpp::R_SPARC_JMP_IREL:
+ case elfcpp::R_SPARC_RELATIVE:
+ case elfcpp::R_SPARC_IRELATIVE:
+ case elfcpp::R_SPARC_TLS_DTPMOD64:
+ case elfcpp::R_SPARC_TLS_DTPMOD32:
+ case elfcpp::R_SPARC_TLS_DTPOFF64:
+ case elfcpp::R_SPARC_TLS_DTPOFF32:
+ case elfcpp::R_SPARC_TLS_TPOFF64:
+ case elfcpp::R_SPARC_TLS_TPOFF32:
+ gold_error(_("%s: unexpected reloc %u in object file"),
+ object->name().c_str(), r_type);
+ break;
+
+ default:
+ unsupported_reloc_local(object, r_type);
+ break;
+ }
+}
+
+// Report an unsupported relocation against a global symbol.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::Scan::unsupported_reloc_global(
+ Sized_relobj_file<size, 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());
+}
+
+// Scan a relocation for a global symbol.
+
+template<int size, bool big_endian>
+inline void
+Target_sparc<size, big_endian>::Scan::global(
+ Symbol_table* symtab,
+ Layout* layout,
+ Target_sparc<size, big_endian>* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, big_endian>& reloc,
+ unsigned int r_type,
+ Symbol* gsym)
+{
+ unsigned int orig_r_type = r_type;
+ bool is_ifunc = gsym->type() == elfcpp::STT_GNU_IFUNC;
+
+ // 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 &= 0xff;
+
+ // A STT_GNU_IFUNC symbol may require a PLT entry.
+ if (is_ifunc
+ && this->reloc_needs_plt_for_ifunc(object, r_type))
+ target->make_plt_entry(symtab, layout, gsym);
+
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_NONE:
+ case elfcpp::R_SPARC_REGISTER:
+ case elfcpp::R_SPARC_GNU_VTINHERIT:
+ case elfcpp::R_SPARC_GNU_VTENTRY:
+ break;
+
+ case elfcpp::R_SPARC_PLT64:
+ case elfcpp::R_SPARC_PLT32:
+ case elfcpp::R_SPARC_HIPLT22:
+ case elfcpp::R_SPARC_LOPLT10:
+ case elfcpp::R_SPARC_PCPLT32:
+ case elfcpp::R_SPARC_PCPLT22:
+ case elfcpp::R_SPARC_PCPLT10:
+ case elfcpp::R_SPARC_WPLT30:
+ // 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_SPARC_DISP8:
+ case elfcpp::R_SPARC_DISP16:
+ case elfcpp::R_SPARC_DISP32:
+ case elfcpp::R_SPARC_DISP64:
+ case elfcpp::R_SPARC_PC_HH22:
+ case elfcpp::R_SPARC_PC_HM10:
+ case elfcpp::R_SPARC_PC_LM22:
+ case elfcpp::R_SPARC_PC10:
+ case elfcpp::R_SPARC_PC22:
+ case elfcpp::R_SPARC_WDISP30:
+ case elfcpp::R_SPARC_WDISP22:
+ case elfcpp::R_SPARC_WDISP19:
+ case elfcpp::R_SPARC_WDISP16:
+ case elfcpp::R_SPARC_WDISP10:
+ {
+ if (gsym->needs_plt_entry())
+ target->make_plt_entry(symtab, layout, gsym);
+ // Make a dynamic relocation if necessary.
+ if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+ {
+ if (gsym->may_need_copy_reloc())
+ {
+ target->copy_reloc(symtab, layout, object,
+ data_shndx, output_section, gsym,
+ reloc);
+ }
+ else
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ check_non_pic(object, r_type);
+ rela_dyn->add_global(gsym, orig_r_type, output_section, object,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ }
+ }
+ break;
+
+ case elfcpp::R_SPARC_UA64:
+ case elfcpp::R_SPARC_64:
+ case elfcpp::R_SPARC_HIX22:
+ case elfcpp::R_SPARC_LOX10:
+ case elfcpp::R_SPARC_H34:
+ case elfcpp::R_SPARC_H44:
+ case elfcpp::R_SPARC_M44:
+ case elfcpp::R_SPARC_L44:
+ case elfcpp::R_SPARC_HH22:
+ case elfcpp::R_SPARC_HM10:
+ case elfcpp::R_SPARC_LM22:
+ case elfcpp::R_SPARC_HI22:
+ case elfcpp::R_SPARC_LO10:
+ case elfcpp::R_SPARC_OLO10:
+ case elfcpp::R_SPARC_UA32:
+ case elfcpp::R_SPARC_32:
+ case elfcpp::R_SPARC_UA16:
+ case elfcpp::R_SPARC_16:
+ case elfcpp::R_SPARC_11:
+ case elfcpp::R_SPARC_10:
+ case elfcpp::R_SPARC_8:
+ case elfcpp::R_SPARC_7:
+ case elfcpp::R_SPARC_6:
+ case elfcpp::R_SPARC_5:
+ {
+ // Make a PLT entry if necessary.
+ if (gsym->needs_plt_entry())
+ {
+ target->make_plt_entry(symtab, layout, gsym);
+ // Since this is not a PC-relative relocation, we may be
+ // taking the address of a function. In that case we need to
+ // set the entry in the dynamic symbol table to the address of
+ // the PLT entry.
+ if (gsym->is_from_dynobj() && !parameters->options().shared())
+ gsym->set_needs_dynsym_value();
+ }
+ // Make a dynamic relocation if necessary.
+ if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+ {
+ unsigned int r_off = reloc.get_r_offset();
+
+ // The assembler can sometimes emit unaligned relocations
+ // for dwarf2 cfi directives.
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_16:
+ if (r_off & 0x1)
+ orig_r_type = r_type = elfcpp::R_SPARC_UA16;
+ break;
+ case elfcpp::R_SPARC_32:
+ if (r_off & 0x3)
+ orig_r_type = r_type = elfcpp::R_SPARC_UA32;
+ break;
+ case elfcpp::R_SPARC_64:
+ if (r_off & 0x7)
+ orig_r_type = r_type = elfcpp::R_SPARC_UA64;
+ break;
+ case elfcpp::R_SPARC_UA16:
+ if (!(r_off & 0x1))
+ orig_r_type = r_type = elfcpp::R_SPARC_16;
+ break;
+ case elfcpp::R_SPARC_UA32:
+ if (!(r_off & 0x3))
+ orig_r_type = r_type = elfcpp::R_SPARC_32;
+ break;
+ case elfcpp::R_SPARC_UA64:
+ if (!(r_off & 0x7))
+ orig_r_type = r_type = elfcpp::R_SPARC_64;
+ break;
+ }
+
+ if (gsym->may_need_copy_reloc())
+ {
+ target->copy_reloc(symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
+ }
+ else if (((size == 64 && r_type == elfcpp::R_SPARC_64)
+ || (size == 32 && r_type == elfcpp::R_SPARC_32))
+ && gsym->type() == elfcpp::STT_GNU_IFUNC
+ && 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* rela_dyn =
+ target->rela_ifunc_section(layout);
+ unsigned int r_type = elfcpp::R_SPARC_IRELATIVE;
+ rela_dyn->add_symbolless_global_addend(gsym, r_type,
+ output_section, object,
+ data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ else if ((r_type == elfcpp::R_SPARC_32
+ || r_type == elfcpp::R_SPARC_64)
+ && gsym->can_use_relative_reloc(false))
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
+ output_section, object,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend(), is_ifunc);
+ }
+ else
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+
+ check_non_pic(object, r_type);
+ if (gsym->is_from_dynobj()
+ || gsym->is_undefined()
+ || gsym->is_preemptible())
+ rela_dyn->add_global(gsym, orig_r_type, output_section,
+ object, data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend());
+ else
+ rela_dyn->add_symbolless_global_addend(gsym, orig_r_type,
+ output_section,
+ object, data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ }
+ }
+ break;
+
+ case elfcpp::R_SPARC_GOTDATA_OP:
+ case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+ case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+ if (gsym->is_defined()
+ && !gsym->is_from_dynobj()
+ && !gsym->is_preemptible()
+ && !is_ifunc)
+ {
+ // We will optimize this into a GOT relative relocation
+ // and code transform the GOT load into an addition.
+ break;
+ }
+ case elfcpp::R_SPARC_GOT10:
+ case elfcpp::R_SPARC_GOT13:
+ case elfcpp::R_SPARC_GOT22:
+ {
+ // The symbol requires a GOT entry.
+ Output_data_got<size, big_endian>* got;
+
+ got = target->got_section(symtab, layout);
+ if (gsym->final_value_is_known())
+ {
+ // 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.
+ bool is_ifunc = gsym->type() == elfcpp::STT_GNU_IFUNC;
+
+ // 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.
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ if (gsym->is_from_dynobj()
+ || gsym->is_undefined()
+ || gsym->is_preemptible()
+ || (gsym->visibility() == elfcpp::STV_PROTECTED
+ && parameters->options().shared())
+ || (gsym->type() == elfcpp::STT_GNU_IFUNC
+ && parameters->options().output_is_position_independent()
+ && !gsym->is_forced_local()))
+ {
+ unsigned int r_type = elfcpp::R_SPARC_GLOB_DAT;
+
+ // If this symbol is forced local, this relocation will
+ // not work properly. That's because ld.so on sparc
+ // (and 32-bit powerpc) expects st_value in the r_addend
+ // of relocations for STB_LOCAL symbols. Curiously the
+ // BFD linker does not promote global hidden symbols to be
+ // STB_LOCAL in the dynamic symbol table like Gold does.
+ gold_assert(!gsym->is_forced_local());
+ got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn,
+ r_type);
+ }
+ else if (!gsym->has_got_offset(GOT_TYPE_STANDARD))
+ {
+ unsigned int off = got->add_constant(0);
+
+ gsym->set_got_offset(GOT_TYPE_STANDARD, off);
+ if (is_ifunc)
+ {
+ // 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();
+ }
+ rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
+ got, off, 0, is_ifunc);
+ }
+ }
+ }
+ break;
+
+ // These are initial tls relocs, which are expected when
+ // linking.
+ case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
+ case elfcpp::R_SPARC_TLS_GD_LO10:
+ case elfcpp::R_SPARC_TLS_GD_ADD:
+ case elfcpp::R_SPARC_TLS_GD_CALL:
+ case elfcpp::R_SPARC_TLS_LDM_HI22: // Local-dynamic
+ case elfcpp::R_SPARC_TLS_LDM_LO10:
+ case elfcpp::R_SPARC_TLS_LDM_ADD:
+ case elfcpp::R_SPARC_TLS_LDM_CALL:
+ case elfcpp::R_SPARC_TLS_LDO_HIX22: // Alternate local-dynamic
+ case elfcpp::R_SPARC_TLS_LDO_LOX10:
+ case elfcpp::R_SPARC_TLS_LDO_ADD:
+ case elfcpp::R_SPARC_TLS_LE_HIX22:
+ case elfcpp::R_SPARC_TLS_LE_LOX10:
+ case elfcpp::R_SPARC_TLS_IE_HI22: // Initial-exec
+ case elfcpp::R_SPARC_TLS_IE_LO10:
+ case elfcpp::R_SPARC_TLS_IE_LD:
+ case elfcpp::R_SPARC_TLS_IE_LDX:
+ case elfcpp::R_SPARC_TLS_IE_ADD:
+ {
+ const bool is_final = gsym->final_value_is_known();
+ const tls::Tls_optimization optimized_type
+ = optimize_tls_reloc(is_final, r_type);
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
+ case elfcpp::R_SPARC_TLS_GD_LO10:
+ case elfcpp::R_SPARC_TLS_GD_ADD:
+ case elfcpp::R_SPARC_TLS_GD_CALL:
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
+ target->rela_dyn_section(layout),
+ (size == 64
+ ? elfcpp::R_SPARC_TLS_DTPMOD64
+ : elfcpp::R_SPARC_TLS_DTPMOD32),
+ (size == 64
+ ? elfcpp::R_SPARC_TLS_DTPOFF64
+ : elfcpp::R_SPARC_TLS_DTPOFF32));
+
+ // Emit R_SPARC_WPLT30 against "__tls_get_addr"
+ if (r_type == elfcpp::R_SPARC_TLS_GD_CALL)
+ generate_tls_call(symtab, layout, target);
+ }
+ else if (optimized_type == tls::TLSOPT_TO_IE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ target->rela_dyn_section(layout),
+ (size == 64 ?
+ elfcpp::R_SPARC_TLS_TPOFF64 :
+ elfcpp::R_SPARC_TLS_TPOFF32));
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_global(object, r_type, gsym);
+ break;
+
+ case elfcpp::R_SPARC_TLS_LDM_HI22: // Local-dynamic
+ case elfcpp::R_SPARC_TLS_LDM_LO10:
+ case elfcpp::R_SPARC_TLS_LDM_ADD:
+ case elfcpp::R_SPARC_TLS_LDM_CALL:
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the module index.
+ target->got_mod_index_entry(symtab, layout, object);
+
+ if (r_type == elfcpp::R_SPARC_TLS_LDM_CALL)
+ generate_tls_call(symtab, layout, target);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_global(object, r_type, gsym);
+ break;
+
+ case elfcpp::R_SPARC_TLS_LDO_HIX22: // Alternate local-dynamic
+ case elfcpp::R_SPARC_TLS_LDO_LOX10:
+ case elfcpp::R_SPARC_TLS_LDO_ADD:
+ break;
+
+ case elfcpp::R_SPARC_TLS_LE_HIX22:
+ case elfcpp::R_SPARC_TLS_LE_LOX10:
+ layout->set_has_static_tls();
+ if (parameters->options().shared())
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_symbolless_global_addend(gsym, orig_r_type,
+ output_section, object,
+ data_shndx, reloc.get_r_offset(),
+ 0);
+ }
+ break;
+
+ case elfcpp::R_SPARC_TLS_IE_HI22: // Initial-exec
+ case elfcpp::R_SPARC_TLS_IE_LO10:
+ case elfcpp::R_SPARC_TLS_IE_LD:
+ case elfcpp::R_SPARC_TLS_IE_LDX:
+ case elfcpp::R_SPARC_TLS_IE_ADD:
+ layout->set_has_static_tls();
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ target->rela_dyn_section(layout),
+ (size == 64
+ ? elfcpp::R_SPARC_TLS_TPOFF64
+ : elfcpp::R_SPARC_TLS_TPOFF32));
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_global(object, r_type, gsym);
+ break;
+ }
+ }
+ break;
+
+ // These are relocations which should only be seen by the
+ // dynamic linker, and should never be seen here.
+ case elfcpp::R_SPARC_COPY:
+ case elfcpp::R_SPARC_GLOB_DAT:
+ case elfcpp::R_SPARC_JMP_SLOT:
+ case elfcpp::R_SPARC_JMP_IREL:
+ case elfcpp::R_SPARC_RELATIVE:
+ case elfcpp::R_SPARC_IRELATIVE:
+ case elfcpp::R_SPARC_TLS_DTPMOD64:
+ case elfcpp::R_SPARC_TLS_DTPMOD32:
+ case elfcpp::R_SPARC_TLS_DTPOFF64:
+ case elfcpp::R_SPARC_TLS_DTPOFF32:
+ case elfcpp::R_SPARC_TLS_TPOFF64:
+ case elfcpp::R_SPARC_TLS_TPOFF32:
+ gold_error(_("%s: unexpected reloc %u in object file"),
+ object->name().c_str(), r_type);
+ break;
+
+ default:
+ unsupported_reloc_global(object, r_type, gsym);
+ break;
+ }
+}
+
+// Process relocations for gc.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::gc_process_relocs(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, 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_sparc<size, big_endian> Sparc;
+ typedef typename Target_sparc<size, big_endian>::Scan Scan;
+
+ gold::gc_process_relocs<size, big_endian, Sparc, elfcpp::SHT_RELA, Scan,
+ typename Target_sparc::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<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::scan_relocs(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols)
+{
+ typedef Target_sparc<size, big_endian> Sparc;
+ typedef typename Target_sparc<size, big_endian>::Scan Scan;
+
+ if (sh_type == elfcpp::SHT_REL)
+ {
+ gold_error(_("%s: unsupported REL reloc section"),
+ object->name().c_str());
+ return;
+ }
+
+ gold::scan_relocs<size, big_endian, Sparc, elfcpp::SHT_RELA, 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<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::do_finalize_sections(
+ Layout* layout,
+ const Input_objects*,
+ Symbol_table* symtab)
+{
+ if (this->plt_)
+ this->plt_->emit_pending_ifunc_relocs();
+
+ // Fill in some more dynamic tags.
+ const Reloc_section* rel_plt = (this->plt_ == NULL
+ ? NULL
+ : this->plt_->rel_plt());
+ layout->add_target_dynamic_tags(false, this->plt_, rel_plt,
+ this->rela_dyn_, true, true);
+
+ // 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->rela_dyn_section(layout));
+
+ if (parameters->doing_static_link()
+ && (this->plt_ == NULL || !this->plt_->has_ifunc_section()))
+ {
+ // If linking statically, make sure that the __rela_iplt symbols
+ // were defined if necessary, even if we didn't create a PLT.
+ static const Define_symbol_in_segment syms[] =
+ {
+ {
+ "__rela_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
+ },
+ {
+ "__rela_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());
+ }
+}
+
+// Perform a relocation.
+
+template<int size, bool big_endian>
+inline bool
+Target_sparc<size, big_endian>::Relocate::relocate(
+ const Relocate_info<size, big_endian>* relinfo,
+ Target_sparc* target,
+ Output_section*,
+ size_t relnum,
+ const elfcpp::Rela<size, big_endian>& rela,
+ unsigned int r_type,
+ const Sized_symbol<size>* gsym,
+ const Symbol_value<size>* psymval,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size)
+{
+ bool orig_is_ifunc = psymval->is_ifunc_symbol();
+ r_type &= 0xff;
+
+ if (this->ignore_gd_add_)
+ {
+ if (r_type != elfcpp::R_SPARC_TLS_GD_ADD)
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("missing expected TLS relocation"));
+ else
+ {
+ this->ignore_gd_add_ = false;
+ return false;
+ }
+ }
+
+ if (view == NULL)
+ return true;
+
+ if (this->reloc_adjust_addr_ == view)
+ view -= 4;
+
+ typedef Sparc_relocate_functions<size, big_endian> Reloc;
+ const Sized_relobj_file<size, big_endian>* object = relinfo->object;
+
+ // Pick the value to use for symbols defined in shared objects.
+ Symbol_value<size> symval;
+ if (gsym != NULL
+ && gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
+ {
+ elfcpp::Elf_Xword value;
+
+ value = target->plt_address_for_global(gsym);
+
+ symval.set_output_value(value);
+
+ psymval = &symval;
+ }
+ else if (gsym == NULL && orig_is_ifunc)
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.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;
+ }
+ }
+
+ const elfcpp::Elf_Xword addend = rela.get_r_addend();
+
+ // Get the GOT offset if needed. Unlike i386 and x86_64, our GOT
+ // pointer points to the beginning, not the end, of the table.
+ // So we just use the plain offset.
+ unsigned int got_offset = 0;
+ bool gdop_valid = false;
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_GOTDATA_OP:
+ case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+ case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+ // If this is local, we did not create a GOT entry because we
+ // intend to transform this into a GOT relative relocation.
+ if (gsym == NULL
+ || (gsym->is_defined()
+ && !gsym->is_from_dynobj()
+ && !gsym->is_preemptible()
+ && !orig_is_ifunc))
+ {
+ got_offset = psymval->value(object, 0) - target->got_address();
+ gdop_valid = true;
+ break;
+ }
+ case elfcpp::R_SPARC_GOT10:
+ case elfcpp::R_SPARC_GOT13:
+ case elfcpp::R_SPARC_GOT22:
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+ got_offset = gsym->got_offset(GOT_TYPE_STANDARD);
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+ got_offset = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_NONE:
+ case elfcpp::R_SPARC_REGISTER:
+ case elfcpp::R_SPARC_GNU_VTINHERIT:
+ case elfcpp::R_SPARC_GNU_VTENTRY:
+ break;
+
+ case elfcpp::R_SPARC_8:
+ Relocate_functions<size, big_endian>::rela8(view, object,
+ psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_16:
+ if (rela.get_r_offset() & 0x1)
+ {
+ // The assembler can sometimes emit unaligned relocations
+ // for dwarf2 cfi directives.
+ Reloc::ua16(view, object, psymval, addend);
+ }
+ else
+ Relocate_functions<size, big_endian>::rela16(view, object,
+ psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_32:
+ if (!parameters->options().output_is_position_independent())
+ {
+ if (rela.get_r_offset() & 0x3)
+ {
+ // The assembler can sometimes emit unaligned relocations
+ // for dwarf2 cfi directives.
+ Reloc::ua32(view, object, psymval, addend);
+ }
+ else
+ Relocate_functions<size, big_endian>::rela32(view, object,
+ psymval, addend);
+ }
+ break;
+
+ case elfcpp::R_SPARC_DISP8:
+ Reloc::disp8(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_DISP16:
+ Reloc::disp16(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_DISP32:
+ Reloc::disp32(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_DISP64:
+ Reloc::disp64(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_WDISP30:
+ case elfcpp::R_SPARC_WPLT30:
+ Reloc::wdisp30(view, object, psymval, addend, address);
+ if (target->may_relax())
+ relax_call(target, view, rela, view_size);
+ break;
+
+ case elfcpp::R_SPARC_WDISP22:
+ Reloc::wdisp22(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_WDISP19:
+ Reloc::wdisp19(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_WDISP16:
+ Reloc::wdisp16(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_WDISP10:
+ Reloc::wdisp10(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_HI22:
+ Reloc::hi22(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_22:
+ Reloc::rela32_22(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_13:
+ Reloc::rela32_13(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_LO10:
+ Reloc::lo10(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_GOT10:
+ Reloc::lo10(view, got_offset, addend);
+ break;
+
+ case elfcpp::R_SPARC_GOTDATA_OP:
+ if (gdop_valid)
+ {
+ typedef typename elfcpp::Swap<32, true>::Valtype Insntype;
+ Insntype* wv = reinterpret_cast<Insntype*>(view);
+ Insntype val;
+
+ // {ld,ldx} [%rs1 + %rs2], %rd --> add %rs1, %rs2, %rd
+ val = elfcpp::Swap<32, true>::readval(wv);
+ val = 0x80000000 | (val & 0x3e07c01f);
+ elfcpp::Swap<32, true>::writeval(wv, val);
+ }
+ break;
+
+ case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+ if (gdop_valid)
+ {
+ Reloc::gdop_lox10(view, got_offset, addend);
+ break;
+ }
+ /* Fall through. */
+ case elfcpp::R_SPARC_GOT13:
+ Reloc::rela32_13(view, got_offset, addend);
+ break;
+
+ case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+ if (gdop_valid)
+ {
+ Reloc::gdop_hix22(view, got_offset, addend);
+ break;
+ }
+ /* Fall through. */
+ case elfcpp::R_SPARC_GOT22:
+ Reloc::hi22(view, got_offset, addend);
+ break;
+
+ case elfcpp::R_SPARC_PC10:
+ Reloc::pc10(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_PC22:
+ Reloc::pc22(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_TLS_DTPOFF32:
+ case elfcpp::R_SPARC_UA32:
+ Reloc::ua32(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_PLT64:
+ Relocate_functions<size, big_endian>::rela64(view, object,
+ psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_PLT32:
+ Relocate_functions<size, big_endian>::rela32(view, object,
+ psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_HIPLT22:
+ Reloc::hi22(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_LOPLT10:
+ Reloc::lo10(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_PCPLT32:
+ Reloc::disp32(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_PCPLT22:
+ Reloc::pcplt22(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_PCPLT10:
+ Reloc::lo10(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_64:
+ if (!parameters->options().output_is_position_independent())
+ {
+ if (rela.get_r_offset() & 0x7)
+ {
+ // The assembler can sometimes emit unaligned relocations
+ // for dwarf2 cfi directives.
+ Reloc::ua64(view, object, psymval, addend);
+ }
+ else
+ Relocate_functions<size, big_endian>::rela64(view, object,
+ psymval, addend);
+ }
+ break;
+
+ case elfcpp::R_SPARC_OLO10:
+ {
+ unsigned int addend2 = rela.get_r_info() & 0xffffffff;
+ addend2 = ((addend2 >> 8) ^ 0x800000) - 0x800000;
+ Reloc::olo10(view, object, psymval, addend, addend2);
+ }
+ break;
+
+ case elfcpp::R_SPARC_HH22:
+ Reloc::hh22(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_PC_HH22:
+ Reloc::pc_hh22(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_HM10:
+ Reloc::hm10(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_PC_HM10:
+ Reloc::pc_hm10(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_LM22:
+ Reloc::hi22(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_PC_LM22:
+ Reloc::pcplt22(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_SPARC_11:
+ Reloc::rela32_11(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_10:
+ Reloc::rela32_10(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_7:
+ Reloc::rela32_7(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_6:
+ Reloc::rela32_6(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_5:
+ Reloc::rela32_5(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_HIX22:
+ Reloc::hix22(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_LOX10:
+ Reloc::lox10(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_H34:
+ Reloc::h34(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_H44:
+ Reloc::h44(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_M44:
+ Reloc::m44(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_L44:
+ Reloc::l44(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_TLS_DTPOFF64:
+ case elfcpp::R_SPARC_UA64:
+ Reloc::ua64(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_UA16:
+ Reloc::ua16(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_SPARC_TLS_GD_HI22:
+ case elfcpp::R_SPARC_TLS_GD_LO10:
+ case elfcpp::R_SPARC_TLS_GD_ADD:
+ case elfcpp::R_SPARC_TLS_GD_CALL:
+ case elfcpp::R_SPARC_TLS_LDM_HI22:
+ case elfcpp::R_SPARC_TLS_LDM_LO10:
+ case elfcpp::R_SPARC_TLS_LDM_ADD:
+ case elfcpp::R_SPARC_TLS_LDM_CALL:
+ case elfcpp::R_SPARC_TLS_LDO_HIX22:
+ case elfcpp::R_SPARC_TLS_LDO_LOX10:
+ case elfcpp::R_SPARC_TLS_LDO_ADD:
+ case elfcpp::R_SPARC_TLS_IE_HI22:
+ case elfcpp::R_SPARC_TLS_IE_LO10:
+ case elfcpp::R_SPARC_TLS_IE_LD:
+ case elfcpp::R_SPARC_TLS_IE_LDX:
+ case elfcpp::R_SPARC_TLS_IE_ADD:
+ case elfcpp::R_SPARC_TLS_LE_HIX22:
+ case elfcpp::R_SPARC_TLS_LE_LOX10:
+ this->relocate_tls(relinfo, target, relnum, rela,
+ r_type, gsym, psymval, view,
+ address, view_size);
+ break;
+
+ case elfcpp::R_SPARC_COPY:
+ case elfcpp::R_SPARC_GLOB_DAT:
+ case elfcpp::R_SPARC_JMP_SLOT:
+ case elfcpp::R_SPARC_JMP_IREL:
+ case elfcpp::R_SPARC_RELATIVE:
+ case elfcpp::R_SPARC_IRELATIVE:
+ // These are outstanding tls relocs, which are unexpected when
+ // linking.
+ case elfcpp::R_SPARC_TLS_DTPMOD64:
+ case elfcpp::R_SPARC_TLS_DTPMOD32:
+ case elfcpp::R_SPARC_TLS_TPOFF64:
+ case elfcpp::R_SPARC_TLS_TPOFF32:
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unexpected reloc %u in object file"),
+ r_type);
+ break;
+
+ default:
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unsupported reloc %u"),
+ r_type);
+ break;
+ }
+
+ return true;
+}
+
+// Perform a TLS relocation.
+
+template<int size, bool big_endian>
+inline void
+Target_sparc<size, big_endian>::Relocate::relocate_tls(
+ const Relocate_info<size, big_endian>* relinfo,
+ Target_sparc<size, big_endian>* target,
+ size_t relnum,
+ const elfcpp::Rela<size, big_endian>& rela,
+ unsigned int r_type,
+ const Sized_symbol<size>* gsym,
+ const Symbol_value<size>* psymval,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type)
+{
+ Output_segment* tls_segment = relinfo->layout->tls_segment();
+ typedef Sparc_relocate_functions<size, big_endian> Reloc;
+ const Sized_relobj_file<size, big_endian>* object = relinfo->object;
+ typedef typename elfcpp::Swap<32, true>::Valtype Insntype;
+
+ const elfcpp::Elf_Xword addend = rela.get_r_addend();
+ typename elfcpp::Elf_types<size>::Elf_Addr value = psymval->value(object, 0);
+
+ const bool is_final =
+ (gsym == NULL
+ ? !parameters->options().output_is_position_independent()
+ : gsym->final_value_is_known());
+ const tls::Tls_optimization optimized_type
+ = optimize_tls_reloc(is_final, r_type);
+
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_TLS_GD_HI22:
+ case elfcpp::R_SPARC_TLS_GD_LO10:
+ case elfcpp::R_SPARC_TLS_GD_ADD:
+ case elfcpp::R_SPARC_TLS_GD_CALL:
+ if (optimized_type == tls::TLSOPT_TO_LE)
+ {
+ Insntype* wv = reinterpret_cast<Insntype*>(view);
+ Insntype val;
+
+ value -= tls_segment->memsz();
+
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_TLS_GD_HI22:
+ // TLS_GD_HI22 --> TLS_LE_HIX22
+ Reloc::hix22(view, value, addend);
+ break;
+
+ case elfcpp::R_SPARC_TLS_GD_LO10:
+ // TLS_GD_LO10 --> TLS_LE_LOX10
+ Reloc::lox10(view, value, addend);
+ break;
+
+ case elfcpp::R_SPARC_TLS_GD_ADD:
+ // add %reg1, %reg2, %reg3 --> mov %g7, %reg2, %reg3
+ val = elfcpp::Swap<32, true>::readval(wv);
+ val = (val & ~0x7c000) | 0x1c000;
+ elfcpp::Swap<32, true>::writeval(wv, val);
+ break;
+ case elfcpp::R_SPARC_TLS_GD_CALL:
+ // call __tls_get_addr --> nop
+ elfcpp::Swap<32, true>::writeval(wv, sparc_nop);
+ break;
+ }
+ break;
+ }
+ else
+ {
+ unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+ ? GOT_TYPE_TLS_OFFSET
+ : GOT_TYPE_TLS_PAIR);
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(got_type));
+ value = gsym->got_offset(got_type);
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ value = object->local_got_offset(r_sym, got_type);
+ }
+ if (optimized_type == tls::TLSOPT_TO_IE)
+ {
+ Insntype* wv = reinterpret_cast<Insntype*>(view);
+ Insntype val;
+
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_TLS_GD_HI22:
+ // TLS_GD_HI22 --> TLS_IE_HI22
+ Reloc::hi22(view, value, addend);
+ break;
+
+ case elfcpp::R_SPARC_TLS_GD_LO10:
+ // TLS_GD_LO10 --> TLS_IE_LO10
+ Reloc::lo10(view, value, addend);
+ break;
+
+ case elfcpp::R_SPARC_TLS_GD_ADD:
+ // add %reg1, %reg2, %reg3 --> ld [%reg1 + %reg2], %reg3
+ val = elfcpp::Swap<32, true>::readval(wv);
+
+ if (size == 64)
+ val |= 0xc0580000;
+ else
+ val |= 0xc0000000;
+
+ elfcpp::Swap<32, true>::writeval(wv, val);
+ break;
+
+ case elfcpp::R_SPARC_TLS_GD_CALL:
+ // The compiler can put the TLS_GD_ADD instruction
+ // into the delay slot of the call. If so, we need
+ // to transpose the two instructions so that the
+ // new sequence works properly.
+ //
+ // The test we use is if the instruction in the
+ // delay slot is an add with destination register
+ // equal to %o0
+ val = elfcpp::Swap<32, true>::readval(wv + 1);
+ if ((val & 0x81f80000) == 0x80000000
+ && ((val >> 25) & 0x1f) == 0x8)
+ {
+ if (size == 64)
+ val |= 0xc0580000;
+ else
+ val |= 0xc0000000;
+
+ elfcpp::Swap<32, true>::writeval(wv, val);
+
+ wv += 1;
+ this->ignore_gd_add_ = true;
+ }
+ else
+ {
+ // Even if the delay slot isn't the TLS_GD_ADD
+ // instruction, we still have to handle the case
+ // where it sets up %o0 in some other way.
+ elfcpp::Swap<32, true>::writeval(wv, val);
+ wv += 1;
+ this->reloc_adjust_addr_ = view + 4;
+ }
+ // call __tls_get_addr --> add %g7, %o0, %o0
+ elfcpp::Swap<32, true>::writeval(wv, 0x9001c008);
+ break;
+ }
+ break;
+ }
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_TLS_GD_HI22:
+ Reloc::hi22(view, value, addend);
+ break;
+ case elfcpp::R_SPARC_TLS_GD_LO10:
+ Reloc::lo10(view, value, addend);
+ break;
+ case elfcpp::R_SPARC_TLS_GD_ADD:
+ break;
+ case elfcpp::R_SPARC_TLS_GD_CALL:
+ {
+ Symbol_value<size> symval;
+ elfcpp::Elf_Xword value;
+ Symbol* tsym;
+
+ tsym = target->tls_get_addr_sym_;
+ gold_assert(tsym);
+ value = (target->plt_section()->address() +
+ tsym->plt_offset());
+ symval.set_output_value(value);
+ Reloc::wdisp30(view, object, &symval, addend, address);
+ }
+ break;
+ }
+ break;
+ }
+ }
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unsupported reloc %u"),
+ r_type);
+ break;
+
+ case elfcpp::R_SPARC_TLS_LDM_HI22:
+ case elfcpp::R_SPARC_TLS_LDM_LO10:
+ case elfcpp::R_SPARC_TLS_LDM_ADD:
+ case elfcpp::R_SPARC_TLS_LDM_CALL:
+ if (optimized_type == tls::TLSOPT_TO_LE)
+ {
+ Insntype* wv = reinterpret_cast<Insntype*>(view);
+
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_TLS_LDM_HI22:
+ case elfcpp::R_SPARC_TLS_LDM_LO10:
+ case elfcpp::R_SPARC_TLS_LDM_ADD:
+ elfcpp::Swap<32, true>::writeval(wv, sparc_nop);
+ break;
+
+ case elfcpp::R_SPARC_TLS_LDM_CALL:
+ elfcpp::Swap<32, true>::writeval(wv, sparc_mov_g0_o0);
+ break;
+ }
+ 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);
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_TLS_LDM_HI22:
+ Reloc::hi22(view, got_offset, addend);
+ break;
+ case elfcpp::R_SPARC_TLS_LDM_LO10:
+ Reloc::lo10(view, got_offset, addend);
+ break;
+ case elfcpp::R_SPARC_TLS_LDM_ADD:
+ break;
+ case elfcpp::R_SPARC_TLS_LDM_CALL:
+ {
+ Symbol_value<size> symval;
+ elfcpp::Elf_Xword value;
+ Symbol* tsym;
+
+ tsym = target->tls_get_addr_sym_;
+ gold_assert(tsym);
+ value = (target->plt_section()->address() +
+ tsym->plt_offset());
+ symval.set_output_value(value);
+ Reloc::wdisp30(view, object, &symval, addend, address);
+ }
+ break;
+ }
+ break;
+ }
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unsupported reloc %u"),
+ r_type);
+ break;
+
+ // These relocs can appear in debugging sections, in which case
+ // we won't see the TLS_LDM relocs. The local_dynamic_type
+ // field tells us this.
+ case elfcpp::R_SPARC_TLS_LDO_HIX22:
+ if (optimized_type == tls::TLSOPT_TO_LE)
+ {
+ value -= tls_segment->memsz();
+ Reloc::hix22(view, value, addend);
+ }
+ else
+ Reloc::ldo_hix22(view, value, addend);
+ break;
+ case elfcpp::R_SPARC_TLS_LDO_LOX10:
+ if (optimized_type == tls::TLSOPT_TO_LE)
+ {
+ value -= tls_segment->memsz();
+ Reloc::lox10(view, value, addend);
+ }
+ else
+ Reloc::ldo_lox10(view, value, addend);
+ break;
+ case elfcpp::R_SPARC_TLS_LDO_ADD:
+ if (optimized_type == tls::TLSOPT_TO_LE)
+ {
+ Insntype* wv = reinterpret_cast<Insntype*>(view);
+ Insntype val;
+
+ // add %reg1, %reg2, %reg3 --> add %g7, %reg2, %reg3
+ val = elfcpp::Swap<32, true>::readval(wv);
+ val = (val & ~0x7c000) | 0x1c000;
+ elfcpp::Swap<32, true>::writeval(wv, val);
+ }
+ break;
+
+ // When optimizing IE --> LE, the only relocation that is handled
+ // differently is R_SPARC_TLS_IE_LD, it is rewritten from
+ // 'ld{,x} [rs1 + rs2], rd' into 'mov rs2, rd' or simply a NOP is
+ // rs2 and rd are the same.
+ case elfcpp::R_SPARC_TLS_IE_LD:
+ case elfcpp::R_SPARC_TLS_IE_LDX:
+ if (optimized_type == tls::TLSOPT_TO_LE)
+ {
+ Insntype* wv = reinterpret_cast<Insntype*>(view);
+ Insntype val = elfcpp::Swap<32, true>::readval(wv);
+ Insntype rs2 = val & 0x1f;
+ Insntype rd = (val >> 25) & 0x1f;
+
+ if (rs2 == rd)
+ val = sparc_nop;
+ else
+ val = sparc_mov | (val & 0x3e00001f);
+
+ elfcpp::Swap<32, true>::writeval(wv, val);
+ }
+ break;
+
+ case elfcpp::R_SPARC_TLS_IE_HI22:
+ case elfcpp::R_SPARC_TLS_IE_LO10:
+ if (optimized_type == tls::TLSOPT_TO_LE)
+ {
+ value -= tls_segment->memsz();
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_TLS_IE_HI22:
+ // IE_HI22 --> LE_HIX22
+ Reloc::hix22(view, value, addend);
+ break;
+ case elfcpp::R_SPARC_TLS_IE_LO10:
+ // IE_LO10 --> LE_LOX10
+ Reloc::lox10(view, value, addend);
+ break;
+ }
+ break;
+ }
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Relocate the field with the offset of the GOT entry for
+ // the tp-relative offset of the symbol.
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
+ value = gsym->got_offset(GOT_TYPE_TLS_OFFSET);
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym,
+ GOT_TYPE_TLS_OFFSET));
+ value = object->local_got_offset(r_sym,
+ GOT_TYPE_TLS_OFFSET);
+ }
+ switch (r_type)
+ {
+ case elfcpp::R_SPARC_TLS_IE_HI22:
+ Reloc::hi22(view, value, addend);
+ break;
+ case elfcpp::R_SPARC_TLS_IE_LO10:
+ Reloc::lo10(view, value, addend);
+ break;
+ }
+ break;
+ }
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unsupported reloc %u"),
+ r_type);
+ break;
+
+ case elfcpp::R_SPARC_TLS_IE_ADD:
+ // This seems to be mainly so that we can find the addition
+ // instruction if there is one. There doesn't seem to be any
+ // actual relocation to apply.
+ break;
+
+ case elfcpp::R_SPARC_TLS_LE_HIX22:
+ // 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())
+ {
+ value -= tls_segment->memsz();
+ Reloc::hix22(view, value, addend);
+ }
+ break;
+
+ case elfcpp::R_SPARC_TLS_LE_LOX10:
+ // 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())
+ {
+ value -= tls_segment->memsz();
+ Reloc::lox10(view, value, addend);
+ }
+ break;
+ }
+}
+
+// Relax a call instruction.
+
+template<int size, bool big_endian>
+inline void
+Target_sparc<size, big_endian>::Relocate::relax_call(
+ Target_sparc<size, big_endian>* target,
+ unsigned char* view,
+ const elfcpp::Rela<size, big_endian>& rela,
+ section_size_type view_size)
+{
+ typedef typename elfcpp::Swap<32, true>::Valtype Insntype;
+ Insntype *wv = reinterpret_cast<Insntype*>(view);
+ Insntype call_insn, delay_insn, set_insn;
+ uint32_t op3, reg, off;
+
+ // This code tries to relax call instructions that meet
+ // certain criteria.
+ //
+ // The first criteria is that the call must be such that the return
+ // address which the call writes into %o7 is unused. Two sequences
+ // meet this criteria, and are used to implement tail calls.
+ //
+ // Leaf function tail call:
+ //
+ // or %o7, %g0, %ANY_REG
+ // call FUNC
+ // or %ANY_REG, %g0, %o7
+ //
+ // Non-leaf function tail call:
+ //
+ // call FUNC
+ // restore
+ //
+ // The second criteria is that the call destination is close. If
+ // the displacement can fit in a signed 22-bit immediate field of a
+ // pre-V9 branch, we can do it. If we are generating a 64-bit
+ // object or a 32-bit object with ELF machine type EF_SPARC32PLUS,
+ // and the displacement fits in a signed 19-bit immediate field,
+ // then we can use a V9 branch.
+
+ // Make sure the delay instruction can be safely accessed.
+ if (rela.get_r_offset() + 8 > view_size)
+ return;
+
+ call_insn = elfcpp::Swap<32, true>::readval(wv);
+ delay_insn = elfcpp::Swap<32, true>::readval(wv + 1);
+
+ // Make sure it is really a call instruction.
+ if (((call_insn >> 30) & 0x3) != 1)
+ return;
+
+ if (((delay_insn >> 30) & 0x3) != 2)
+ return;
+
+ // Accept only a restore or an integer arithmetic operation whose
+ // sole side effect is to write the %o7 register (and perhaps set
+ // the condition codes, which are considered clobbered across
+ // function calls).
+ //
+ // For example, we don't want to match a tagged addition or
+ // subtraction. We also don't want to match something like a
+ // divide.
+ //
+ // Specifically we accept add{,cc}, and{,cc}, or{,cc},
+ // xor{,cc}, sub{,cc}, andn{,cc}, orn{,cc}, and xnor{,cc}.
+
+ op3 = (delay_insn >> 19) & 0x3f;
+ reg = (delay_insn >> 25) & 0x1f;
+ if (op3 != 0x3d
+ && ((op3 & 0x28) != 0 || reg != 15))
+ return;
+
+ // For non-restore instructions, make sure %o7 isn't
+ // an input.
+ if (op3 != 0x3d)
+ {
+ // First check RS1
+ reg = (delay_insn >> 14) & 0x15;
+ if (reg == 15)
+ return;
+
+ // And if non-immediate, check RS2
+ if (((delay_insn >> 13) & 1) == 0)
+ {
+ reg = (delay_insn & 0x1f);
+ if (reg == 15)
+ return;
+ }
+ }
+
+ // Now check the branch distance. We are called after the
+ // call has been relocated, so we just have to peek at the
+ // offset contained in the instruction.
+ off = call_insn & 0x3fffffff;
+ if ((off & 0x3fe00000) != 0
+ && (off & 0x3fe00000) != 0x3fe00000)
+ return;
+
+ if ((size == 64 || target->elf_machine_ == elfcpp::EM_SPARC32PLUS)
+ && ((off & 0x3c0000) == 0
+ || (off & 0x3c0000) == 0x3c0000))
+ {
+ // ba,pt %xcc, FUNC
+ call_insn = 0x10680000 | (off & 0x07ffff);
+ }
+ else
+ {
+ // ba FUNC
+ call_insn = 0x10800000 | (off & 0x3fffff);
+ }
+ elfcpp::Swap<32, true>::writeval(wv, call_insn);
+
+ // See if we can NOP out the delay slot instruction. We peek
+ // at the instruction before the call to make sure we're dealing
+ // with exactly the:
+ //
+ // or %o7, %g0, %ANY_REG
+ // call
+ // or %ANY_REG, %g0, %o7
+ //
+ // case. Otherwise this might be a tricky piece of hand written
+ // assembler calculating %o7 in some non-trivial way, and therefore
+ // we can't be sure that NOP'ing out the delay slot is safe.
+ if (op3 == 0x02
+ && rela.get_r_offset() >= 4)
+ {
+ if ((delay_insn & ~(0x1f << 14)) != 0x9e100000)
+ return;
+
+ set_insn = elfcpp::Swap<32, true>::readval(wv - 1);
+ if ((set_insn & ~(0x1f << 25)) != 0x8013c000)
+ return;
+
+ reg = (set_insn >> 25) & 0x1f;
+ if (reg == 0 || reg == 15)
+ return;
+ if (reg != ((delay_insn >> 14) & 0x1f))
+ return;
+
+ // All tests pass, nop it out.
+ elfcpp::Swap<32, true>::writeval(wv + 1, sparc_nop);
+ }
+}
+
+// Relocate section data.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::relocate_section(
+ const Relocate_info<size, 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,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size,
+ const Reloc_symbol_changes* reloc_symbol_changes)
+{
+ typedef Target_sparc<size, big_endian> Sparc;
+ typedef typename Target_sparc<size, big_endian>::Relocate Sparc_relocate;
+
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+
+ gold::relocate_section<size, big_endian, Sparc, elfcpp::SHT_RELA,
+ Sparc_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<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
+ unsigned int,
+ Relobj*)
+{
+ // We are always SHT_RELA, so we should never get here.
+ gold_unreachable();
+ return 0;
+}
+
+// Scan the relocs during a relocatable link.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::scan_relocatable_relocs(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols,
+ Relocatable_relocs* rr)
+{
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+
+ typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
+ Relocatable_size_for_reloc> Scan_relocatable_relocs;
+
+ gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
+ 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<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::relocate_relocs(
+ const Relocate_info<size, big_endian>* relinfo,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
+ const Relocatable_relocs* rr,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::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_RELA);
+
+ gold::relocate_relocs<size, big_endian, elfcpp::SHT_RELA>(
+ 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.
+
+template<int size, bool big_endian>
+uint64_t
+Target_sparc<size, big_endian>::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();
+}
+
+// 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<size, big_endian> to process SPARC specific bits
+// of the ELF headers. Hence we need to have our own ELF object creation.
+
+template<int size, bool big_endian>
+Object*
+Target_sparc<size, big_endian>::do_make_elf_object(
+ const std::string& name,
+ Input_file* input_file,
+ off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
+{
+ elfcpp::Elf_Half machine = ehdr.get_e_machine();
+ elfcpp::Elf_Word flags = ehdr.get_e_flags();
+ elfcpp::Elf_Word omm, mm;
+
+ switch (machine)
+ {
+ case elfcpp::EM_SPARC32PLUS:
+ this->elf_machine_ = elfcpp::EM_SPARC32PLUS;
+ break;
+
+ case elfcpp::EM_SPARC:
+ case elfcpp::EM_SPARCV9:
+ break;
+
+ default:
+ break;
+ }
+
+ if (!this->elf_flags_set_)
+ {
+ this->elf_flags_ = flags;
+ this->elf_flags_set_ = true;
+ }
+ else
+ {
+ // Accumulate cpu feature bits.
+ this->elf_flags_ |= (flags & (elfcpp::EF_SPARC_32PLUS
+ | elfcpp::EF_SPARC_SUN_US1
+ | elfcpp::EF_SPARC_HAL_R1
+ | elfcpp::EF_SPARC_SUN_US3));
+
+ // Bump the memory model setting to the most restrictive
+ // one we encounter.
+ omm = (this->elf_flags_ & elfcpp::EF_SPARCV9_MM);
+ mm = (flags & elfcpp::EF_SPARCV9_MM);
+ if (omm != mm)
+ {
+ if (mm == elfcpp::EF_SPARCV9_TSO)
+ {
+ this->elf_flags_ &= ~elfcpp::EF_SPARCV9_MM;
+ this->elf_flags_ |= elfcpp::EF_SPARCV9_TSO;
+ }
+ else if (mm == elfcpp::EF_SPARCV9_PSO
+ && omm == elfcpp::EF_SPARCV9_RMO)
+ {
+ this->elf_flags_ &= ~elfcpp::EF_SPARCV9_MM;
+ this->elf_flags_ |= elfcpp::EF_SPARCV9_PSO;
+ }
+ }
+ }
+
+ // Validate that the little-endian flag matches how we've
+ // been instantiated.
+ if (!(flags & elfcpp::EF_SPARC_LEDATA) != big_endian)
+ {
+ if (big_endian)
+ gold_error(_("%s: little endian elf flag set on BE object"),
+ name.c_str());
+ else
+ gold_error(_("%s: little endian elf flag clear on LE object"),
+ name.c_str());
+ }
+
+ return Target::do_make_elf_object(name, input_file, offset, ehdr);
+}
+
+// Adjust ELF file header.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::do_adjust_elf_header(
+ unsigned char* view,
+ int len)
+{
+ elfcpp::Ehdr_write<size, big_endian> oehdr(view);
+
+ oehdr.put_e_machine(this->elf_machine_);
+ oehdr.put_e_flags(this->elf_flags_);
+
+ Sized_target<size, big_endian>::do_adjust_elf_header(view, len);
+}
+
+// The selector for sparc object files.
+
+template<int size, bool big_endian>
+class Target_selector_sparc : public Target_selector
+{
+public:
+ Target_selector_sparc()
+ : Target_selector(elfcpp::EM_NONE, size, big_endian,
+ (size == 64 ? "elf64-sparc" : "elf32-sparc"),
+ (size == 64 ? "elf64_sparc" : "elf32_sparc"))
+ { }
+
+ virtual Target*
+ do_recognize(Input_file*, off_t, int machine, int, int)
+ {
+ switch (size)
+ {
+ case 64:
+ if (machine != elfcpp::EM_SPARCV9)
+ return NULL;
+ break;
+
+ case 32:
+ if (machine != elfcpp::EM_SPARC
+ && machine != elfcpp::EM_SPARC32PLUS)
+ return NULL;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ return this->instantiate_target();
+ }
+
+ virtual Target*
+ do_instantiate_target()
+ { return new Target_sparc<size, big_endian>(); }
+};
+
+Target_selector_sparc<32, true> target_selector_sparc32;
+Target_selector_sparc<64, true> target_selector_sparc64;
+
+} // End anonymous namespace.
diff --git a/binutils-2.25/gold/stringpool.cc b/binutils-2.25/gold/stringpool.cc
new file mode 100644
index 00000000..665fcc8c
--- /dev/null
+++ b/binutils-2.25/gold/stringpool.cc
@@ -0,0 +1,529 @@
+// stringpool.cc -- a string pool for gold
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cstring>
+#include <algorithm>
+#include <vector>
+
+#include "output.h"
+#include "parameters.h"
+#include "stringpool.h"
+
+namespace gold
+{
+
+template<typename Stringpool_char>
+Stringpool_template<Stringpool_char>::Stringpool_template(uint64_t addralign)
+ : string_set_(), key_to_offset_(), strings_(), strtab_size_(0),
+ zero_null_(true), optimize_(false), offset_(sizeof(Stringpool_char)),
+ addralign_(addralign)
+{
+ if (parameters->options_valid() && parameters->options().optimize() >= 2)
+ this->optimize_ = true;
+}
+
+template<typename Stringpool_char>
+void
+Stringpool_template<Stringpool_char>::clear()
+{
+ for (typename std::list<Stringdata*>::iterator p = this->strings_.begin();
+ p != this->strings_.end();
+ ++p)
+ delete[] reinterpret_cast<char*>(*p);
+ this->strings_.clear();
+ this->key_to_offset_.clear();
+ this->string_set_.clear();
+}
+
+template<typename Stringpool_char>
+Stringpool_template<Stringpool_char>::~Stringpool_template()
+{
+ this->clear();
+}
+
+// Resize the internal hashtable with the expectation we'll get n new
+// elements. Note that the hashtable constructor takes a "number of
+// buckets you'd like," rather than "number of elements you'd like,"
+// but that's the best we can do.
+
+template<typename Stringpool_char>
+void
+Stringpool_template<Stringpool_char>::reserve(unsigned int n)
+{
+ this->key_to_offset_.reserve(n);
+
+#if defined(HAVE_TR1_UNORDERED_MAP)
+ // rehash() implementation is broken in gcc 4.0.3's stl
+ //this->string_set_.rehash(this->string_set_.size() + n);
+ //return;
+#elif defined(HAVE_EXT_HASH_MAP)
+ this->string_set_.resize(this->string_set_.size() + n);
+ return;
+#endif
+
+ // This is the generic "reserve" code, if no #ifdef above triggers.
+ String_set_type new_string_set(this->string_set_.size() + n);
+ new_string_set.insert(this->string_set_.begin(), this->string_set_.end());
+ this->string_set_.swap(new_string_set);
+}
+
+// Compare two strings of arbitrary character type for equality.
+
+template<typename Stringpool_char>
+bool
+Stringpool_template<Stringpool_char>::string_equal(const Stringpool_char* s1,
+ const Stringpool_char* s2)
+{
+ while (*s1 != 0)
+ if (*s1++ != *s2++)
+ return false;
+ return *s2 == 0;
+}
+
+// Specialize string_equal for char.
+
+template<>
+inline bool
+Stringpool_template<char>::string_equal(const char* s1, const char* s2)
+{
+ return strcmp(s1, s2) == 0;
+}
+
+// Equality comparison function for the hash table.
+
+template<typename Stringpool_char>
+inline bool
+Stringpool_template<Stringpool_char>::Stringpool_eq::operator()(
+ const Hashkey& h1,
+ const Hashkey& h2) const
+{
+ return (h1.hash_code == h2.hash_code
+ && h1.length == h2.length
+ && (h1.string == h2.string
+ || memcmp(h1.string, h2.string,
+ h1.length * sizeof(Stringpool_char)) == 0));
+}
+
+// Hash function. The length is in characters, not bytes.
+
+template<typename Stringpool_char>
+size_t
+Stringpool_template<Stringpool_char>::string_hash(const Stringpool_char* s,
+ size_t length)
+{
+ return gold::string_hash<Stringpool_char>(s, length);
+}
+
+// Add the string S to the list of canonical strings. Return a
+// pointer to the canonical string. If PKEY is not NULL, set *PKEY to
+// the key. LENGTH is the length of S in characters. Note that S may
+// not be NUL terminated.
+
+template<typename Stringpool_char>
+const Stringpool_char*
+Stringpool_template<Stringpool_char>::add_string(const Stringpool_char* s,
+ size_t len)
+{
+ // We are in trouble if we've already computed the string offsets.
+ gold_assert(this->strtab_size_ == 0);
+
+ // The size we allocate for a new Stringdata.
+ const size_t buffer_size = 1000;
+ // The amount we multiply the Stringdata index when calculating the
+ // key.
+ const size_t key_mult = 1024;
+ gold_assert(key_mult >= buffer_size);
+
+ // Convert len to the number of bytes we need to allocate, including
+ // the null character.
+ len = (len + 1) * sizeof(Stringpool_char);
+
+ size_t alc;
+ bool front = true;
+ if (len > buffer_size)
+ {
+ alc = sizeof(Stringdata) + len;
+ front = false;
+ }
+ else if (this->strings_.empty())
+ alc = sizeof(Stringdata) + buffer_size;
+ else
+ {
+ Stringdata* psd = this->strings_.front();
+ if (len > psd->alc - psd->len)
+ alc = sizeof(Stringdata) + buffer_size;
+ else
+ {
+ char* ret = psd->data + psd->len;
+ memcpy(ret, s, len - sizeof(Stringpool_char));
+ memset(ret + len - sizeof(Stringpool_char), 0,
+ sizeof(Stringpool_char));
+
+ psd->len += len;
+
+ return reinterpret_cast<const Stringpool_char*>(ret);
+ }
+ }
+
+ Stringdata* psd = reinterpret_cast<Stringdata*>(new char[alc]);
+ psd->alc = alc - sizeof(Stringdata);
+ memcpy(psd->data, s, len - sizeof(Stringpool_char));
+ memset(psd->data + len - sizeof(Stringpool_char), 0,
+ sizeof(Stringpool_char));
+ psd->len = len;
+
+ if (front)
+ this->strings_.push_front(psd);
+ else
+ this->strings_.push_back(psd);
+
+ return reinterpret_cast<const Stringpool_char*>(psd->data);
+}
+
+// Add a string to a string pool.
+
+template<typename Stringpool_char>
+const Stringpool_char*
+Stringpool_template<Stringpool_char>::add(const Stringpool_char* s, bool copy,
+ Key* pkey)
+{
+ return this->add_with_length(s, string_length(s), copy, pkey);
+}
+
+// Add a new key offset entry.
+
+template<typename Stringpool_char>
+void
+Stringpool_template<Stringpool_char>::new_key_offset(size_t length)
+{
+ section_offset_type offset;
+ if (this->zero_null_ && length == 0)
+ offset = 0;
+ else
+ {
+ offset = this->offset_;
+ // Align non-zero length strings.
+ if (length != 0)
+ offset = align_address(offset, this->addralign_);
+ this->offset_ = offset + (length + 1) * sizeof(Stringpool_char);
+ }
+ this->key_to_offset_.push_back(offset);
+}
+
+template<typename Stringpool_char>
+const Stringpool_char*
+Stringpool_template<Stringpool_char>::add_with_length(const Stringpool_char* s,
+ size_t length,
+ bool copy,
+ Key* pkey)
+{
+ typedef std::pair<typename String_set_type::iterator, bool> Insert_type;
+
+ // We add 1 so that 0 is always invalid.
+ const Key k = this->key_to_offset_.size() + 1;
+
+ if (!copy)
+ {
+ // When we don't need to copy the string, we can call insert
+ // directly.
+
+ std::pair<Hashkey, Hashval> element(Hashkey(s, length), k);
+
+ Insert_type ins = this->string_set_.insert(element);
+
+ typename String_set_type::const_iterator p = ins.first;
+
+ if (ins.second)
+ {
+ // We just added the string. The key value has now been
+ // used.
+ this->new_key_offset(length);
+ }
+ else
+ {
+ gold_assert(k != p->second);
+ }
+
+ if (pkey != NULL)
+ *pkey = p->second;
+ return p->first.string;
+ }
+
+ // When we have to copy the string, we look it up twice in the hash
+ // table. The problem is that we can't insert S before we
+ // canonicalize it by copying it into the canonical list. The hash
+ // code will only be computed once.
+
+ Hashkey hk(s, length);
+ typename String_set_type::const_iterator p = this->string_set_.find(hk);
+ if (p != this->string_set_.end())
+ {
+ if (pkey != NULL)
+ *pkey = p->second;
+ return p->first.string;
+ }
+
+ this->new_key_offset(length);
+
+ hk.string = this->add_string(s, length);
+ // The contents of the string stay the same, so we don't need to
+ // adjust hk.hash_code or hk.length.
+
+ std::pair<Hashkey, Hashval> element(hk, k);
+
+ Insert_type ins = this->string_set_.insert(element);
+ gold_assert(ins.second);
+
+ if (pkey != NULL)
+ *pkey = k;
+ return hk.string;
+}
+
+template<typename Stringpool_char>
+const Stringpool_char*
+Stringpool_template<Stringpool_char>::find(const Stringpool_char* s,
+ Key* pkey) const
+{
+ Hashkey hk(s);
+ typename String_set_type::const_iterator p = this->string_set_.find(hk);
+ if (p == this->string_set_.end())
+ return NULL;
+
+ if (pkey != NULL)
+ *pkey = p->second;
+
+ return p->first.string;
+}
+
+// Comparison routine used when sorting into an ELF strtab. We want
+// to sort this so that when one string is a suffix of another, we
+// always see the shorter string immediately after the longer string.
+// For example, we want to see these strings in this order:
+// abcd
+// cd
+// d
+// When strings are not suffixes, we don't care what order they are
+// in, but we need to ensure that suffixes wind up next to each other.
+// So we do a reversed lexicographic sort on the reversed string.
+
+template<typename Stringpool_char>
+bool
+Stringpool_template<Stringpool_char>::Stringpool_sort_comparison::operator()(
+ const Stringpool_sort_info& sort_info1,
+ const Stringpool_sort_info& sort_info2) const
+{
+ const Hashkey& h1(sort_info1->first);
+ const Hashkey& h2(sort_info2->first);
+ const Stringpool_char* s1 = h1.string;
+ const Stringpool_char* s2 = h2.string;
+ const size_t len1 = h1.length;
+ const size_t len2 = h2.length;
+ const size_t minlen = len1 < len2 ? len1 : len2;
+ const Stringpool_char* p1 = s1 + len1 - 1;
+ const Stringpool_char* p2 = s2 + len2 - 1;
+ for (size_t i = minlen; i > 0; --i, --p1, --p2)
+ {
+ if (*p1 != *p2)
+ return *p1 > *p2;
+ }
+ return len1 > len2;
+}
+
+// Return whether s1 is a suffix of s2.
+
+template<typename Stringpool_char>
+bool
+Stringpool_template<Stringpool_char>::is_suffix(const Stringpool_char* s1,
+ size_t len1,
+ const Stringpool_char* s2,
+ size_t len2)
+{
+ if (len1 > len2)
+ return false;
+ return memcmp(s1, s2 + len2 - len1, len1 * sizeof(Stringpool_char)) == 0;
+}
+
+// Turn the stringpool into an ELF strtab: determine the offsets of
+// each string in the table.
+
+template<typename Stringpool_char>
+void
+Stringpool_template<Stringpool_char>::set_string_offsets()
+{
+ if (this->strtab_size_ != 0)
+ {
+ // We've already computed the offsets.
+ return;
+ }
+
+ const size_t charsize = sizeof(Stringpool_char);
+
+ // Offset 0 may be reserved for the empty string.
+ section_offset_type offset = this->zero_null_ ? charsize : 0;
+
+ // Sorting to find suffixes can take over 25% of the total CPU time
+ // used by the linker. Since it's merely an optimization to reduce
+ // the strtab size, and gives a relatively small benefit (it's
+ // typically rare for a symbol to be a suffix of another), we only
+ // take the time to sort when the user asks for heavy optimization.
+ if (!this->optimize_)
+ {
+ // If we are not optimizing, the offsets are already assigned.
+ offset = this->offset_;
+ }
+ else
+ {
+ size_t count = this->string_set_.size();
+
+ std::vector<Stringpool_sort_info> v;
+ v.reserve(count);
+
+ for (typename String_set_type::iterator p = this->string_set_.begin();
+ p != this->string_set_.end();
+ ++p)
+ v.push_back(Stringpool_sort_info(p));
+
+ std::sort(v.begin(), v.end(), Stringpool_sort_comparison());
+
+ section_offset_type last_offset = -1;
+ for (typename std::vector<Stringpool_sort_info>::iterator last = v.end(),
+ curr = v.begin();
+ curr != v.end();
+ last = curr++)
+ {
+ section_offset_type this_offset;
+ if (this->zero_null_ && (*curr)->first.string[0] == 0)
+ this_offset = 0;
+ else if (last != v.end()
+ && is_suffix((*curr)->first.string,
+ (*curr)->first.length,
+ (*last)->first.string,
+ (*last)->first.length))
+ this_offset = (last_offset
+ + (((*last)->first.length - (*curr)->first.length)
+ * charsize));
+ else
+ {
+ this_offset = align_address(offset, this->addralign_);
+ offset = this_offset + ((*curr)->first.length + 1) * charsize;
+ }
+ this->key_to_offset_[(*curr)->second - 1] = this_offset;
+ last_offset = this_offset;
+ }
+ }
+
+ this->strtab_size_ = offset;
+}
+
+// Get the offset of a string in the ELF strtab. The string must
+// exist.
+
+template<typename Stringpool_char>
+section_offset_type
+Stringpool_template<Stringpool_char>::get_offset(const Stringpool_char* s)
+ const
+{
+ return this->get_offset_with_length(s, string_length(s));
+}
+
+template<typename Stringpool_char>
+section_offset_type
+Stringpool_template<Stringpool_char>::get_offset_with_length(
+ const Stringpool_char* s,
+ size_t length) const
+{
+ gold_assert(this->strtab_size_ != 0);
+ Hashkey hk(s, length);
+ typename String_set_type::const_iterator p = this->string_set_.find(hk);
+ if (p != this->string_set_.end())
+ return this->key_to_offset_[p->second - 1];
+ gold_unreachable();
+}
+
+// Write the ELF strtab into the buffer.
+
+template<typename Stringpool_char>
+void
+Stringpool_template<Stringpool_char>::write_to_buffer(
+ unsigned char* buffer,
+ section_size_type bufsize)
+{
+ gold_assert(this->strtab_size_ != 0);
+ gold_assert(bufsize >= this->strtab_size_);
+ if (this->zero_null_)
+ buffer[0] = '\0';
+ for (typename String_set_type::const_iterator p = this->string_set_.begin();
+ p != this->string_set_.end();
+ ++p)
+ {
+ const int len = (p->first.length + 1) * sizeof(Stringpool_char);
+ const section_offset_type offset = this->key_to_offset_[p->second - 1];
+ gold_assert(static_cast<section_size_type>(offset) + len
+ <= this->strtab_size_);
+ memcpy(buffer + offset, p->first.string, len);
+ }
+}
+
+// Write the ELF strtab into the output file at the specified offset.
+
+template<typename Stringpool_char>
+void
+Stringpool_template<Stringpool_char>::write(Output_file* of, off_t offset)
+{
+ gold_assert(this->strtab_size_ != 0);
+ unsigned char* view = of->get_output_view(offset, this->strtab_size_);
+ this->write_to_buffer(view, this->strtab_size_);
+ of->write_output_view(offset, this->strtab_size_, view);
+}
+
+// Print statistical information to stderr. This is used for --stats.
+
+template<typename Stringpool_char>
+void
+Stringpool_template<Stringpool_char>::print_stats(const char* name) const
+{
+#if defined(HAVE_TR1_UNORDERED_MAP) || defined(HAVE_EXT_HASH_MAP)
+ fprintf(stderr, _("%s: %s entries: %zu; buckets: %zu\n"),
+ program_name, name, this->string_set_.size(),
+ this->string_set_.bucket_count());
+#else
+ fprintf(stderr, _("%s: %s entries: %zu\n"),
+ program_name, name, this->table_.size());
+#endif
+ fprintf(stderr, _("%s: %s Stringdata structures: %zu\n"),
+ program_name, name, this->strings_.size());
+}
+
+// Instantiate the templates we need.
+
+template
+class Stringpool_template<char>;
+
+template
+class Stringpool_template<uint16_t>;
+
+template
+class Stringpool_template<uint32_t>;
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/stringpool.h b/binutils-2.25/gold/stringpool.h
new file mode 100644
index 00000000..b6383296
--- /dev/null
+++ b/binutils-2.25/gold/stringpool.h
@@ -0,0 +1,421 @@
+// stringpool.h -- a string pool for gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <string>
+#include <list>
+#include <vector>
+
+#ifndef GOLD_STRINGPOOL_H
+#define GOLD_STRINGPOOL_H
+
+namespace gold
+{
+
+class Output_file;
+
+// Return the length of a string in units of Char_type.
+
+template<typename Char_type>
+inline size_t
+string_length(const Char_type* p)
+{
+ size_t len = 0;
+ for (; *p != 0; ++p)
+ ++len;
+ return len;
+}
+
+// Specialize string_length for char. Maybe we could just use
+// std::char_traits<>::length?
+
+template<>
+inline size_t
+string_length(const char* p)
+{
+ return strlen(p);
+}
+
+// A Stringpool is a pool of unique strings. It provides the
+// following features:
+
+// Every string in the pool is unique. Thus, if you have two strings
+// in the Stringpool, you can compare them for equality by using
+// pointer comparison rather than string comparison.
+
+// There is a key associated with every string in the pool. If you
+// add strings to the Stringpool in the same order, then the key for
+// each string will always be the same for any run of the linker.
+// This is not true of the string pointers themselves, as they may
+// change due to address space randomization. Some parts of the
+// linker (e.g., the symbol table) use the key value instead of the
+// string pointer so that repeated runs of the linker will generate
+// precisely the same output.
+
+// When you add a string to a Stringpool, Stringpool will optionally
+// make a copy of it. Thus there is no requirement to keep a copy
+// elsewhere.
+
+// A Stringpool can be turned into a string table, a sequential series
+// of null terminated strings. The first string may optionally be a
+// single zero byte, as required for SHT_STRTAB sections. This
+// conversion is only permitted after all strings have been added to
+// the Stringpool. After doing this conversion, you can ask for the
+// offset of any string (or any key) in the stringpool in the string
+// table, and you can write the resulting string table to an output
+// file.
+
+// When a Stringpool is turned into a string table, then as an
+// optimization it will reuse string suffixes to avoid duplicating
+// strings. That is, given the strings "abc" and "bc", only the
+// string "abc" will be stored, and "bc" will be represented by an
+// offset into the middle of the string "abc".
+
+
+// A simple chunked vector class--this is a subset of std::vector
+// which stores memory in chunks. We don't provide iterators, because
+// we don't need them.
+
+template<typename Element>
+class Chunked_vector
+{
+ public:
+ Chunked_vector()
+ : chunks_(), size_(0)
+ { }
+
+ // Clear the elements.
+ void
+ clear()
+ {
+ this->chunks_.clear();
+ this->size_ = 0;
+ }
+
+ // Reserve elements.
+ void
+ reserve(unsigned int n)
+ {
+ if (n > this->chunks_.size() * chunk_size)
+ {
+ this->chunks_.resize((n + chunk_size - 1) / chunk_size);
+ // We need to call reserve() of all chunks since changing
+ // this->chunks_ casues Element_vectors to be copied. The
+ // reserved capacity of an Element_vector may be lost in copying.
+ for (size_t i = 0; i < this->chunks_.size(); ++i)
+ this->chunks_[i].reserve(chunk_size);
+ }
+ }
+
+ // Get the number of elements.
+ size_t
+ size() const
+ { return this->size_; }
+
+ // Push a new element on the back of the vector.
+ void
+ push_back(const Element& element)
+ {
+ size_t chunk_index = this->size_ / chunk_size;
+ if (chunk_index >= this->chunks_.size())
+ {
+ this->chunks_.push_back(Element_vector());
+ this->chunks_.back().reserve(chunk_size);
+ gold_assert(chunk_index < this->chunks_.size());
+ }
+ this->chunks_[chunk_index].push_back(element);
+ this->size_++;
+ }
+
+ // Return a reference to an entry in the vector.
+ Element&
+ operator[](size_t i)
+ { return this->chunks_[i / chunk_size][i % chunk_size]; }
+
+ const Element&
+ operator[](size_t i) const
+ { return this->chunks_[i / chunk_size][i % chunk_size]; }
+
+ private:
+ static const unsigned int chunk_size = 8192;
+
+ typedef std::vector<Element> Element_vector;
+ typedef std::vector<Element_vector> Chunk_vector;
+
+ Chunk_vector chunks_;
+ size_t size_;
+};
+
+
+// Stringpools are implemented in terms of Stringpool_template, which
+// is generalized on the type of character used for the strings. Most
+// uses will want the Stringpool type which uses char. Other cases
+// are used for merging wide string constants.
+
+template<typename Stringpool_char>
+class Stringpool_template
+{
+ public:
+ // The type of a key into the stringpool. As described above, a key
+ // value will always be the same during any run of the linker. Zero
+ // is never a valid key value.
+ typedef size_t Key;
+
+ // Create a Stringpool.
+ Stringpool_template(uint64_t addralign = 1);
+
+ ~Stringpool_template();
+
+ // Clear all the data from the stringpool.
+ void
+ clear();
+
+ // Hint to the stringpool class that you intend to insert n additional
+ // elements. The stringpool class can use this info however it likes;
+ // in practice it will resize its internal hashtables to make room.
+ void
+ reserve(unsigned int n);
+
+ // Indicate that we should not reserve offset 0 to hold the empty
+ // string when converting the stringpool to a string table. This
+ // should not be called for a proper ELF SHT_STRTAB section.
+ void
+ set_no_zero_null()
+ {
+ gold_assert(this->string_set_.empty()
+ && this->offset_ == sizeof(Stringpool_char));
+ this->zero_null_ = false;
+ this->offset_ = 0;
+ }
+
+ // Indicate that this string pool should be optimized, even if not
+ // running with -O2.
+ void
+ set_optimize()
+ { this->optimize_ = true; }
+
+ // Add the string S to the pool. This returns a canonical permanent
+ // pointer to the string in the pool. If COPY is true, the string
+ // is copied into permanent storage. If PKEY is not NULL, this sets
+ // *PKEY to the key for the string.
+ const Stringpool_char*
+ add(const Stringpool_char* s, bool copy, Key* pkey);
+
+ // Add the string S to the pool.
+ const Stringpool_char*
+ add(const std::basic_string<Stringpool_char>& s, bool copy, Key* pkey)
+ { return this->add_with_length(s.data(), s.size(), copy, pkey); }
+
+ // Add string S of length LEN characters to the pool. If COPY is
+ // true, S need not be null terminated.
+ const Stringpool_char*
+ add_with_length(const Stringpool_char* s, size_t len, bool copy, Key* pkey);
+
+ // If the string S is present in the pool, return the canonical
+ // string pointer. Otherwise, return NULL. If PKEY is not NULL,
+ // set *PKEY to the key.
+ const Stringpool_char*
+ find(const Stringpool_char* s, Key* pkey) const;
+
+ // Turn the stringpool into a string table: determine the offsets of
+ // all the strings. After this is called, no more strings may be
+ // added to the stringpool.
+ void
+ set_string_offsets();
+
+ // Get the offset of the string S in the string table. This returns
+ // the offset in bytes, not in units of Stringpool_char. This may
+ // only be called after set_string_offsets has been called.
+ section_offset_type
+ get_offset(const Stringpool_char* s) const;
+
+ // Get the offset of the string S in the string table.
+ section_offset_type
+ get_offset(const std::basic_string<Stringpool_char>& s) const
+ { return this->get_offset_with_length(s.c_str(), s.size()); }
+
+ // Get the offset of string S, with length LENGTH characters, in the
+ // string table.
+ section_offset_type
+ get_offset_with_length(const Stringpool_char* s, size_t length) const;
+
+ // Get the offset of the string with key K.
+ section_offset_type
+ get_offset_from_key(Key k) const
+ {
+ gold_assert(k <= this->key_to_offset_.size());
+ return this->key_to_offset_[k - 1];
+ }
+
+ // Get the size of the string table. This returns the number of
+ // bytes, not in units of Stringpool_char.
+ section_size_type
+ get_strtab_size() const
+ {
+ gold_assert(this->strtab_size_ != 0);
+ return this->strtab_size_;
+ }
+
+ // Write the string table into the output file at the specified
+ // offset.
+ void
+ write(Output_file*, off_t offset);
+
+ // Write the string table into the specified buffer, of the
+ // specified size. buffer_size should be at least
+ // get_strtab_size().
+ void
+ write_to_buffer(unsigned char* buffer, section_size_type buffer_size);
+
+ // Dump statistical information to stderr.
+ void
+ print_stats(const char*) const;
+
+ private:
+ Stringpool_template(const Stringpool_template&);
+ Stringpool_template& operator=(const Stringpool_template&);
+
+ // Return whether two strings are equal.
+ static bool
+ string_equal(const Stringpool_char*, const Stringpool_char*);
+
+ // Compute a hash code for a string. LENGTH is the length of the
+ // string in characters.
+ static size_t
+ string_hash(const Stringpool_char*, size_t length);
+
+ // We store the actual data in a list of these buffers.
+ struct Stringdata
+ {
+ // Length of data in buffer.
+ size_t len;
+ // Allocated size of buffer.
+ size_t alc;
+ // Buffer.
+ char data[1];
+ };
+
+ // Add a new key offset entry.
+ void
+ new_key_offset(size_t);
+
+ // Copy a string into the buffers, returning a canonical string.
+ const Stringpool_char*
+ add_string(const Stringpool_char*, size_t);
+
+ // Return whether s1 is a suffix of s2.
+ static bool
+ is_suffix(const Stringpool_char* s1, size_t len1,
+ const Stringpool_char* s2, size_t len2);
+
+ // The hash table key includes the string, the length of the string,
+ // and the hash code for the string. We put the hash code
+ // explicitly into the key so that we can do a find()/insert()
+ // sequence without having to recompute the hash. Computing the
+ // hash code is a significant user of CPU time in the linker.
+ struct Hashkey
+ {
+ const Stringpool_char* string;
+ // Length is in characters, not bytes.
+ size_t length;
+ size_t hash_code;
+
+ // This goes in an STL container, so we need a default
+ // constructor.
+ Hashkey()
+ : string(NULL), length(0), hash_code(0)
+ { }
+
+ // Note that these constructors are relatively expensive, because
+ // they compute the hash code.
+ explicit Hashkey(const Stringpool_char* s)
+ : string(s), length(string_length(s)), hash_code(string_hash(s, length))
+ { }
+
+ Hashkey(const Stringpool_char* s, size_t len)
+ : string(s), length(len), hash_code(string_hash(s, len))
+ { }
+ };
+
+ // Hash function. This is trivial, since we have already computed
+ // the hash.
+ struct Stringpool_hash
+ {
+ size_t
+ operator()(const Hashkey& hk) const
+ { return hk.hash_code; }
+ };
+
+ // Equality comparison function for hash table.
+ struct Stringpool_eq
+ {
+ bool
+ operator()(const Hashkey&, const Hashkey&) const;
+ };
+
+ // The hash table is a map from strings to Keys.
+
+ typedef Key Hashval;
+
+ typedef Unordered_map<Hashkey, Hashval, Stringpool_hash,
+ Stringpool_eq> String_set_type;
+
+ // Comparison routine used when sorting into a string table.
+
+ typedef typename String_set_type::iterator Stringpool_sort_info;
+
+ struct Stringpool_sort_comparison
+ {
+ bool
+ operator()(const Stringpool_sort_info&, const Stringpool_sort_info&) const;
+ };
+
+ // Keys map to offsets via a Chunked_vector. We only use the
+ // offsets if we turn this into an string table section.
+ typedef Chunked_vector<section_offset_type> Key_to_offset;
+
+ // List of Stringdata structures.
+ typedef std::list<Stringdata*> Stringdata_list;
+
+ // Mapping from const char* to namepool entry.
+ String_set_type string_set_;
+ // Mapping from Key to string table offset.
+ Key_to_offset key_to_offset_;
+ // List of buffers.
+ Stringdata_list strings_;
+ // Size of string table.
+ section_size_type strtab_size_;
+ // Whether to reserve offset 0 to hold the null string.
+ bool zero_null_;
+ // Whether to optimize the string table.
+ bool optimize_;
+ // offset of the next string.
+ section_offset_type offset_;
+ // The alignment of strings in the stringpool.
+ uint64_t addralign_;
+};
+
+// The most common type of Stringpool.
+typedef Stringpool_template<char> Stringpool;
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_STRINGPOOL_H)
diff --git a/binutils-2.25/gold/symtab.cc b/binutils-2.25/gold/symtab.cc
new file mode 100644
index 00000000..2e17529b
--- /dev/null
+++ b/binutils-2.25/gold/symtab.cc
@@ -0,0 +1,3657 @@
+// symtab.cc -- the gold symbol table
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cstring>
+#include <stdint.h>
+#include <algorithm>
+#include <set>
+#include <string>
+#include <utility>
+#include "demangle.h"
+
+#include "gc.h"
+#include "object.h"
+#include "dwarf_reader.h"
+#include "dynobj.h"
+#include "output.h"
+#include "target.h"
+#include "workqueue.h"
+#include "symtab.h"
+#include "script.h"
+#include "plugin.h"
+#include "incremental.h"
+
+namespace gold
+{
+
+// Class Symbol.
+
+// Initialize fields in Symbol. This initializes everything except u_
+// and source_.
+
+void
+Symbol::init_fields(const char* name, const char* version,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis)
+{
+ this->name_ = name;
+ this->version_ = version;
+ this->symtab_index_ = 0;
+ this->dynsym_index_ = 0;
+ this->got_offsets_.init();
+ this->plt_offset_ = -1U;
+ this->type_ = type;
+ this->binding_ = binding;
+ this->visibility_ = visibility;
+ this->nonvis_ = nonvis;
+ this->is_def_ = false;
+ this->is_forwarder_ = false;
+ this->has_alias_ = false;
+ this->needs_dynsym_entry_ = false;
+ this->in_reg_ = false;
+ this->in_dyn_ = false;
+ this->has_warning_ = false;
+ this->is_copied_from_dynobj_ = false;
+ this->is_forced_local_ = false;
+ this->is_ordinary_shndx_ = false;
+ this->in_real_elf_ = false;
+ this->is_defined_in_discarded_section_ = false;
+ this->undef_binding_set_ = false;
+ this->undef_binding_weak_ = false;
+ this->is_predefined_ = false;
+}
+
+// Return the demangled version of the symbol's name, but only
+// if the --demangle flag was set.
+
+static std::string
+demangle(const char* name)
+{
+ if (!parameters->options().do_demangle())
+ return name;
+
+ // cplus_demangle allocates memory for the result it returns,
+ // and returns NULL if the name is already demangled.
+ char* demangled_name = cplus_demangle(name, DMGL_ANSI | DMGL_PARAMS);
+ if (demangled_name == NULL)
+ return name;
+
+ std::string retval(demangled_name);
+ free(demangled_name);
+ return retval;
+}
+
+std::string
+Symbol::demangled_name() const
+{
+ return demangle(this->name());
+}
+
+// Initialize the fields in the base class Symbol for SYM in OBJECT.
+
+template<int size, bool big_endian>
+void
+Symbol::init_base_object(const char* name, const char* version, Object* object,
+ const elfcpp::Sym<size, big_endian>& sym,
+ unsigned int st_shndx, bool is_ordinary)
+{
+ this->init_fields(name, version, sym.get_st_type(), sym.get_st_bind(),
+ sym.get_st_visibility(), sym.get_st_nonvis());
+ this->u_.from_object.object = object;
+ this->u_.from_object.shndx = st_shndx;
+ this->is_ordinary_shndx_ = is_ordinary;
+ this->source_ = FROM_OBJECT;
+ this->in_reg_ = !object->is_dynamic();
+ this->in_dyn_ = object->is_dynamic();
+ this->in_real_elf_ = object->pluginobj() == NULL;
+}
+
+// Initialize the fields in the base class Symbol for a symbol defined
+// in an Output_data.
+
+void
+Symbol::init_base_output_data(const char* name, const char* version,
+ Output_data* od, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis, bool offset_is_from_end,
+ bool is_predefined)
+{
+ this->init_fields(name, version, type, binding, visibility, nonvis);
+ this->u_.in_output_data.output_data = od;
+ this->u_.in_output_data.offset_is_from_end = offset_is_from_end;
+ this->source_ = IN_OUTPUT_DATA;
+ this->in_reg_ = true;
+ this->in_real_elf_ = true;
+ this->is_predefined_ = is_predefined;
+}
+
+// Initialize the fields in the base class Symbol for a symbol defined
+// in an Output_segment.
+
+void
+Symbol::init_base_output_segment(const char* name, const char* version,
+ Output_segment* os, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis,
+ Segment_offset_base offset_base,
+ bool is_predefined)
+{
+ this->init_fields(name, version, type, binding, visibility, nonvis);
+ this->u_.in_output_segment.output_segment = os;
+ this->u_.in_output_segment.offset_base = offset_base;
+ this->source_ = IN_OUTPUT_SEGMENT;
+ this->in_reg_ = true;
+ this->in_real_elf_ = true;
+ this->is_predefined_ = is_predefined;
+}
+
+// Initialize the fields in the base class Symbol for a symbol defined
+// as a constant.
+
+void
+Symbol::init_base_constant(const char* name, const char* version,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ bool is_predefined)
+{
+ this->init_fields(name, version, type, binding, visibility, nonvis);
+ this->source_ = IS_CONSTANT;
+ this->in_reg_ = true;
+ this->in_real_elf_ = true;
+ this->is_predefined_ = is_predefined;
+}
+
+// Initialize the fields in the base class Symbol for an undefined
+// symbol.
+
+void
+Symbol::init_base_undefined(const char* name, const char* version,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis)
+{
+ this->init_fields(name, version, type, binding, visibility, nonvis);
+ this->dynsym_index_ = -1U;
+ this->source_ = IS_UNDEFINED;
+ this->in_reg_ = true;
+ this->in_real_elf_ = true;
+}
+
+// Allocate a common symbol in the base.
+
+void
+Symbol::allocate_base_common(Output_data* od)
+{
+ gold_assert(this->is_common());
+ this->source_ = IN_OUTPUT_DATA;
+ this->u_.in_output_data.output_data = od;
+ this->u_.in_output_data.offset_is_from_end = false;
+}
+
+// Initialize the fields in Sized_symbol for SYM in OBJECT.
+
+template<int size>
+template<bool big_endian>
+void
+Sized_symbol<size>::init_object(const char* name, const char* version,
+ Object* object,
+ const elfcpp::Sym<size, big_endian>& sym,
+ unsigned int st_shndx, bool is_ordinary)
+{
+ this->init_base_object(name, version, object, sym, st_shndx, is_ordinary);
+ this->value_ = sym.get_st_value();
+ this->symsize_ = sym.get_st_size();
+}
+
+// Initialize the fields in Sized_symbol for a symbol defined in an
+// Output_data.
+
+template<int size>
+void
+Sized_symbol<size>::init_output_data(const char* name, const char* version,
+ Output_data* od, Value_type value,
+ Size_type symsize, elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ bool offset_is_from_end,
+ bool is_predefined)
+{
+ this->init_base_output_data(name, version, od, type, binding, visibility,
+ nonvis, offset_is_from_end, is_predefined);
+ this->value_ = value;
+ this->symsize_ = symsize;
+}
+
+// Initialize the fields in Sized_symbol for a symbol defined in an
+// Output_segment.
+
+template<int size>
+void
+Sized_symbol<size>::init_output_segment(const char* name, const char* version,
+ Output_segment* os, Value_type value,
+ Size_type symsize, elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ Segment_offset_base offset_base,
+ bool is_predefined)
+{
+ this->init_base_output_segment(name, version, os, type, binding, visibility,
+ nonvis, offset_base, is_predefined);
+ this->value_ = value;
+ this->symsize_ = symsize;
+}
+
+// Initialize the fields in Sized_symbol for a symbol defined as a
+// constant.
+
+template<int size>
+void
+Sized_symbol<size>::init_constant(const char* name, const char* version,
+ Value_type value, Size_type symsize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ bool is_predefined)
+{
+ this->init_base_constant(name, version, type, binding, visibility, nonvis,
+ is_predefined);
+ this->value_ = value;
+ this->symsize_ = symsize;
+}
+
+// Initialize the fields in Sized_symbol for an undefined symbol.
+
+template<int size>
+void
+Sized_symbol<size>::init_undefined(const char* name, const char* version,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis)
+{
+ this->init_base_undefined(name, version, type, binding, visibility, nonvis);
+ this->value_ = 0;
+ this->symsize_ = 0;
+}
+
+// Return an allocated string holding the symbol's name as
+// name@version. This is used for relocatable links.
+
+std::string
+Symbol::versioned_name() const
+{
+ gold_assert(this->version_ != NULL);
+ std::string ret = this->name_;
+ ret.push_back('@');
+ if (this->is_def_)
+ ret.push_back('@');
+ ret += this->version_;
+ return ret;
+}
+
+// Return true if SHNDX represents a common symbol.
+
+bool
+Symbol::is_common_shndx(unsigned int shndx)
+{
+ return (shndx == elfcpp::SHN_COMMON
+ || shndx == parameters->target().small_common_shndx()
+ || shndx == parameters->target().large_common_shndx());
+}
+
+// Allocate a common symbol.
+
+template<int size>
+void
+Sized_symbol<size>::allocate_common(Output_data* od, Value_type value)
+{
+ this->allocate_base_common(od);
+ this->value_ = value;
+}
+
+// The ""'s around str ensure str is a string literal, so sizeof works.
+#define strprefix(var, str) (strncmp(var, str, sizeof("" str "") - 1) == 0)
+
+// Return true if this symbol should be added to the dynamic symbol
+// table.
+
+inline bool
+Symbol::should_add_dynsym_entry(Symbol_table* symtab) const
+{
+ // If the symbol is only present on plugin files, the plugin decided we
+ // don't need it.
+ if (!this->in_real_elf())
+ return false;
+
+ // If the symbol is used by a dynamic relocation, we need to add it.
+ if (this->needs_dynsym_entry())
+ return true;
+
+ // If this symbol's section is not added, the symbol need not be added.
+ // The section may have been GCed. Note that export_dynamic is being
+ // overridden here. This should not be done for shared objects.
+ if (parameters->options().gc_sections()
+ && !parameters->options().shared()
+ && this->source() == Symbol::FROM_OBJECT
+ && !this->object()->is_dynamic())
+ {
+ Relobj* relobj = static_cast<Relobj*>(this->object());
+ bool is_ordinary;
+ unsigned int shndx = this->shndx(&is_ordinary);
+ if (is_ordinary && shndx != elfcpp::SHN_UNDEF
+ && !relobj->is_section_included(shndx)
+ && !symtab->is_section_folded(relobj, shndx))
+ return false;
+ }
+
+ // If the symbol was forced dynamic in a --dynamic-list file
+ // or an --export-dynamic-symbol option, add it.
+ if (!this->is_from_dynobj()
+ && (parameters->options().in_dynamic_list(this->name())
+ || parameters->options().is_export_dynamic_symbol(this->name())))
+ {
+ if (!this->is_forced_local())
+ return true;
+ gold_warning(_("Cannot export local symbol '%s'"),
+ this->demangled_name().c_str());
+ return false;
+ }
+
+ // If the symbol was forced local in a version script, do not add it.
+ if (this->is_forced_local())
+ return false;
+
+ // If dynamic-list-data was specified, add any STT_OBJECT.
+ if (parameters->options().dynamic_list_data()
+ && !this->is_from_dynobj()
+ && this->type() == elfcpp::STT_OBJECT)
+ return true;
+
+ // If --dynamic-list-cpp-new was specified, add any new/delete symbol.
+ // If --dynamic-list-cpp-typeinfo was specified, add any typeinfo symbols.
+ if ((parameters->options().dynamic_list_cpp_new()
+ || parameters->options().dynamic_list_cpp_typeinfo())
+ && !this->is_from_dynobj())
+ {
+ // TODO(csilvers): We could probably figure out if we're an operator
+ // new/delete or typeinfo without the need to demangle.
+ char* demangled_name = cplus_demangle(this->name(),
+ DMGL_ANSI | DMGL_PARAMS);
+ if (demangled_name == NULL)
+ {
+ // Not a C++ symbol, so it can't satisfy these flags
+ }
+ else if (parameters->options().dynamic_list_cpp_new()
+ && (strprefix(demangled_name, "operator new")
+ || strprefix(demangled_name, "operator delete")))
+ {
+ free(demangled_name);
+ return true;
+ }
+ else if (parameters->options().dynamic_list_cpp_typeinfo()
+ && (strprefix(demangled_name, "typeinfo name for")
+ || strprefix(demangled_name, "typeinfo for")))
+ {
+ free(demangled_name);
+ return true;
+ }
+ else
+ free(demangled_name);
+ }
+
+ // If exporting all symbols or building a shared library,
+ // and the symbol is defined in a regular object and is
+ // externally visible, we need to add it.
+ if ((parameters->options().export_dynamic() || parameters->options().shared())
+ && !this->is_from_dynobj()
+ && !this->is_undefined()
+ && this->is_externally_visible())
+ return true;
+
+ return false;
+}
+
+// Return true if the final value of this symbol is known at link
+// time.
+
+bool
+Symbol::final_value_is_known() const
+{
+ // If we are not generating an executable, then no final values are
+ // known, since they will change at runtime.
+ if (parameters->options().output_is_position_independent()
+ || parameters->options().relocatable())
+ return false;
+
+ // If the symbol is not from an object file, and is not undefined,
+ // then it is defined, and known.
+ if (this->source_ != FROM_OBJECT)
+ {
+ if (this->source_ != IS_UNDEFINED)
+ return true;
+ }
+ else
+ {
+ // If the symbol is from a dynamic object, then the final value
+ // is not known.
+ if (this->object()->is_dynamic())
+ return false;
+
+ // If the symbol is not undefined (it is defined or common),
+ // then the final value is known.
+ if (!this->is_undefined())
+ return true;
+ }
+
+ // If the symbol is undefined, then whether the final value is known
+ // depends on whether we are doing a static link. If we are doing a
+ // dynamic link, then the final value could be filled in at runtime.
+ // This could reasonably be the case for a weak undefined symbol.
+ return parameters->doing_static_link();
+}
+
+// Return the output section where this symbol is defined.
+
+Output_section*
+Symbol::output_section() const
+{
+ switch (this->source_)
+ {
+ case FROM_OBJECT:
+ {
+ unsigned int shndx = this->u_.from_object.shndx;
+ if (shndx != elfcpp::SHN_UNDEF && this->is_ordinary_shndx_)
+ {
+ gold_assert(!this->u_.from_object.object->is_dynamic());
+ gold_assert(this->u_.from_object.object->pluginobj() == NULL);
+ Relobj* relobj = static_cast<Relobj*>(this->u_.from_object.object);
+ return relobj->output_section(shndx);
+ }
+ return NULL;
+ }
+
+ case IN_OUTPUT_DATA:
+ return this->u_.in_output_data.output_data->output_section();
+
+ case IN_OUTPUT_SEGMENT:
+ case IS_CONSTANT:
+ case IS_UNDEFINED:
+ return NULL;
+
+ default:
+ gold_unreachable();
+ }
+}
+
+// Set the symbol's output section. This is used for symbols defined
+// in scripts. This should only be called after the symbol table has
+// been finalized.
+
+void
+Symbol::set_output_section(Output_section* os)
+{
+ switch (this->source_)
+ {
+ case FROM_OBJECT:
+ case IN_OUTPUT_DATA:
+ gold_assert(this->output_section() == os);
+ break;
+ case IS_CONSTANT:
+ this->source_ = IN_OUTPUT_DATA;
+ this->u_.in_output_data.output_data = os;
+ this->u_.in_output_data.offset_is_from_end = false;
+ break;
+ case IN_OUTPUT_SEGMENT:
+ case IS_UNDEFINED:
+ default:
+ gold_unreachable();
+ }
+}
+
+// Class Symbol_table.
+
+Symbol_table::Symbol_table(unsigned int count,
+ const Version_script_info& version_script)
+ : saw_undefined_(0), offset_(0), table_(count), namepool_(),
+ forwarders_(), commons_(), tls_commons_(), small_commons_(),
+ large_commons_(), forced_locals_(), warnings_(),
+ version_script_(version_script), gc_(NULL), icf_(NULL)
+{
+ namepool_.reserve(count);
+}
+
+Symbol_table::~Symbol_table()
+{
+}
+
+// The symbol table key equality function. This is called with
+// Stringpool keys.
+
+inline bool
+Symbol_table::Symbol_table_eq::operator()(const Symbol_table_key& k1,
+ const Symbol_table_key& k2) const
+{
+ return k1.first == k2.first && k1.second == k2.second;
+}
+
+bool
+Symbol_table::is_section_folded(Object* obj, unsigned int shndx) const
+{
+ return (parameters->options().icf_enabled()
+ && this->icf_->is_section_folded(obj, shndx));
+}
+
+// For symbols that have been listed with a -u or --export-dynamic-symbol
+// option, add them to the work list to avoid gc'ing them.
+
+void
+Symbol_table::gc_mark_undef_symbols(Layout* layout)
+{
+ for (options::String_set::const_iterator p =
+ parameters->options().undefined_begin();
+ p != parameters->options().undefined_end();
+ ++p)
+ {
+ const char* name = p->c_str();
+ Symbol* sym = this->lookup(name);
+ gold_assert(sym != NULL);
+ if (sym->source() == Symbol::FROM_OBJECT
+ && !sym->object()->is_dynamic())
+ {
+ this->gc_mark_symbol(sym);
+ }
+ }
+
+ for (options::String_set::const_iterator p =
+ parameters->options().export_dynamic_symbol_begin();
+ p != parameters->options().export_dynamic_symbol_end();
+ ++p)
+ {
+ const char* name = p->c_str();
+ Symbol* sym = this->lookup(name);
+ // It's not an error if a symbol named by --export-dynamic-symbol
+ // is undefined.
+ if (sym != NULL
+ && sym->source() == Symbol::FROM_OBJECT
+ && !sym->object()->is_dynamic())
+ {
+ this->gc_mark_symbol(sym);
+ }
+ }
+
+ for (Script_options::referenced_const_iterator p =
+ layout->script_options()->referenced_begin();
+ p != layout->script_options()->referenced_end();
+ ++p)
+ {
+ Symbol* sym = this->lookup(p->c_str());
+ gold_assert(sym != NULL);
+ if (sym->source() == Symbol::FROM_OBJECT
+ && !sym->object()->is_dynamic())
+ {
+ this->gc_mark_symbol(sym);
+ }
+ }
+}
+
+void
+Symbol_table::gc_mark_symbol(Symbol* sym)
+{
+ // Add the object and section to the work list.
+ bool is_ordinary;
+ unsigned int shndx = sym->shndx(&is_ordinary);
+ if (is_ordinary && shndx != elfcpp::SHN_UNDEF)
+ {
+ gold_assert(this->gc_!= NULL);
+ this->gc_->worklist().push(Section_id(sym->object(), shndx));
+ }
+ parameters->target().gc_mark_symbol(this, sym);
+}
+
+// When doing garbage collection, keep symbols that have been seen in
+// dynamic objects.
+inline void
+Symbol_table::gc_mark_dyn_syms(Symbol* sym)
+{
+ if (sym->in_dyn() && sym->source() == Symbol::FROM_OBJECT
+ && !sym->object()->is_dynamic())
+ this->gc_mark_symbol(sym);
+}
+
+// Make TO a symbol which forwards to FROM.
+
+void
+Symbol_table::make_forwarder(Symbol* from, Symbol* to)
+{
+ gold_assert(from != to);
+ gold_assert(!from->is_forwarder() && !to->is_forwarder());
+ this->forwarders_[from] = to;
+ from->set_forwarder();
+}
+
+// Resolve the forwards from FROM, returning the real symbol.
+
+Symbol*
+Symbol_table::resolve_forwards(const Symbol* from) const
+{
+ gold_assert(from->is_forwarder());
+ Unordered_map<const Symbol*, Symbol*>::const_iterator p =
+ this->forwarders_.find(from);
+ gold_assert(p != this->forwarders_.end());
+ return p->second;
+}
+
+// Look up a symbol by name.
+
+Symbol*
+Symbol_table::lookup(const char* name, const char* version) const
+{
+ Stringpool::Key name_key;
+ name = this->namepool_.find(name, &name_key);
+ if (name == NULL)
+ return NULL;
+
+ Stringpool::Key version_key = 0;
+ if (version != NULL)
+ {
+ version = this->namepool_.find(version, &version_key);
+ if (version == NULL)
+ return NULL;
+ }
+
+ Symbol_table_key key(name_key, version_key);
+ Symbol_table::Symbol_table_type::const_iterator p = this->table_.find(key);
+ if (p == this->table_.end())
+ return NULL;
+ return p->second;
+}
+
+// Resolve a Symbol with another Symbol. This is only used in the
+// unusual case where there are references to both an unversioned
+// symbol and a symbol with a version, and we then discover that that
+// version is the default version. Because this is unusual, we do
+// this the slow way, by converting back to an ELF symbol.
+
+template<int size, bool big_endian>
+void
+Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from)
+{
+ unsigned char buf[elfcpp::Elf_sizes<size>::sym_size];
+ elfcpp::Sym_write<size, big_endian> esym(buf);
+ // We don't bother to set the st_name or the st_shndx field.
+ esym.put_st_value(from->value());
+ esym.put_st_size(from->symsize());
+ esym.put_st_info(from->binding(), from->type());
+ esym.put_st_other(from->visibility(), from->nonvis());
+ bool is_ordinary;
+ unsigned int shndx = from->shndx(&is_ordinary);
+ this->resolve(to, esym.sym(), shndx, is_ordinary, shndx, from->object(),
+ from->version());
+ if (from->in_reg())
+ to->set_in_reg();
+ if (from->in_dyn())
+ to->set_in_dyn();
+ if (parameters->options().gc_sections())
+ this->gc_mark_dyn_syms(to);
+}
+
+// Record that a symbol is forced to be local by a version script or
+// by visibility.
+
+void
+Symbol_table::force_local(Symbol* sym)
+{
+ if (!sym->is_defined() && !sym->is_common())
+ return;
+ if (sym->is_forced_local())
+ {
+ // We already got this one.
+ return;
+ }
+ sym->set_is_forced_local();
+ this->forced_locals_.push_back(sym);
+}
+
+// Adjust NAME for wrapping, and update *NAME_KEY if necessary. This
+// is only called for undefined symbols, when at least one --wrap
+// option was used.
+
+const char*
+Symbol_table::wrap_symbol(const char* name, Stringpool::Key* name_key)
+{
+ // For some targets, we need to ignore a specific character when
+ // wrapping, and add it back later.
+ char prefix = '\0';
+ if (name[0] == parameters->target().wrap_char())
+ {
+ prefix = name[0];
+ ++name;
+ }
+
+ if (parameters->options().is_wrap(name))
+ {
+ // Turn NAME into __wrap_NAME.
+ std::string s;
+ if (prefix != '\0')
+ s += prefix;
+ s += "__wrap_";
+ s += name;
+
+ // This will give us both the old and new name in NAMEPOOL_, but
+ // that is OK. Only the versions we need will wind up in the
+ // real string table in the output file.
+ return this->namepool_.add(s.c_str(), true, name_key);
+ }
+
+ const char* const real_prefix = "__real_";
+ const size_t real_prefix_length = strlen(real_prefix);
+ if (strncmp(name, real_prefix, real_prefix_length) == 0
+ && parameters->options().is_wrap(name + real_prefix_length))
+ {
+ // Turn __real_NAME into NAME.
+ std::string s;
+ if (prefix != '\0')
+ s += prefix;
+ s += name + real_prefix_length;
+ return this->namepool_.add(s.c_str(), true, name_key);
+ }
+
+ return name;
+}
+
+// This is called when we see a symbol NAME/VERSION, and the symbol
+// already exists in the symbol table, and VERSION is marked as being
+// the default version. SYM is the NAME/VERSION symbol we just added.
+// DEFAULT_IS_NEW is true if this is the first time we have seen the
+// symbol NAME/NULL. PDEF points to the entry for NAME/NULL.
+
+template<int size, bool big_endian>
+void
+Symbol_table::define_default_version(Sized_symbol<size>* sym,
+ bool default_is_new,
+ Symbol_table_type::iterator pdef)
+{
+ if (default_is_new)
+ {
+ // This is the first time we have seen NAME/NULL. Make
+ // NAME/NULL point to NAME/VERSION, and mark SYM as the default
+ // version.
+ pdef->second = sym;
+ sym->set_is_default();
+ }
+ else if (pdef->second == sym)
+ {
+ // NAME/NULL already points to NAME/VERSION. Don't mark the
+ // symbol as the default if it is not already the default.
+ }
+ else
+ {
+ // This is the unfortunate case where we already have entries
+ // for both NAME/VERSION and NAME/NULL. We now see a symbol
+ // NAME/VERSION where VERSION is the default version. We have
+ // already resolved this new symbol with the existing
+ // NAME/VERSION symbol.
+
+ // It's possible that NAME/NULL and NAME/VERSION are both
+ // defined in regular objects. This can only happen if one
+ // object file defines foo and another defines foo@@ver. This
+ // is somewhat obscure, but we call it a multiple definition
+ // error.
+
+ // It's possible that NAME/NULL actually has a version, in which
+ // case it won't be the same as VERSION. This happens with
+ // ver_test_7.so in the testsuite for the symbol t2_2. We see
+ // t2_2@@VER2, so we define both t2_2/VER2 and t2_2/NULL. We
+ // then see an unadorned t2_2 in an object file and give it
+ // version VER1 from the version script. This looks like a
+ // default definition for VER1, so it looks like we should merge
+ // t2_2/NULL with t2_2/VER1. That doesn't make sense, but it's
+ // not obvious that this is an error, either. So we just punt.
+
+ // If one of the symbols has non-default visibility, and the
+ // other is defined in a shared object, then they are different
+ // symbols.
+
+ // Otherwise, we just resolve the symbols as though they were
+ // the same.
+
+ if (pdef->second->version() != NULL)
+ gold_assert(pdef->second->version() != sym->version());
+ else if (sym->visibility() != elfcpp::STV_DEFAULT
+ && pdef->second->is_from_dynobj())
+ ;
+ else if (pdef->second->visibility() != elfcpp::STV_DEFAULT
+ && sym->is_from_dynobj())
+ ;
+ else
+ {
+ const Sized_symbol<size>* symdef;
+ symdef = this->get_sized_symbol<size>(pdef->second);
+ Symbol_table::resolve<size, big_endian>(sym, symdef);
+ this->make_forwarder(pdef->second, sym);
+ pdef->second = sym;
+ sym->set_is_default();
+ }
+ }
+}
+
+// Add one symbol from OBJECT to the symbol table. NAME is symbol
+// name and VERSION is the version; both are canonicalized. DEF is
+// whether this is the default version. ST_SHNDX is the symbol's
+// section index; IS_ORDINARY is whether this is a normal section
+// rather than a special code.
+
+// If IS_DEFAULT_VERSION is true, then this is the definition of a
+// default version of a symbol. That means that any lookup of
+// NAME/NULL and any lookup of NAME/VERSION should always return the
+// same symbol. This is obvious for references, but in particular we
+// want to do this for definitions: overriding NAME/NULL should also
+// override NAME/VERSION. If we don't do that, it would be very hard
+// to override functions in a shared library which uses versioning.
+
+// We implement this by simply making both entries in the hash table
+// point to the same Symbol structure. That is easy enough if this is
+// the first time we see NAME/NULL or NAME/VERSION, but it is possible
+// that we have seen both already, in which case they will both have
+// independent entries in the symbol table. We can't simply change
+// the symbol table entry, because we have pointers to the entries
+// attached to the object files. So we mark the entry attached to the
+// object file as a forwarder, and record it in the forwarders_ map.
+// Note that entries in the hash table will never be marked as
+// forwarders.
+//
+// ORIG_ST_SHNDX and ST_SHNDX are almost always the same.
+// ORIG_ST_SHNDX is the section index in the input file, or SHN_UNDEF
+// for a special section code. ST_SHNDX may be modified if the symbol
+// is defined in a section being discarded.
+
+template<int size, bool big_endian>
+Sized_symbol<size>*
+Symbol_table::add_from_object(Object* object,
+ const char* name,
+ Stringpool::Key name_key,
+ const char* version,
+ Stringpool::Key version_key,
+ bool is_default_version,
+ const elfcpp::Sym<size, big_endian>& sym,
+ unsigned int st_shndx,
+ bool is_ordinary,
+ unsigned int orig_st_shndx)
+{
+ // Print a message if this symbol is being traced.
+ if (parameters->options().is_trace_symbol(name))
+ {
+ if (orig_st_shndx == elfcpp::SHN_UNDEF)
+ gold_info(_("%s: reference to %s"), object->name().c_str(), name);
+ else
+ gold_info(_("%s: definition of %s"), object->name().c_str(), name);
+ }
+
+ // For an undefined symbol, we may need to adjust the name using
+ // --wrap.
+ if (orig_st_shndx == elfcpp::SHN_UNDEF
+ && parameters->options().any_wrap())
+ {
+ const char* wrap_name = this->wrap_symbol(name, &name_key);
+ if (wrap_name != name)
+ {
+ // If we see a reference to malloc with version GLIBC_2.0,
+ // and we turn it into a reference to __wrap_malloc, then we
+ // discard the version number. Otherwise the user would be
+ // required to specify the correct version for
+ // __wrap_malloc.
+ version = NULL;
+ version_key = 0;
+ name = wrap_name;
+ }
+ }
+
+ Symbol* const snull = NULL;
+ std::pair<typename Symbol_table_type::iterator, bool> ins =
+ this->table_.insert(std::make_pair(std::make_pair(name_key, version_key),
+ snull));
+
+ std::pair<typename Symbol_table_type::iterator, bool> insdefault =
+ std::make_pair(this->table_.end(), false);
+ if (is_default_version)
+ {
+ const Stringpool::Key vnull_key = 0;
+ insdefault = this->table_.insert(std::make_pair(std::make_pair(name_key,
+ vnull_key),
+ snull));
+ }
+
+ // ins.first: an iterator, which is a pointer to a pair.
+ // ins.first->first: the key (a pair of name and version).
+ // ins.first->second: the value (Symbol*).
+ // ins.second: true if new entry was inserted, false if not.
+
+ Sized_symbol<size>* ret;
+ bool was_undefined;
+ bool was_common;
+ if (!ins.second)
+ {
+ // We already have an entry for NAME/VERSION.
+ ret = this->get_sized_symbol<size>(ins.first->second);
+ gold_assert(ret != NULL);
+
+ was_undefined = ret->is_undefined();
+ was_common = ret->is_common();
+
+ this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object,
+ version);
+ if (parameters->options().gc_sections())
+ this->gc_mark_dyn_syms(ret);
+
+ if (is_default_version)
+ this->define_default_version<size, big_endian>(ret, insdefault.second,
+ insdefault.first);
+ }
+ else
+ {
+ // This is the first time we have seen NAME/VERSION.
+ gold_assert(ins.first->second == NULL);
+
+ if (is_default_version && !insdefault.second)
+ {
+ // We already have an entry for NAME/NULL. If we override
+ // it, then change it to NAME/VERSION.
+ ret = this->get_sized_symbol<size>(insdefault.first->second);
+
+ was_undefined = ret->is_undefined();
+ was_common = ret->is_common();
+
+ this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object,
+ version);
+ if (parameters->options().gc_sections())
+ this->gc_mark_dyn_syms(ret);
+ ins.first->second = ret;
+ }
+ else
+ {
+ was_undefined = false;
+ was_common = false;
+
+ Sized_target<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
+ if (!target->has_make_symbol())
+ ret = new Sized_symbol<size>();
+ else
+ {
+ ret = target->make_symbol();
+ if (ret == NULL)
+ {
+ // This means that we don't want a symbol table
+ // entry after all.
+ if (!is_default_version)
+ this->table_.erase(ins.first);
+ else
+ {
+ this->table_.erase(insdefault.first);
+ // Inserting INSDEFAULT invalidated INS.
+ this->table_.erase(std::make_pair(name_key,
+ version_key));
+ }
+ return NULL;
+ }
+ }
+
+ ret->init_object(name, version, object, sym, st_shndx, is_ordinary);
+
+ ins.first->second = ret;
+ if (is_default_version)
+ {
+ // This is the first time we have seen NAME/NULL. Point
+ // it at the new entry for NAME/VERSION.
+ gold_assert(insdefault.second);
+ insdefault.first->second = ret;
+ }
+ }
+
+ if (is_default_version)
+ ret->set_is_default();
+ }
+
+ // Record every time we see a new undefined symbol, to speed up
+ // archive groups.
+ if (!was_undefined && ret->is_undefined())
+ {
+ ++this->saw_undefined_;
+ if (parameters->options().has_plugins())
+ parameters->options().plugins()->new_undefined_symbol(ret);
+ }
+
+ // Keep track of common symbols, to speed up common symbol
+ // allocation.
+ if (!was_common && ret->is_common())
+ {
+ if (ret->type() == elfcpp::STT_TLS)
+ this->tls_commons_.push_back(ret);
+ else if (!is_ordinary
+ && st_shndx == parameters->target().small_common_shndx())
+ this->small_commons_.push_back(ret);
+ else if (!is_ordinary
+ && st_shndx == parameters->target().large_common_shndx())
+ this->large_commons_.push_back(ret);
+ else
+ this->commons_.push_back(ret);
+ }
+
+ // If we're not doing a relocatable link, then any symbol with
+ // hidden or internal visibility is local.
+ if ((ret->visibility() == elfcpp::STV_HIDDEN
+ || ret->visibility() == elfcpp::STV_INTERNAL)
+ && (ret->binding() == elfcpp::STB_GLOBAL
+ || ret->binding() == elfcpp::STB_GNU_UNIQUE
+ || ret->binding() == elfcpp::STB_WEAK)
+ && !parameters->options().relocatable())
+ this->force_local(ret);
+
+ return ret;
+}
+
+// Add all the symbols in a relocatable object to the hash table.
+
+template<int size, bool big_endian>
+void
+Symbol_table::add_from_relobj(
+ Sized_relobj_file<size, big_endian>* relobj,
+ const unsigned char* syms,
+ size_t count,
+ size_t symndx_offset,
+ const char* sym_names,
+ size_t sym_name_size,
+ typename Sized_relobj_file<size, big_endian>::Symbols* sympointers,
+ size_t* defined)
+{
+ *defined = 0;
+
+ gold_assert(size == parameters->target().get_size());
+
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+ const bool just_symbols = relobj->just_symbols();
+
+ const unsigned char* p = syms;
+ for (size_t i = 0; i < count; ++i, p += sym_size)
+ {
+ (*sympointers)[i] = NULL;
+
+ elfcpp::Sym<size, big_endian> sym(p);
+
+ unsigned int st_name = sym.get_st_name();
+ if (st_name >= sym_name_size)
+ {
+ relobj->error(_("bad global symbol name offset %u at %zu"),
+ st_name, i);
+ continue;
+ }
+
+ const char* name = sym_names + st_name;
+
+ bool is_ordinary;
+ unsigned int st_shndx = relobj->adjust_sym_shndx(i + symndx_offset,
+ sym.get_st_shndx(),
+ &is_ordinary);
+ unsigned int orig_st_shndx = st_shndx;
+ if (!is_ordinary)
+ orig_st_shndx = elfcpp::SHN_UNDEF;
+
+ if (st_shndx != elfcpp::SHN_UNDEF)
+ ++*defined;
+
+ // A symbol defined in a section which we are not including must
+ // be treated as an undefined symbol.
+ bool is_defined_in_discarded_section = false;
+ if (st_shndx != elfcpp::SHN_UNDEF
+ && is_ordinary
+ && !relobj->is_section_included(st_shndx)
+ && !this->is_section_folded(relobj, st_shndx))
+ {
+ st_shndx = elfcpp::SHN_UNDEF;
+ is_defined_in_discarded_section = true;
+ }
+
+ // In an object file, an '@' in the name separates the symbol
+ // name from the version name. If there are two '@' characters,
+ // this is the default version.
+ const char* ver = strchr(name, '@');
+ Stringpool::Key ver_key = 0;
+ int namelen = 0;
+ // IS_DEFAULT_VERSION: is the version default?
+ // IS_FORCED_LOCAL: is the symbol forced local?
+ bool is_default_version = false;
+ bool is_forced_local = false;
+
+ // FIXME: For incremental links, we don't store version information,
+ // so we need to ignore version symbols for now.
+ if (parameters->incremental_update() && ver != NULL)
+ {
+ namelen = ver - name;
+ ver = NULL;
+ }
+
+ if (ver != NULL)
+ {
+ // The symbol name is of the form foo@VERSION or foo@@VERSION
+ namelen = ver - name;
+ ++ver;
+ if (*ver == '@')
+ {
+ is_default_version = true;
+ ++ver;
+ }
+ ver = this->namepool_.add(ver, true, &ver_key);
+ }
+ // We don't want to assign a version to an undefined symbol,
+ // even if it is listed in the version script. FIXME: What
+ // about a common symbol?
+ else
+ {
+ namelen = strlen(name);
+ if (!this->version_script_.empty()
+ && st_shndx != elfcpp::SHN_UNDEF)
+ {
+ // The symbol name did not have a version, but the
+ // version script may assign a version anyway.
+ std::string version;
+ bool is_global;
+ if (this->version_script_.get_symbol_version(name, &version,
+ &is_global))
+ {
+ if (!is_global)
+ is_forced_local = true;
+ else if (!version.empty())
+ {
+ ver = this->namepool_.add_with_length(version.c_str(),
+ version.length(),
+ true,
+ &ver_key);
+ is_default_version = true;
+ }
+ }
+ }
+ }
+
+ elfcpp::Sym<size, big_endian>* psym = &sym;
+ unsigned char symbuf[sym_size];
+ elfcpp::Sym<size, big_endian> sym2(symbuf);
+ if (just_symbols)
+ {
+ memcpy(symbuf, p, sym_size);
+ elfcpp::Sym_write<size, big_endian> sw(symbuf);
+ if (orig_st_shndx != elfcpp::SHN_UNDEF
+ && is_ordinary
+ && relobj->e_type() == elfcpp::ET_REL)
+ {
+ // Symbol values in relocatable object files are section
+ // relative. This is normally what we want, but since here
+ // we are converting the symbol to absolute we need to add
+ // the section address. The section address in an object
+ // file is normally zero, but people can use a linker
+ // script to change it.
+ sw.put_st_value(sym.get_st_value()
+ + relobj->section_address(orig_st_shndx));
+ }
+ st_shndx = elfcpp::SHN_ABS;
+ is_ordinary = false;
+ psym = &sym2;
+ }
+
+ // Fix up visibility if object has no-export set.
+ if (relobj->no_export()
+ && (orig_st_shndx != elfcpp::SHN_UNDEF || !is_ordinary))
+ {
+ // We may have copied symbol already above.
+ if (psym != &sym2)
+ {
+ memcpy(symbuf, p, sym_size);
+ psym = &sym2;
+ }
+
+ elfcpp::STV visibility = sym2.get_st_visibility();
+ if (visibility == elfcpp::STV_DEFAULT
+ || visibility == elfcpp::STV_PROTECTED)
+ {
+ elfcpp::Sym_write<size, big_endian> sw(symbuf);
+ unsigned char nonvis = sym2.get_st_nonvis();
+ sw.put_st_other(elfcpp::STV_HIDDEN, nonvis);
+ }
+ }
+
+ Stringpool::Key name_key;
+ name = this->namepool_.add_with_length(name, namelen, true,
+ &name_key);
+
+ Sized_symbol<size>* res;
+ res = this->add_from_object(relobj, name, name_key, ver, ver_key,
+ is_default_version, *psym, st_shndx,
+ is_ordinary, orig_st_shndx);
+
+ if (is_forced_local)
+ this->force_local(res);
+
+ // Do not treat this symbol as garbage if this symbol will be
+ // exported to the dynamic symbol table. This is true when
+ // building a shared library or using --export-dynamic and
+ // the symbol is externally visible.
+ if (parameters->options().gc_sections()
+ && res->is_externally_visible()
+ && !res->is_from_dynobj()
+ && (parameters->options().shared()
+ || parameters->options().export_dynamic()))
+ this->gc_mark_symbol(res);
+
+ if (is_defined_in_discarded_section)
+ res->set_is_defined_in_discarded_section();
+
+ (*sympointers)[i] = res;
+ }
+}
+
+// Add a symbol from a plugin-claimed file.
+
+template<int size, bool big_endian>
+Symbol*
+Symbol_table::add_from_pluginobj(
+ Sized_pluginobj<size, big_endian>* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<size, big_endian>* sym)
+{
+ unsigned int st_shndx = sym->get_st_shndx();
+ bool is_ordinary = st_shndx < elfcpp::SHN_LORESERVE;
+
+ Stringpool::Key ver_key = 0;
+ bool is_default_version = false;
+ bool is_forced_local = false;
+
+ if (ver != NULL)
+ {
+ ver = this->namepool_.add(ver, true, &ver_key);
+ }
+ // We don't want to assign a version to an undefined symbol,
+ // even if it is listed in the version script. FIXME: What
+ // about a common symbol?
+ else
+ {
+ if (!this->version_script_.empty()
+ && st_shndx != elfcpp::SHN_UNDEF)
+ {
+ // The symbol name did not have a version, but the
+ // version script may assign a version anyway.
+ std::string version;
+ bool is_global;
+ if (this->version_script_.get_symbol_version(name, &version,
+ &is_global))
+ {
+ if (!is_global)
+ is_forced_local = true;
+ else if (!version.empty())
+ {
+ ver = this->namepool_.add_with_length(version.c_str(),
+ version.length(),
+ true,
+ &ver_key);
+ is_default_version = true;
+ }
+ }
+ }
+ }
+
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, true, &name_key);
+
+ Sized_symbol<size>* res;
+ res = this->add_from_object(obj, name, name_key, ver, ver_key,
+ is_default_version, *sym, st_shndx,
+ is_ordinary, st_shndx);
+
+ if (is_forced_local)
+ this->force_local(res);
+
+ return res;
+}
+
+// Add all the symbols in a dynamic object to the hash table.
+
+template<int size, bool big_endian>
+void
+Symbol_table::add_from_dynobj(
+ Sized_dynobj<size, big_endian>* dynobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ const unsigned char* versym,
+ size_t versym_size,
+ const std::vector<const char*>* version_map,
+ typename Sized_relobj_file<size, big_endian>::Symbols* sympointers,
+ size_t* defined)
+{
+ *defined = 0;
+
+ gold_assert(size == parameters->target().get_size());
+
+ if (dynobj->just_symbols())
+ {
+ gold_error(_("--just-symbols does not make sense with a shared object"));
+ return;
+ }
+
+ // FIXME: For incremental links, we don't store version information,
+ // so we need to ignore version symbols for now.
+ if (parameters->incremental_update())
+ versym = NULL;
+
+ if (versym != NULL && versym_size / 2 < count)
+ {
+ dynobj->error(_("too few symbol versions"));
+ return;
+ }
+
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+ // We keep a list of all STT_OBJECT symbols, so that we can resolve
+ // weak aliases. This is necessary because if the dynamic object
+ // provides the same variable under two names, one of which is a
+ // weak definition, and the regular object refers to the weak
+ // definition, we have to put both the weak definition and the
+ // strong definition into the dynamic symbol table. Given a weak
+ // definition, the only way that we can find the corresponding
+ // strong definition, if any, is to search the symbol table.
+ std::vector<Sized_symbol<size>*> object_symbols;
+
+ const unsigned char* p = syms;
+ const unsigned char* vs = versym;
+ for (size_t i = 0; i < count; ++i, p += sym_size, vs += 2)
+ {
+ elfcpp::Sym<size, big_endian> sym(p);
+
+ if (sympointers != NULL)
+ (*sympointers)[i] = NULL;
+
+ // Ignore symbols with local binding or that have
+ // internal or hidden visibility.
+ if (sym.get_st_bind() == elfcpp::STB_LOCAL
+ || sym.get_st_visibility() == elfcpp::STV_INTERNAL
+ || sym.get_st_visibility() == elfcpp::STV_HIDDEN)
+ continue;
+
+ // A protected symbol in a shared library must be treated as a
+ // normal symbol when viewed from outside the shared library.
+ // Implement this by overriding the visibility here.
+ elfcpp::Sym<size, big_endian>* psym = &sym;
+ unsigned char symbuf[sym_size];
+ elfcpp::Sym<size, big_endian> sym2(symbuf);
+ if (sym.get_st_visibility() == elfcpp::STV_PROTECTED)
+ {
+ memcpy(symbuf, p, sym_size);
+ elfcpp::Sym_write<size, big_endian> sw(symbuf);
+ sw.put_st_other(elfcpp::STV_DEFAULT, sym.get_st_nonvis());
+ psym = &sym2;
+ }
+
+ unsigned int st_name = psym->get_st_name();
+ if (st_name >= sym_name_size)
+ {
+ dynobj->error(_("bad symbol name offset %u at %zu"),
+ st_name, i);
+ continue;
+ }
+
+ const char* name = sym_names + st_name;
+
+ bool is_ordinary;
+ unsigned int st_shndx = dynobj->adjust_sym_shndx(i, psym->get_st_shndx(),
+ &is_ordinary);
+
+ if (st_shndx != elfcpp::SHN_UNDEF)
+ ++*defined;
+
+ Sized_symbol<size>* res;
+
+ if (versym == NULL)
+ {
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, true, &name_key);
+ res = this->add_from_object(dynobj, name, name_key, NULL, 0,
+ false, *psym, st_shndx, is_ordinary,
+ st_shndx);
+ }
+ else
+ {
+ // Read the version information.
+
+ unsigned int v = elfcpp::Swap<16, big_endian>::readval(vs);
+
+ bool hidden = (v & elfcpp::VERSYM_HIDDEN) != 0;
+ v &= elfcpp::VERSYM_VERSION;
+
+ // The Sun documentation says that V can be VER_NDX_LOCAL,
+ // or VER_NDX_GLOBAL, or a version index. The meaning of
+ // VER_NDX_LOCAL is defined as "Symbol has local scope."
+ // The old GNU linker will happily generate VER_NDX_LOCAL
+ // for an undefined symbol. I don't know what the Sun
+ // linker will generate.
+
+ if (v == static_cast<unsigned int>(elfcpp::VER_NDX_LOCAL)
+ && st_shndx != elfcpp::SHN_UNDEF)
+ {
+ // This symbol should not be visible outside the object.
+ continue;
+ }
+
+ // At this point we are definitely going to add this symbol.
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, true, &name_key);
+
+ if (v == static_cast<unsigned int>(elfcpp::VER_NDX_LOCAL)
+ || v == static_cast<unsigned int>(elfcpp::VER_NDX_GLOBAL))
+ {
+ // This symbol does not have a version.
+ res = this->add_from_object(dynobj, name, name_key, NULL, 0,
+ false, *psym, st_shndx, is_ordinary,
+ st_shndx);
+ }
+ else
+ {
+ if (v >= version_map->size())
+ {
+ dynobj->error(_("versym for symbol %zu out of range: %u"),
+ i, v);
+ continue;
+ }
+
+ const char* version = (*version_map)[v];
+ if (version == NULL)
+ {
+ dynobj->error(_("versym for symbol %zu has no name: %u"),
+ i, v);
+ continue;
+ }
+
+ Stringpool::Key version_key;
+ version = this->namepool_.add(version, true, &version_key);
+
+ // If this is an absolute symbol, and the version name
+ // and symbol name are the same, then this is the
+ // version definition symbol. These symbols exist to
+ // support using -u to pull in particular versions. We
+ // do not want to record a version for them.
+ if (st_shndx == elfcpp::SHN_ABS
+ && !is_ordinary
+ && name_key == version_key)
+ res = this->add_from_object(dynobj, name, name_key, NULL, 0,
+ false, *psym, st_shndx, is_ordinary,
+ st_shndx);
+ else
+ {
+ const bool is_default_version =
+ !hidden && st_shndx != elfcpp::SHN_UNDEF;
+ res = this->add_from_object(dynobj, name, name_key, version,
+ version_key, is_default_version,
+ *psym, st_shndx,
+ is_ordinary, st_shndx);
+ }
+ }
+ }
+
+ // Note that it is possible that RES was overridden by an
+ // earlier object, in which case it can't be aliased here.
+ if (st_shndx != elfcpp::SHN_UNDEF
+ && is_ordinary
+ && psym->get_st_type() == elfcpp::STT_OBJECT
+ && res->source() == Symbol::FROM_OBJECT
+ && res->object() == dynobj)
+ object_symbols.push_back(res);
+
+ if (sympointers != NULL)
+ (*sympointers)[i] = res;
+ }
+
+ this->record_weak_aliases(&object_symbols);
+}
+
+// Add a symbol from a incremental object file.
+
+template<int size, bool big_endian>
+Sized_symbol<size>*
+Symbol_table::add_from_incrobj(
+ Object* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<size, big_endian>* sym)
+{
+ unsigned int st_shndx = sym->get_st_shndx();
+ bool is_ordinary = st_shndx < elfcpp::SHN_LORESERVE;
+
+ Stringpool::Key ver_key = 0;
+ bool is_default_version = false;
+ bool is_forced_local = false;
+
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, true, &name_key);
+
+ Sized_symbol<size>* res;
+ res = this->add_from_object(obj, name, name_key, ver, ver_key,
+ is_default_version, *sym, st_shndx,
+ is_ordinary, st_shndx);
+
+ if (is_forced_local)
+ this->force_local(res);
+
+ return res;
+}
+
+// This is used to sort weak aliases. We sort them first by section
+// index, then by offset, then by weak ahead of strong.
+
+template<int size>
+class Weak_alias_sorter
+{
+ public:
+ bool operator()(const Sized_symbol<size>*, const Sized_symbol<size>*) const;
+};
+
+template<int size>
+bool
+Weak_alias_sorter<size>::operator()(const Sized_symbol<size>* s1,
+ const Sized_symbol<size>* s2) const
+{
+ bool is_ordinary;
+ unsigned int s1_shndx = s1->shndx(&is_ordinary);
+ gold_assert(is_ordinary);
+ unsigned int s2_shndx = s2->shndx(&is_ordinary);
+ gold_assert(is_ordinary);
+ if (s1_shndx != s2_shndx)
+ return s1_shndx < s2_shndx;
+
+ if (s1->value() != s2->value())
+ return s1->value() < s2->value();
+ if (s1->binding() != s2->binding())
+ {
+ if (s1->binding() == elfcpp::STB_WEAK)
+ return true;
+ if (s2->binding() == elfcpp::STB_WEAK)
+ return false;
+ }
+ return std::string(s1->name()) < std::string(s2->name());
+}
+
+// SYMBOLS is a list of object symbols from a dynamic object. Look
+// for any weak aliases, and record them so that if we add the weak
+// alias to the dynamic symbol table, we also add the corresponding
+// strong symbol.
+
+template<int size>
+void
+Symbol_table::record_weak_aliases(std::vector<Sized_symbol<size>*>* symbols)
+{
+ // Sort the vector by section index, then by offset, then by weak
+ // ahead of strong.
+ std::sort(symbols->begin(), symbols->end(), Weak_alias_sorter<size>());
+
+ // Walk through the vector. For each weak definition, record
+ // aliases.
+ for (typename std::vector<Sized_symbol<size>*>::const_iterator p =
+ symbols->begin();
+ p != symbols->end();
+ ++p)
+ {
+ if ((*p)->binding() != elfcpp::STB_WEAK)
+ continue;
+
+ // Build a circular list of weak aliases. Each symbol points to
+ // the next one in the circular list.
+
+ Sized_symbol<size>* from_sym = *p;
+ typename std::vector<Sized_symbol<size>*>::const_iterator q;
+ for (q = p + 1; q != symbols->end(); ++q)
+ {
+ bool dummy;
+ if ((*q)->shndx(&dummy) != from_sym->shndx(&dummy)
+ || (*q)->value() != from_sym->value())
+ break;
+
+ this->weak_aliases_[from_sym] = *q;
+ from_sym->set_has_alias();
+ from_sym = *q;
+ }
+
+ if (from_sym != *p)
+ {
+ this->weak_aliases_[from_sym] = *p;
+ from_sym->set_has_alias();
+ }
+
+ p = q - 1;
+ }
+}
+
+// Create and return a specially defined symbol. If ONLY_IF_REF is
+// true, then only create the symbol if there is a reference to it.
+// If this does not return NULL, it sets *POLDSYM to the existing
+// symbol if there is one. This sets *RESOLVE_OLDSYM if we should
+// resolve the newly created symbol to the old one. This
+// canonicalizes *PNAME and *PVERSION.
+
+template<int size, bool big_endian>
+Sized_symbol<size>*
+Symbol_table::define_special_symbol(const char** pname, const char** pversion,
+ bool only_if_ref,
+ Sized_symbol<size>** poldsym,
+ bool* resolve_oldsym)
+{
+ *resolve_oldsym = false;
+ *poldsym = NULL;
+
+ // If the caller didn't give us a version, see if we get one from
+ // the version script.
+ std::string v;
+ bool is_default_version = false;
+ if (*pversion == NULL)
+ {
+ bool is_global;
+ if (this->version_script_.get_symbol_version(*pname, &v, &is_global))
+ {
+ if (is_global && !v.empty())
+ {
+ *pversion = v.c_str();
+ // If we get the version from a version script, then we
+ // are also the default version.
+ is_default_version = true;
+ }
+ }
+ }
+
+ Symbol* oldsym;
+ Sized_symbol<size>* sym;
+
+ bool add_to_table = false;
+ typename Symbol_table_type::iterator add_loc = this->table_.end();
+ bool add_def_to_table = false;
+ typename Symbol_table_type::iterator add_def_loc = this->table_.end();
+
+ if (only_if_ref)
+ {
+ oldsym = this->lookup(*pname, *pversion);
+ if (oldsym == NULL && is_default_version)
+ oldsym = this->lookup(*pname, NULL);
+ if (oldsym == NULL || !oldsym->is_undefined())
+ return NULL;
+
+ *pname = oldsym->name();
+ if (is_default_version)
+ *pversion = this->namepool_.add(*pversion, true, NULL);
+ else
+ *pversion = oldsym->version();
+ }
+ else
+ {
+ // Canonicalize NAME and VERSION.
+ Stringpool::Key name_key;
+ *pname = this->namepool_.add(*pname, true, &name_key);
+
+ Stringpool::Key version_key = 0;
+ if (*pversion != NULL)
+ *pversion = this->namepool_.add(*pversion, true, &version_key);
+
+ Symbol* const snull = NULL;
+ std::pair<typename Symbol_table_type::iterator, bool> ins =
+ this->table_.insert(std::make_pair(std::make_pair(name_key,
+ version_key),
+ snull));
+
+ std::pair<typename Symbol_table_type::iterator, bool> insdefault =
+ std::make_pair(this->table_.end(), false);
+ if (is_default_version)
+ {
+ const Stringpool::Key vnull = 0;
+ insdefault =
+ this->table_.insert(std::make_pair(std::make_pair(name_key,
+ vnull),
+ snull));
+ }
+
+ if (!ins.second)
+ {
+ // We already have a symbol table entry for NAME/VERSION.
+ oldsym = ins.first->second;
+ gold_assert(oldsym != NULL);
+
+ if (is_default_version)
+ {
+ Sized_symbol<size>* soldsym =
+ this->get_sized_symbol<size>(oldsym);
+ this->define_default_version<size, big_endian>(soldsym,
+ insdefault.second,
+ insdefault.first);
+ }
+ }
+ else
+ {
+ // We haven't seen this symbol before.
+ gold_assert(ins.first->second == NULL);
+
+ add_to_table = true;
+ add_loc = ins.first;
+
+ if (is_default_version && !insdefault.second)
+ {
+ // We are adding NAME/VERSION, and it is the default
+ // version. We already have an entry for NAME/NULL.
+ oldsym = insdefault.first->second;
+ *resolve_oldsym = true;
+ }
+ else
+ {
+ oldsym = NULL;
+
+ if (is_default_version)
+ {
+ add_def_to_table = true;
+ add_def_loc = insdefault.first;
+ }
+ }
+ }
+ }
+
+ const Target& target = parameters->target();
+ if (!target.has_make_symbol())
+ sym = new Sized_symbol<size>();
+ else
+ {
+ Sized_target<size, big_endian>* sized_target =
+ parameters->sized_target<size, big_endian>();
+ sym = sized_target->make_symbol();
+ if (sym == NULL)
+ return NULL;
+ }
+
+ if (add_to_table)
+ add_loc->second = sym;
+ else
+ gold_assert(oldsym != NULL);
+
+ if (add_def_to_table)
+ add_def_loc->second = sym;
+
+ *poldsym = this->get_sized_symbol<size>(oldsym);
+
+ return sym;
+}
+
+// Define a symbol based on an Output_data.
+
+Symbol*
+Symbol_table::define_in_output_data(const char* name,
+ const char* version,
+ Defined defined,
+ Output_data* od,
+ uint64_t value,
+ uint64_t symsize,
+ elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ bool offset_is_from_end,
+ bool only_if_ref)
+{
+ if (parameters->target().get_size() == 32)
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+ return this->do_define_in_output_data<32>(name, version, defined, od,
+ value, symsize, type, binding,
+ visibility, nonvis,
+ offset_is_from_end,
+ only_if_ref);
+#else
+ gold_unreachable();
+#endif
+ }
+ else if (parameters->target().get_size() == 64)
+ {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+ return this->do_define_in_output_data<64>(name, version, defined, od,
+ value, symsize, type, binding,
+ visibility, nonvis,
+ offset_is_from_end,
+ only_if_ref);
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ gold_unreachable();
+}
+
+// Define a symbol in an Output_data, sized version.
+
+template<int size>
+Sized_symbol<size>*
+Symbol_table::do_define_in_output_data(
+ const char* name,
+ const char* version,
+ Defined defined,
+ Output_data* od,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+ elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ bool offset_is_from_end,
+ bool only_if_ref)
+{
+ Sized_symbol<size>* sym;
+ Sized_symbol<size>* oldsym;
+ bool resolve_oldsym;
+
+ if (parameters->target().is_big_endian())
+ {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
+ sym = this->define_special_symbol<size, true>(&name, &version,
+ only_if_ref, &oldsym,
+ &resolve_oldsym);
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
+ sym = this->define_special_symbol<size, false>(&name, &version,
+ only_if_ref, &oldsym,
+ &resolve_oldsym);
+#else
+ gold_unreachable();
+#endif
+ }
+
+ if (sym == NULL)
+ return NULL;
+
+ sym->init_output_data(name, version, od, value, symsize, type, binding,
+ visibility, nonvis, offset_is_from_end,
+ defined == PREDEFINED);
+
+ if (oldsym == NULL)
+ {
+ if (binding == elfcpp::STB_LOCAL
+ || this->version_script_.symbol_is_local(name))
+ this->force_local(sym);
+ else if (version != NULL)
+ sym->set_is_default();
+ return sym;
+ }
+
+ if (Symbol_table::should_override_with_special(oldsym, type, defined))
+ this->override_with_special(oldsym, sym);
+
+ if (resolve_oldsym)
+ return sym;
+ else
+ {
+ delete sym;
+ return oldsym;
+ }
+}
+
+// Define a symbol based on an Output_segment.
+
+Symbol*
+Symbol_table::define_in_output_segment(const char* name,
+ const char* version,
+ Defined defined,
+ Output_segment* os,
+ uint64_t value,
+ uint64_t symsize,
+ elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ Symbol::Segment_offset_base offset_base,
+ bool only_if_ref)
+{
+ if (parameters->target().get_size() == 32)
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+ return this->do_define_in_output_segment<32>(name, version, defined, os,
+ value, symsize, type,
+ binding, visibility, nonvis,
+ offset_base, only_if_ref);
+#else
+ gold_unreachable();
+#endif
+ }
+ else if (parameters->target().get_size() == 64)
+ {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+ return this->do_define_in_output_segment<64>(name, version, defined, os,
+ value, symsize, type,
+ binding, visibility, nonvis,
+ offset_base, only_if_ref);
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ gold_unreachable();
+}
+
+// Define a symbol in an Output_segment, sized version.
+
+template<int size>
+Sized_symbol<size>*
+Symbol_table::do_define_in_output_segment(
+ const char* name,
+ const char* version,
+ Defined defined,
+ Output_segment* os,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+ elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ Symbol::Segment_offset_base offset_base,
+ bool only_if_ref)
+{
+ Sized_symbol<size>* sym;
+ Sized_symbol<size>* oldsym;
+ bool resolve_oldsym;
+
+ if (parameters->target().is_big_endian())
+ {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
+ sym = this->define_special_symbol<size, true>(&name, &version,
+ only_if_ref, &oldsym,
+ &resolve_oldsym);
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
+ sym = this->define_special_symbol<size, false>(&name, &version,
+ only_if_ref, &oldsym,
+ &resolve_oldsym);
+#else
+ gold_unreachable();
+#endif
+ }
+
+ if (sym == NULL)
+ return NULL;
+
+ sym->init_output_segment(name, version, os, value, symsize, type, binding,
+ visibility, nonvis, offset_base,
+ defined == PREDEFINED);
+
+ if (oldsym == NULL)
+ {
+ if (binding == elfcpp::STB_LOCAL
+ || this->version_script_.symbol_is_local(name))
+ this->force_local(sym);
+ else if (version != NULL)
+ sym->set_is_default();
+ return sym;
+ }
+
+ if (Symbol_table::should_override_with_special(oldsym, type, defined))
+ this->override_with_special(oldsym, sym);
+
+ if (resolve_oldsym)
+ return sym;
+ else
+ {
+ delete sym;
+ return oldsym;
+ }
+}
+
+// Define a special symbol with a constant value. It is a multiple
+// definition error if this symbol is already defined.
+
+Symbol*
+Symbol_table::define_as_constant(const char* name,
+ const char* version,
+ Defined defined,
+ uint64_t value,
+ uint64_t symsize,
+ elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ bool only_if_ref,
+ bool force_override)
+{
+ if (parameters->target().get_size() == 32)
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+ return this->do_define_as_constant<32>(name, version, defined, value,
+ symsize, type, binding,
+ visibility, nonvis, only_if_ref,
+ force_override);
+#else
+ gold_unreachable();
+#endif
+ }
+ else if (parameters->target().get_size() == 64)
+ {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+ return this->do_define_as_constant<64>(name, version, defined, value,
+ symsize, type, binding,
+ visibility, nonvis, only_if_ref,
+ force_override);
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ gold_unreachable();
+}
+
+// Define a symbol as a constant, sized version.
+
+template<int size>
+Sized_symbol<size>*
+Symbol_table::do_define_as_constant(
+ const char* name,
+ const char* version,
+ Defined defined,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+ elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ bool only_if_ref,
+ bool force_override)
+{
+ Sized_symbol<size>* sym;
+ Sized_symbol<size>* oldsym;
+ bool resolve_oldsym;
+
+ if (parameters->target().is_big_endian())
+ {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
+ sym = this->define_special_symbol<size, true>(&name, &version,
+ only_if_ref, &oldsym,
+ &resolve_oldsym);
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
+ sym = this->define_special_symbol<size, false>(&name, &version,
+ only_if_ref, &oldsym,
+ &resolve_oldsym);
+#else
+ gold_unreachable();
+#endif
+ }
+
+ if (sym == NULL)
+ return NULL;
+
+ sym->init_constant(name, version, value, symsize, type, binding, visibility,
+ nonvis, defined == PREDEFINED);
+
+ if (oldsym == NULL)
+ {
+ // Version symbols are absolute symbols with name == version.
+ // We don't want to force them to be local.
+ if ((version == NULL
+ || name != version
+ || value != 0)
+ && (binding == elfcpp::STB_LOCAL
+ || this->version_script_.symbol_is_local(name)))
+ this->force_local(sym);
+ else if (version != NULL
+ && (name != version || value != 0))
+ sym->set_is_default();
+ return sym;
+ }
+
+ if (force_override
+ || Symbol_table::should_override_with_special(oldsym, type, defined))
+ this->override_with_special(oldsym, sym);
+
+ if (resolve_oldsym)
+ return sym;
+ else
+ {
+ delete sym;
+ return oldsym;
+ }
+}
+
+// Define a set of symbols in output sections.
+
+void
+Symbol_table::define_symbols(const Layout* layout, int count,
+ const Define_symbol_in_section* p,
+ bool only_if_ref)
+{
+ for (int i = 0; i < count; ++i, ++p)
+ {
+ Output_section* os = layout->find_output_section(p->output_section);
+ if (os != NULL)
+ this->define_in_output_data(p->name, NULL, PREDEFINED, os, p->value,
+ p->size, p->type, p->binding,
+ p->visibility, p->nonvis,
+ p->offset_is_from_end,
+ only_if_ref || p->only_if_ref);
+ else
+ this->define_as_constant(p->name, NULL, PREDEFINED, 0, p->size,
+ p->type, p->binding, p->visibility, p->nonvis,
+ only_if_ref || p->only_if_ref,
+ false);
+ }
+}
+
+// Define a set of symbols in output segments.
+
+void
+Symbol_table::define_symbols(const Layout* layout, int count,
+ const Define_symbol_in_segment* p,
+ bool only_if_ref)
+{
+ for (int i = 0; i < count; ++i, ++p)
+ {
+ Output_segment* os = layout->find_output_segment(p->segment_type,
+ p->segment_flags_set,
+ p->segment_flags_clear);
+ if (os != NULL)
+ this->define_in_output_segment(p->name, NULL, PREDEFINED, os, p->value,
+ p->size, p->type, p->binding,
+ p->visibility, p->nonvis,
+ p->offset_base,
+ only_if_ref || p->only_if_ref);
+ else
+ this->define_as_constant(p->name, NULL, PREDEFINED, 0, p->size,
+ p->type, p->binding, p->visibility, p->nonvis,
+ only_if_ref || p->only_if_ref,
+ false);
+ }
+}
+
+// Define CSYM using a COPY reloc. POSD is the Output_data where the
+// symbol should be defined--typically a .dyn.bss section. VALUE is
+// the offset within POSD.
+
+template<int size>
+void
+Symbol_table::define_with_copy_reloc(
+ Sized_symbol<size>* csym,
+ Output_data* posd,
+ typename elfcpp::Elf_types<size>::Elf_Addr value)
+{
+ gold_assert(csym->is_from_dynobj());
+ gold_assert(!csym->is_copied_from_dynobj());
+ Object* object = csym->object();
+ gold_assert(object->is_dynamic());
+ Dynobj* dynobj = static_cast<Dynobj*>(object);
+
+ // Our copied variable has to override any variable in a shared
+ // library.
+ elfcpp::STB binding = csym->binding();
+ if (binding == elfcpp::STB_WEAK)
+ binding = elfcpp::STB_GLOBAL;
+
+ this->define_in_output_data(csym->name(), csym->version(), COPY,
+ posd, value, csym->symsize(),
+ csym->type(), binding,
+ csym->visibility(), csym->nonvis(),
+ false, false);
+
+ csym->set_is_copied_from_dynobj();
+ csym->set_needs_dynsym_entry();
+
+ this->copied_symbol_dynobjs_[csym] = dynobj;
+
+ // We have now defined all aliases, but we have not entered them all
+ // in the copied_symbol_dynobjs_ map.
+ if (csym->has_alias())
+ {
+ Symbol* sym = csym;
+ while (true)
+ {
+ sym = this->weak_aliases_[sym];
+ if (sym == csym)
+ break;
+ gold_assert(sym->output_data() == posd);
+
+ sym->set_is_copied_from_dynobj();
+ this->copied_symbol_dynobjs_[sym] = dynobj;
+ }
+ }
+}
+
+// SYM is defined using a COPY reloc. Return the dynamic object where
+// the original definition was found.
+
+Dynobj*
+Symbol_table::get_copy_source(const Symbol* sym) const
+{
+ gold_assert(sym->is_copied_from_dynobj());
+ Copied_symbol_dynobjs::const_iterator p =
+ this->copied_symbol_dynobjs_.find(sym);
+ gold_assert(p != this->copied_symbol_dynobjs_.end());
+ return p->second;
+}
+
+// Add any undefined symbols named on the command line.
+
+void
+Symbol_table::add_undefined_symbols_from_command_line(Layout* layout)
+{
+ if (parameters->options().any_undefined()
+ || layout->script_options()->any_unreferenced())
+ {
+ if (parameters->target().get_size() == 32)
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+ this->do_add_undefined_symbols_from_command_line<32>(layout);
+#else
+ gold_unreachable();
+#endif
+ }
+ else if (parameters->target().get_size() == 64)
+ {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+ this->do_add_undefined_symbols_from_command_line<64>(layout);
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ gold_unreachable();
+ }
+}
+
+template<int size>
+void
+Symbol_table::do_add_undefined_symbols_from_command_line(Layout* layout)
+{
+ for (options::String_set::const_iterator p =
+ parameters->options().undefined_begin();
+ p != parameters->options().undefined_end();
+ ++p)
+ this->add_undefined_symbol_from_command_line<size>(p->c_str());
+
+ for (options::String_set::const_iterator p =
+ parameters->options().export_dynamic_symbol_begin();
+ p != parameters->options().export_dynamic_symbol_end();
+ ++p)
+ this->add_undefined_symbol_from_command_line<size>(p->c_str());
+
+ for (Script_options::referenced_const_iterator p =
+ layout->script_options()->referenced_begin();
+ p != layout->script_options()->referenced_end();
+ ++p)
+ this->add_undefined_symbol_from_command_line<size>(p->c_str());
+}
+
+template<int size>
+void
+Symbol_table::add_undefined_symbol_from_command_line(const char* name)
+{
+ if (this->lookup(name) != NULL)
+ return;
+
+ const char* version = NULL;
+
+ Sized_symbol<size>* sym;
+ Sized_symbol<size>* oldsym;
+ bool resolve_oldsym;
+ if (parameters->target().is_big_endian())
+ {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
+ sym = this->define_special_symbol<size, true>(&name, &version,
+ false, &oldsym,
+ &resolve_oldsym);
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
+ sym = this->define_special_symbol<size, false>(&name, &version,
+ false, &oldsym,
+ &resolve_oldsym);
+#else
+ gold_unreachable();
+#endif
+ }
+
+ gold_assert(oldsym == NULL);
+
+ sym->init_undefined(name, version, elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
+ elfcpp::STV_DEFAULT, 0);
+ ++this->saw_undefined_;
+}
+
+// Set the dynamic symbol indexes. INDEX is the index of the first
+// global dynamic symbol. Pointers to the symbols are stored into the
+// vector SYMS. The names are added to DYNPOOL. This returns an
+// updated dynamic symbol index.
+
+unsigned int
+Symbol_table::set_dynsym_indexes(unsigned int index,
+ std::vector<Symbol*>* syms,
+ Stringpool* dynpool,
+ Versions* versions)
+{
+ std::vector<Symbol*> as_needed_sym;
+
+ for (Symbol_table_type::iterator p = this->table_.begin();
+ p != this->table_.end();
+ ++p)
+ {
+ Symbol* sym = p->second;
+
+ // Note that SYM may already have a dynamic symbol index, since
+ // some symbols appear more than once in the symbol table, with
+ // and without a version.
+
+ if (!sym->should_add_dynsym_entry(this))
+ sym->set_dynsym_index(-1U);
+ else if (!sym->has_dynsym_index())
+ {
+ sym->set_dynsym_index(index);
+ ++index;
+ syms->push_back(sym);
+ dynpool->add(sym->name(), false, NULL);
+
+ // If the symbol is defined in a dynamic object and is
+ // referenced strongly in a regular object, then mark the
+ // dynamic object as needed. This is used to implement
+ // --as-needed.
+ if (sym->is_from_dynobj()
+ && sym->in_reg()
+ && !sym->is_undef_binding_weak())
+ sym->object()->set_is_needed();
+
+ // Record any version information, except those from
+ // as-needed libraries not seen to be needed. Note that the
+ // is_needed state for such libraries can change in this loop.
+ if (sym->version() != NULL)
+ {
+ if (!sym->is_from_dynobj()
+ || !sym->object()->as_needed()
+ || sym->object()->is_needed())
+ versions->record_version(this, dynpool, sym);
+ else
+ as_needed_sym.push_back(sym);
+ }
+ }
+ }
+
+ // Process version information for symbols from as-needed libraries.
+ for (std::vector<Symbol*>::iterator p = as_needed_sym.begin();
+ p != as_needed_sym.end();
+ ++p)
+ {
+ Symbol* sym = *p;
+
+ if (sym->object()->is_needed())
+ versions->record_version(this, dynpool, sym);
+ else
+ sym->clear_version();
+ }
+
+ // Finish up the versions. In some cases this may add new dynamic
+ // symbols.
+ index = versions->finalize(this, index, syms);
+
+ return index;
+}
+
+// Set the final values for all the symbols. The index of the first
+// global symbol in the output file is *PLOCAL_SYMCOUNT. Record the
+// file offset OFF. Add their names to POOL. Return the new file
+// offset. Update *PLOCAL_SYMCOUNT if necessary.
+
+off_t
+Symbol_table::finalize(off_t off, off_t dynoff, size_t dyn_global_index,
+ size_t dyncount, Stringpool* pool,
+ unsigned int* plocal_symcount)
+{
+ off_t ret;
+
+ gold_assert(*plocal_symcount != 0);
+ this->first_global_index_ = *plocal_symcount;
+
+ this->dynamic_offset_ = dynoff;
+ this->first_dynamic_global_index_ = dyn_global_index;
+ this->dynamic_count_ = dyncount;
+
+ if (parameters->target().get_size() == 32)
+ {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_32_LITTLE)
+ ret = this->sized_finalize<32>(off, pool, plocal_symcount);
+#else
+ gold_unreachable();
+#endif
+ }
+ else if (parameters->target().get_size() == 64)
+ {
+#if defined(HAVE_TARGET_64_BIG) || defined(HAVE_TARGET_64_LITTLE)
+ ret = this->sized_finalize<64>(off, pool, plocal_symcount);
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ gold_unreachable();
+
+ // Now that we have the final symbol table, we can reliably note
+ // which symbols should get warnings.
+ this->warnings_.note_warnings(this);
+
+ return ret;
+}
+
+// SYM is going into the symbol table at *PINDEX. Add the name to
+// POOL, update *PINDEX and *POFF.
+
+template<int size>
+void
+Symbol_table::add_to_final_symtab(Symbol* sym, Stringpool* pool,
+ unsigned int* pindex, off_t* poff)
+{
+ sym->set_symtab_index(*pindex);
+ if (sym->version() == NULL || !parameters->options().relocatable())
+ pool->add(sym->name(), false, NULL);
+ else
+ pool->add(sym->versioned_name(), true, NULL);
+ ++*pindex;
+ *poff += elfcpp::Elf_sizes<size>::sym_size;
+}
+
+// Set the final value for all the symbols. This is called after
+// Layout::finalize, so all the output sections have their final
+// address.
+
+template<int size>
+off_t
+Symbol_table::sized_finalize(off_t off, Stringpool* pool,
+ unsigned int* plocal_symcount)
+{
+ off = align_address(off, size >> 3);
+ this->offset_ = off;
+
+ unsigned int index = *plocal_symcount;
+ const unsigned int orig_index = index;
+
+ // First do all the symbols which have been forced to be local, as
+ // they must appear before all global symbols.
+ for (Forced_locals::iterator p = this->forced_locals_.begin();
+ p != this->forced_locals_.end();
+ ++p)
+ {
+ Symbol* sym = *p;
+ gold_assert(sym->is_forced_local());
+ if (this->sized_finalize_symbol<size>(sym))
+ {
+ this->add_to_final_symtab<size>(sym, pool, &index, &off);
+ ++*plocal_symcount;
+ }
+ }
+
+ // Now do all the remaining symbols.
+ for (Symbol_table_type::iterator p = this->table_.begin();
+ p != this->table_.end();
+ ++p)
+ {
+ Symbol* sym = p->second;
+ if (this->sized_finalize_symbol<size>(sym))
+ this->add_to_final_symtab<size>(sym, pool, &index, &off);
+ }
+
+ this->output_count_ = index - orig_index;
+
+ return off;
+}
+
+// Compute the final value of SYM and store status in location PSTATUS.
+// During relaxation, this may be called multiple times for a symbol to
+// compute its would-be final value in each relaxation pass.
+
+template<int size>
+typename Sized_symbol<size>::Value_type
+Symbol_table::compute_final_value(
+ const Sized_symbol<size>* sym,
+ Compute_final_value_status* pstatus) const
+{
+ typedef typename Sized_symbol<size>::Value_type Value_type;
+ Value_type value;
+
+ switch (sym->source())
+ {
+ case Symbol::FROM_OBJECT:
+ {
+ bool is_ordinary;
+ unsigned int shndx = sym->shndx(&is_ordinary);
+
+ if (!is_ordinary
+ && shndx != elfcpp::SHN_ABS
+ && !Symbol::is_common_shndx(shndx))
+ {
+ *pstatus = CFVS_UNSUPPORTED_SYMBOL_SECTION;
+ return 0;
+ }
+
+ Object* symobj = sym->object();
+ if (symobj->is_dynamic())
+ {
+ value = 0;
+ shndx = elfcpp::SHN_UNDEF;
+ }
+ else if (symobj->pluginobj() != NULL)
+ {
+ value = 0;
+ shndx = elfcpp::SHN_UNDEF;
+ }
+ else if (shndx == elfcpp::SHN_UNDEF)
+ value = 0;
+ else if (!is_ordinary
+ && (shndx == elfcpp::SHN_ABS
+ || Symbol::is_common_shndx(shndx)))
+ value = sym->value();
+ else
+ {
+ Relobj* relobj = static_cast<Relobj*>(symobj);
+ Output_section* os = relobj->output_section(shndx);
+
+ if (this->is_section_folded(relobj, shndx))
+ {
+ gold_assert(os == NULL);
+ // Get the os of the section it is folded onto.
+ Section_id folded = this->icf_->get_folded_section(relobj,
+ shndx);
+ gold_assert(folded.first != NULL);
+ Relobj* folded_obj = reinterpret_cast<Relobj*>(folded.first);
+ unsigned folded_shndx = folded.second;
+
+ os = folded_obj->output_section(folded_shndx);
+ gold_assert(os != NULL);
+
+ // Replace (relobj, shndx) with canonical ICF input section.
+ shndx = folded_shndx;
+ relobj = folded_obj;
+ }
+
+ uint64_t secoff64 = relobj->output_section_offset(shndx);
+ if (os == NULL)
+ {
+ bool static_or_reloc = (parameters->doing_static_link() ||
+ parameters->options().relocatable());
+ gold_assert(static_or_reloc || sym->dynsym_index() == -1U);
+
+ *pstatus = CFVS_NO_OUTPUT_SECTION;
+ return 0;
+ }
+
+ if (secoff64 == -1ULL)
+ {
+ // The section needs special handling (e.g., a merge section).
+
+ value = os->output_address(relobj, shndx, sym->value());
+ }
+ else
+ {
+ Value_type secoff =
+ convert_types<Value_type, uint64_t>(secoff64);
+ if (sym->type() == elfcpp::STT_TLS)
+ value = sym->value() + os->tls_offset() + secoff;
+ else
+ value = sym->value() + os->address() + secoff;
+ }
+ }
+ }
+ break;
+
+ case Symbol::IN_OUTPUT_DATA:
+ {
+ Output_data* od = sym->output_data();
+ value = sym->value();
+ if (sym->type() != elfcpp::STT_TLS)
+ value += od->address();
+ else
+ {
+ Output_section* os = od->output_section();
+ gold_assert(os != NULL);
+ value += os->tls_offset() + (od->address() - os->address());
+ }
+ if (sym->offset_is_from_end())
+ value += od->data_size();
+ }
+ break;
+
+ case Symbol::IN_OUTPUT_SEGMENT:
+ {
+ Output_segment* os = sym->output_segment();
+ value = sym->value();
+ if (sym->type() != elfcpp::STT_TLS)
+ value += os->vaddr();
+ switch (sym->offset_base())
+ {
+ case Symbol::SEGMENT_START:
+ break;
+ case Symbol::SEGMENT_END:
+ value += os->memsz();
+ break;
+ case Symbol::SEGMENT_BSS:
+ value += os->filesz();
+ break;
+ default:
+ gold_unreachable();
+ }
+ }
+ break;
+
+ case Symbol::IS_CONSTANT:
+ value = sym->value();
+ break;
+
+ case Symbol::IS_UNDEFINED:
+ value = 0;
+ break;
+
+ default:
+ gold_unreachable();
+ }
+
+ *pstatus = CFVS_OK;
+ return value;
+}
+
+// Finalize the symbol SYM. This returns true if the symbol should be
+// added to the symbol table, false otherwise.
+
+template<int size>
+bool
+Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
+{
+ typedef typename Sized_symbol<size>::Value_type Value_type;
+
+ Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(unsized_sym);
+
+ // The default version of a symbol may appear twice in the symbol
+ // table. We only need to finalize it once.
+ if (sym->has_symtab_index())
+ return false;
+
+ if (!sym->in_reg())
+ {
+ gold_assert(!sym->has_symtab_index());
+ sym->set_symtab_index(-1U);
+ gold_assert(sym->dynsym_index() == -1U);
+ return false;
+ }
+
+ // If the symbol is only present on plugin files, the plugin decided we
+ // don't need it.
+ if (!sym->in_real_elf())
+ {
+ gold_assert(!sym->has_symtab_index());
+ sym->set_symtab_index(-1U);
+ return false;
+ }
+
+ // Compute final symbol value.
+ Compute_final_value_status status;
+ Value_type value = this->compute_final_value(sym, &status);
+
+ switch (status)
+ {
+ case CFVS_OK:
+ break;
+ case CFVS_UNSUPPORTED_SYMBOL_SECTION:
+ {
+ bool is_ordinary;
+ unsigned int shndx = sym->shndx(&is_ordinary);
+ gold_error(_("%s: unsupported symbol section 0x%x"),
+ sym->demangled_name().c_str(), shndx);
+ }
+ break;
+ case CFVS_NO_OUTPUT_SECTION:
+ sym->set_symtab_index(-1U);
+ return false;
+ default:
+ gold_unreachable();
+ }
+
+ sym->set_value(value);
+
+ if (parameters->options().strip_all()
+ || !parameters->options().should_retain_symbol(sym->name()))
+ {
+ sym->set_symtab_index(-1U);
+ return false;
+ }
+
+ return true;
+}
+
+// Write out the global symbols.
+
+void
+Symbol_table::write_globals(const Stringpool* sympool,
+ const Stringpool* dynpool,
+ Output_symtab_xindex* symtab_xindex,
+ Output_symtab_xindex* dynsym_xindex,
+ Output_file* of) const
+{
+ switch (parameters->size_and_endianness())
+ {
+#ifdef HAVE_TARGET_32_LITTLE
+ case Parameters::TARGET_32_LITTLE:
+ this->sized_write_globals<32, false>(sympool, dynpool, symtab_xindex,
+ dynsym_xindex, of);
+ break;
+#endif
+#ifdef HAVE_TARGET_32_BIG
+ case Parameters::TARGET_32_BIG:
+ this->sized_write_globals<32, true>(sympool, dynpool, symtab_xindex,
+ dynsym_xindex, of);
+ break;
+#endif
+#ifdef HAVE_TARGET_64_LITTLE
+ case Parameters::TARGET_64_LITTLE:
+ this->sized_write_globals<64, false>(sympool, dynpool, symtab_xindex,
+ dynsym_xindex, of);
+ break;
+#endif
+#ifdef HAVE_TARGET_64_BIG
+ case Parameters::TARGET_64_BIG:
+ this->sized_write_globals<64, true>(sympool, dynpool, symtab_xindex,
+ dynsym_xindex, of);
+ break;
+#endif
+ default:
+ gold_unreachable();
+ }
+}
+
+// Write out the global symbols.
+
+template<int size, bool big_endian>
+void
+Symbol_table::sized_write_globals(const Stringpool* sympool,
+ const Stringpool* dynpool,
+ Output_symtab_xindex* symtab_xindex,
+ Output_symtab_xindex* dynsym_xindex,
+ Output_file* of) const
+{
+ const Target& target = parameters->target();
+
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+ const unsigned int output_count = this->output_count_;
+ const section_size_type oview_size = output_count * sym_size;
+ const unsigned int first_global_index = this->first_global_index_;
+ unsigned char* psyms;
+ if (this->offset_ == 0 || output_count == 0)
+ psyms = NULL;
+ else
+ psyms = of->get_output_view(this->offset_, oview_size);
+
+ const unsigned int dynamic_count = this->dynamic_count_;
+ const section_size_type dynamic_size = dynamic_count * sym_size;
+ const unsigned int first_dynamic_global_index =
+ this->first_dynamic_global_index_;
+ unsigned char* dynamic_view;
+ if (this->dynamic_offset_ == 0 || dynamic_count == 0)
+ dynamic_view = NULL;
+ else
+ dynamic_view = of->get_output_view(this->dynamic_offset_, dynamic_size);
+
+ for (Symbol_table_type::const_iterator p = this->table_.begin();
+ p != this->table_.end();
+ ++p)
+ {
+ Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
+
+ // Possibly warn about unresolved symbols in shared libraries.
+ this->warn_about_undefined_dynobj_symbol(sym);
+
+ unsigned int sym_index = sym->symtab_index();
+ unsigned int dynsym_index;
+ if (dynamic_view == NULL)
+ dynsym_index = -1U;
+ else
+ dynsym_index = sym->dynsym_index();
+
+ if (sym_index == -1U && dynsym_index == -1U)
+ {
+ // This symbol is not included in the output file.
+ continue;
+ }
+
+ unsigned int shndx;
+ typename elfcpp::Elf_types<size>::Elf_Addr sym_value = sym->value();
+ typename elfcpp::Elf_types<size>::Elf_Addr dynsym_value = sym_value;
+ elfcpp::STB binding = sym->binding();
+
+ // If --no-gnu-unique is set, change STB_GNU_UNIQUE to STB_GLOBAL.
+ if (binding == elfcpp::STB_GNU_UNIQUE
+ && !parameters->options().gnu_unique())
+ binding = elfcpp::STB_GLOBAL;
+
+ switch (sym->source())
+ {
+ case Symbol::FROM_OBJECT:
+ {
+ bool is_ordinary;
+ unsigned int in_shndx = sym->shndx(&is_ordinary);
+
+ if (!is_ordinary
+ && in_shndx != elfcpp::SHN_ABS
+ && !Symbol::is_common_shndx(in_shndx))
+ {
+ gold_error(_("%s: unsupported symbol section 0x%x"),
+ sym->demangled_name().c_str(), in_shndx);
+ shndx = in_shndx;
+ }
+ else
+ {
+ Object* symobj = sym->object();
+ if (symobj->is_dynamic())
+ {
+ if (sym->needs_dynsym_value())
+ dynsym_value = target.dynsym_value(sym);
+ shndx = elfcpp::SHN_UNDEF;
+ if (sym->is_undef_binding_weak())
+ binding = elfcpp::STB_WEAK;
+ else
+ binding = elfcpp::STB_GLOBAL;
+ }
+ else if (symobj->pluginobj() != NULL)
+ shndx = elfcpp::SHN_UNDEF;
+ else if (in_shndx == elfcpp::SHN_UNDEF
+ || (!is_ordinary
+ && (in_shndx == elfcpp::SHN_ABS
+ || Symbol::is_common_shndx(in_shndx))))
+ shndx = in_shndx;
+ else
+ {
+ Relobj* relobj = static_cast<Relobj*>(symobj);
+ Output_section* os = relobj->output_section(in_shndx);
+ if (this->is_section_folded(relobj, in_shndx))
+ {
+ // This global symbol must be written out even though
+ // it is folded.
+ // Get the os of the section it is folded onto.
+ Section_id folded =
+ this->icf_->get_folded_section(relobj, in_shndx);
+ gold_assert(folded.first !=NULL);
+ Relobj* folded_obj =
+ reinterpret_cast<Relobj*>(folded.first);
+ os = folded_obj->output_section(folded.second);
+ gold_assert(os != NULL);
+ }
+ gold_assert(os != NULL);
+ shndx = os->out_shndx();
+
+ if (shndx >= elfcpp::SHN_LORESERVE)
+ {
+ if (sym_index != -1U)
+ symtab_xindex->add(sym_index, shndx);
+ if (dynsym_index != -1U)
+ dynsym_xindex->add(dynsym_index, shndx);
+ shndx = elfcpp::SHN_XINDEX;
+ }
+
+ // In object files symbol values are section
+ // relative.
+ if (parameters->options().relocatable())
+ sym_value -= os->address();
+ }
+ }
+ }
+ break;
+
+ case Symbol::IN_OUTPUT_DATA:
+ {
+ Output_data* od = sym->output_data();
+
+ shndx = od->out_shndx();
+ if (shndx >= elfcpp::SHN_LORESERVE)
+ {
+ if (sym_index != -1U)
+ symtab_xindex->add(sym_index, shndx);
+ if (dynsym_index != -1U)
+ dynsym_xindex->add(dynsym_index, shndx);
+ shndx = elfcpp::SHN_XINDEX;
+ }
+
+ // In object files symbol values are section
+ // relative.
+ if (parameters->options().relocatable())
+ sym_value -= od->address();
+ }
+ break;
+
+ case Symbol::IN_OUTPUT_SEGMENT:
+ shndx = elfcpp::SHN_ABS;
+ break;
+
+ case Symbol::IS_CONSTANT:
+ shndx = elfcpp::SHN_ABS;
+ break;
+
+ case Symbol::IS_UNDEFINED:
+ shndx = elfcpp::SHN_UNDEF;
+ break;
+
+ default:
+ gold_unreachable();
+ }
+
+ if (sym_index != -1U)
+ {
+ sym_index -= first_global_index;
+ gold_assert(sym_index < output_count);
+ unsigned char* ps = psyms + (sym_index * sym_size);
+ this->sized_write_symbol<size, big_endian>(sym, sym_value, shndx,
+ binding, sympool, ps);
+ }
+
+ if (dynsym_index != -1U)
+ {
+ dynsym_index -= first_dynamic_global_index;
+ gold_assert(dynsym_index < dynamic_count);
+ unsigned char* pd = dynamic_view + (dynsym_index * sym_size);
+ this->sized_write_symbol<size, big_endian>(sym, dynsym_value, shndx,
+ binding, dynpool, pd);
+ }
+ }
+
+ of->write_output_view(this->offset_, oview_size, psyms);
+ if (dynamic_view != NULL)
+ of->write_output_view(this->dynamic_offset_, dynamic_size, dynamic_view);
+}
+
+// Write out the symbol SYM, in section SHNDX, to P. POOL is the
+// strtab holding the name.
+
+template<int size, bool big_endian>
+void
+Symbol_table::sized_write_symbol(
+ Sized_symbol<size>* sym,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ unsigned int shndx,
+ elfcpp::STB binding,
+ const Stringpool* pool,
+ unsigned char* p) const
+{
+ elfcpp::Sym_write<size, big_endian> osym(p);
+ if (sym->version() == NULL || !parameters->options().relocatable())
+ osym.put_st_name(pool->get_offset(sym->name()));
+ else
+ osym.put_st_name(pool->get_offset(sym->versioned_name()));
+ osym.put_st_value(value);
+ // Use a symbol size of zero for undefined symbols from shared libraries.
+ if (shndx == elfcpp::SHN_UNDEF && sym->is_from_dynobj())
+ osym.put_st_size(0);
+ else
+ osym.put_st_size(sym->symsize());
+ elfcpp::STT type = sym->type();
+ // Turn IFUNC symbols from shared libraries into normal FUNC symbols.
+ if (type == elfcpp::STT_GNU_IFUNC
+ && sym->is_from_dynobj())
+ type = elfcpp::STT_FUNC;
+ // A version script may have overridden the default binding.
+ if (sym->is_forced_local())
+ osym.put_st_info(elfcpp::elf_st_info(elfcpp::STB_LOCAL, type));
+ else
+ osym.put_st_info(elfcpp::elf_st_info(binding, type));
+ osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->nonvis()));
+ osym.put_st_shndx(shndx);
+}
+
+// Check for unresolved symbols in shared libraries. This is
+// controlled by the --allow-shlib-undefined option.
+
+// We only warn about libraries for which we have seen all the
+// DT_NEEDED entries. We don't try to track down DT_NEEDED entries
+// which were not seen in this link. If we didn't see a DT_NEEDED
+// entry, we aren't going to be able to reliably report whether the
+// symbol is undefined.
+
+// We also don't warn about libraries found in a system library
+// directory (e.g., /lib or /usr/lib); we assume that those libraries
+// are OK. This heuristic avoids problems on GNU/Linux, in which -ldl
+// can have undefined references satisfied by ld-linux.so.
+
+inline void
+Symbol_table::warn_about_undefined_dynobj_symbol(Symbol* sym) const
+{
+ bool dummy;
+ if (sym->source() == Symbol::FROM_OBJECT
+ && sym->object()->is_dynamic()
+ && sym->shndx(&dummy) == elfcpp::SHN_UNDEF
+ && sym->binding() != elfcpp::STB_WEAK
+ && !parameters->options().allow_shlib_undefined()
+ && !parameters->target().is_defined_by_abi(sym)
+ && !sym->object()->is_in_system_directory())
+ {
+ // A very ugly cast.
+ Dynobj* dynobj = static_cast<Dynobj*>(sym->object());
+ if (!dynobj->has_unknown_needed_entries())
+ gold_undefined_symbol(sym);
+ }
+}
+
+// Write out a section symbol. Return the update offset.
+
+void
+Symbol_table::write_section_symbol(const Output_section* os,
+ Output_symtab_xindex* symtab_xindex,
+ Output_file* of,
+ off_t offset) const
+{
+ switch (parameters->size_and_endianness())
+ {
+#ifdef HAVE_TARGET_32_LITTLE
+ case Parameters::TARGET_32_LITTLE:
+ this->sized_write_section_symbol<32, false>(os, symtab_xindex, of,
+ offset);
+ break;
+#endif
+#ifdef HAVE_TARGET_32_BIG
+ case Parameters::TARGET_32_BIG:
+ this->sized_write_section_symbol<32, true>(os, symtab_xindex, of,
+ offset);
+ break;
+#endif
+#ifdef HAVE_TARGET_64_LITTLE
+ case Parameters::TARGET_64_LITTLE:
+ this->sized_write_section_symbol<64, false>(os, symtab_xindex, of,
+ offset);
+ break;
+#endif
+#ifdef HAVE_TARGET_64_BIG
+ case Parameters::TARGET_64_BIG:
+ this->sized_write_section_symbol<64, true>(os, symtab_xindex, of,
+ offset);
+ break;
+#endif
+ default:
+ gold_unreachable();
+ }
+}
+
+// Write out a section symbol, specialized for size and endianness.
+
+template<int size, bool big_endian>
+void
+Symbol_table::sized_write_section_symbol(const Output_section* os,
+ Output_symtab_xindex* symtab_xindex,
+ Output_file* of,
+ off_t offset) const
+{
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+ unsigned char* pov = of->get_output_view(offset, sym_size);
+
+ elfcpp::Sym_write<size, big_endian> osym(pov);
+ osym.put_st_name(0);
+ if (parameters->options().relocatable())
+ osym.put_st_value(0);
+ else
+ osym.put_st_value(os->address());
+ osym.put_st_size(0);
+ osym.put_st_info(elfcpp::elf_st_info(elfcpp::STB_LOCAL,
+ elfcpp::STT_SECTION));
+ osym.put_st_other(elfcpp::elf_st_other(elfcpp::STV_DEFAULT, 0));
+
+ unsigned int shndx = os->out_shndx();
+ if (shndx >= elfcpp::SHN_LORESERVE)
+ {
+ symtab_xindex->add(os->symtab_index(), shndx);
+ shndx = elfcpp::SHN_XINDEX;
+ }
+ osym.put_st_shndx(shndx);
+
+ of->write_output_view(offset, sym_size, pov);
+}
+
+// Print statistical information to stderr. This is used for --stats.
+
+void
+Symbol_table::print_stats() const
+{
+#if defined(HAVE_TR1_UNORDERED_MAP) || defined(HAVE_EXT_HASH_MAP)
+ fprintf(stderr, _("%s: symbol table entries: %zu; buckets: %zu\n"),
+ program_name, this->table_.size(), this->table_.bucket_count());
+#else
+ fprintf(stderr, _("%s: symbol table entries: %zu\n"),
+ program_name, this->table_.size());
+#endif
+ this->namepool_.print_stats("symbol table stringpool");
+}
+
+// We check for ODR violations by looking for symbols with the same
+// name for which the debugging information reports that they were
+// defined in disjoint source locations. When comparing the source
+// location, we consider instances with the same base filename to be
+// the same. This is because different object files/shared libraries
+// can include the same header file using different paths, and
+// different optimization settings can make the line number appear to
+// be a couple lines off, and we don't want to report an ODR violation
+// in those cases.
+
+// This struct is used to compare line information, as returned by
+// Dwarf_line_info::one_addr2line. It implements a < comparison
+// operator used with std::sort.
+
+struct Odr_violation_compare
+{
+ bool
+ operator()(const std::string& s1, const std::string& s2) const
+ {
+ // Inputs should be of the form "dirname/filename:linenum" where
+ // "dirname/" is optional. We want to compare just the filename:linenum.
+
+ // Find the last '/' in each string.
+ std::string::size_type s1begin = s1.rfind('/');
+ std::string::size_type s2begin = s2.rfind('/');
+ // If there was no '/' in a string, start at the beginning.
+ if (s1begin == std::string::npos)
+ s1begin = 0;
+ if (s2begin == std::string::npos)
+ s2begin = 0;
+ return s1.compare(s1begin, std::string::npos,
+ s2, s2begin, std::string::npos) < 0;
+ }
+};
+
+// Returns all of the lines attached to LOC, not just the one the
+// instruction actually came from.
+std::vector<std::string>
+Symbol_table::linenos_from_loc(const Task* task,
+ const Symbol_location& loc)
+{
+ // We need to lock the object in order to read it. This
+ // means that we have to run in a singleton Task. If we
+ // want to run this in a general Task for better
+ // performance, we will need one Task for object, plus
+ // appropriate locking to ensure that we don't conflict with
+ // other uses of the object. Also note, one_addr2line is not
+ // currently thread-safe.
+ Task_lock_obj<Object> tl(task, loc.object);
+
+ std::vector<std::string> result;
+ Symbol_location code_loc = loc;
+ parameters->target().function_location(&code_loc);
+ // 16 is the size of the object-cache that one_addr2line should use.
+ std::string canonical_result = Dwarf_line_info::one_addr2line(
+ code_loc.object, code_loc.shndx, code_loc.offset, 16, &result);
+ if (!canonical_result.empty())
+ result.push_back(canonical_result);
+ return result;
+}
+
+// OutputIterator that records if it was ever assigned to. This
+// allows it to be used with std::set_intersection() to check for
+// intersection rather than computing the intersection.
+struct Check_intersection
+{
+ Check_intersection()
+ : value_(false)
+ {}
+
+ bool had_intersection() const
+ { return this->value_; }
+
+ Check_intersection& operator++()
+ { return *this; }
+
+ Check_intersection& operator*()
+ { return *this; }
+
+ template<typename T>
+ Check_intersection& operator=(const T&)
+ {
+ this->value_ = true;
+ return *this;
+ }
+
+ private:
+ bool value_;
+};
+
+// Check candidate_odr_violations_ to find symbols with the same name
+// but apparently different definitions (different source-file/line-no
+// for each line assigned to the first instruction).
+
+void
+Symbol_table::detect_odr_violations(const Task* task,
+ const char* output_file_name) const
+{
+ for (Odr_map::const_iterator it = candidate_odr_violations_.begin();
+ it != candidate_odr_violations_.end();
+ ++it)
+ {
+ const char* const symbol_name = it->first;
+
+ std::string first_object_name;
+ std::vector<std::string> first_object_linenos;
+
+ Unordered_set<Symbol_location, Symbol_location_hash>::const_iterator
+ locs = it->second.begin();
+ const Unordered_set<Symbol_location, Symbol_location_hash>::const_iterator
+ locs_end = it->second.end();
+ for (; locs != locs_end && first_object_linenos.empty(); ++locs)
+ {
+ // Save the line numbers from the first definition to
+ // compare to the other definitions. Ideally, we'd compare
+ // every definition to every other, but we don't want to
+ // take O(N^2) time to do this. This shortcut may cause
+ // false negatives that appear or disappear depending on the
+ // link order, but it won't cause false positives.
+ first_object_name = locs->object->name();
+ first_object_linenos = this->linenos_from_loc(task, *locs);
+ }
+
+ // Sort by Odr_violation_compare to make std::set_intersection work.
+ std::sort(first_object_linenos.begin(), first_object_linenos.end(),
+ Odr_violation_compare());
+
+ for (; locs != locs_end; ++locs)
+ {
+ std::vector<std::string> linenos =
+ this->linenos_from_loc(task, *locs);
+ // linenos will be empty if we couldn't parse the debug info.
+ if (linenos.empty())
+ continue;
+ // Sort by Odr_violation_compare to make std::set_intersection work.
+ std::sort(linenos.begin(), linenos.end(), Odr_violation_compare());
+
+ Check_intersection intersection_result =
+ std::set_intersection(first_object_linenos.begin(),
+ first_object_linenos.end(),
+ linenos.begin(),
+ linenos.end(),
+ Check_intersection(),
+ Odr_violation_compare());
+ if (!intersection_result.had_intersection())
+ {
+ gold_warning(_("while linking %s: symbol '%s' defined in "
+ "multiple places (possible ODR violation):"),
+ output_file_name, demangle(symbol_name).c_str());
+ // This only prints one location from each definition,
+ // which may not be the location we expect to intersect
+ // with another definition. We could print the whole
+ // set of locations, but that seems too verbose.
+ gold_assert(!first_object_linenos.empty());
+ gold_assert(!linenos.empty());
+ fprintf(stderr, _(" %s from %s\n"),
+ first_object_linenos[0].c_str(),
+ first_object_name.c_str());
+ fprintf(stderr, _(" %s from %s\n"),
+ linenos[0].c_str(),
+ locs->object->name().c_str());
+ // Only print one broken pair, to avoid needing to
+ // compare against a list of the disjoint definition
+ // locations we've found so far. (If we kept comparing
+ // against just the first one, we'd get a lot of
+ // redundant complaints about the second definition
+ // location.)
+ break;
+ }
+ }
+ }
+ // We only call one_addr2line() in this function, so we can clear its cache.
+ Dwarf_line_info::clear_addr2line_cache();
+}
+
+// Warnings functions.
+
+// Add a new warning.
+
+void
+Warnings::add_warning(Symbol_table* symtab, const char* name, Object* obj,
+ const std::string& warning)
+{
+ name = symtab->canonicalize_name(name);
+ this->warnings_[name].set(obj, warning);
+}
+
+// Look through the warnings and mark the symbols for which we should
+// warn. This is called during Layout::finalize when we know the
+// sources for all the symbols.
+
+void
+Warnings::note_warnings(Symbol_table* symtab)
+{
+ for (Warning_table::iterator p = this->warnings_.begin();
+ p != this->warnings_.end();
+ ++p)
+ {
+ Symbol* sym = symtab->lookup(p->first, NULL);
+ if (sym != NULL
+ && sym->source() == Symbol::FROM_OBJECT
+ && sym->object() == p->second.object)
+ sym->set_has_warning();
+ }
+}
+
+// Issue a warning. This is called when we see a relocation against a
+// symbol for which has a warning.
+
+template<int size, bool big_endian>
+void
+Warnings::issue_warning(const Symbol* sym,
+ const Relocate_info<size, big_endian>* relinfo,
+ size_t relnum, off_t reloffset) const
+{
+ gold_assert(sym->has_warning());
+
+ // We don't want to issue a warning for a relocation against the
+ // symbol in the same object file in which the symbol is defined.
+ if (sym->object() == relinfo->object)
+ return;
+
+ Warning_table::const_iterator p = this->warnings_.find(sym->name());
+ gold_assert(p != this->warnings_.end());
+ gold_warning_at_location(relinfo, relnum, reloffset,
+ "%s", p->second.text.c_str());
+}
+
+// Instantiate the templates we need. We could use the configure
+// script to restrict this to only the ones needed for implemented
+// targets.
+
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+template
+void
+Sized_symbol<32>::allocate_common(Output_data*, Value_type);
+#endif
+
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+template
+void
+Sized_symbol<64>::allocate_common(Output_data*, Value_type);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+void
+Symbol_table::add_from_relobj<32, false>(
+ Sized_relobj_file<32, false>* relobj,
+ const unsigned char* syms,
+ size_t count,
+ size_t symndx_offset,
+ const char* sym_names,
+ size_t sym_name_size,
+ Sized_relobj_file<32, false>::Symbols* sympointers,
+ size_t* defined);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+void
+Symbol_table::add_from_relobj<32, true>(
+ Sized_relobj_file<32, true>* relobj,
+ const unsigned char* syms,
+ size_t count,
+ size_t symndx_offset,
+ const char* sym_names,
+ size_t sym_name_size,
+ Sized_relobj_file<32, true>::Symbols* sympointers,
+ size_t* defined);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+void
+Symbol_table::add_from_relobj<64, false>(
+ Sized_relobj_file<64, false>* relobj,
+ const unsigned char* syms,
+ size_t count,
+ size_t symndx_offset,
+ const char* sym_names,
+ size_t sym_name_size,
+ Sized_relobj_file<64, false>::Symbols* sympointers,
+ size_t* defined);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+void
+Symbol_table::add_from_relobj<64, true>(
+ Sized_relobj_file<64, true>* relobj,
+ const unsigned char* syms,
+ size_t count,
+ size_t symndx_offset,
+ const char* sym_names,
+ size_t sym_name_size,
+ Sized_relobj_file<64, true>::Symbols* sympointers,
+ size_t* defined);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+Symbol*
+Symbol_table::add_from_pluginobj<32, false>(
+ Sized_pluginobj<32, false>* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<32, false>* sym);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+Symbol*
+Symbol_table::add_from_pluginobj<32, true>(
+ Sized_pluginobj<32, true>* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<32, true>* sym);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+Symbol*
+Symbol_table::add_from_pluginobj<64, false>(
+ Sized_pluginobj<64, false>* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<64, false>* sym);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+Symbol*
+Symbol_table::add_from_pluginobj<64, true>(
+ Sized_pluginobj<64, true>* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<64, true>* sym);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+void
+Symbol_table::add_from_dynobj<32, false>(
+ Sized_dynobj<32, false>* dynobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ const unsigned char* versym,
+ size_t versym_size,
+ const std::vector<const char*>* version_map,
+ Sized_relobj_file<32, false>::Symbols* sympointers,
+ size_t* defined);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+void
+Symbol_table::add_from_dynobj<32, true>(
+ Sized_dynobj<32, true>* dynobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ const unsigned char* versym,
+ size_t versym_size,
+ const std::vector<const char*>* version_map,
+ Sized_relobj_file<32, true>::Symbols* sympointers,
+ size_t* defined);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+void
+Symbol_table::add_from_dynobj<64, false>(
+ Sized_dynobj<64, false>* dynobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ const unsigned char* versym,
+ size_t versym_size,
+ const std::vector<const char*>* version_map,
+ Sized_relobj_file<64, false>::Symbols* sympointers,
+ size_t* defined);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+void
+Symbol_table::add_from_dynobj<64, true>(
+ Sized_dynobj<64, true>* dynobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ const unsigned char* versym,
+ size_t versym_size,
+ const std::vector<const char*>* version_map,
+ Sized_relobj_file<64, true>::Symbols* sympointers,
+ size_t* defined);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+Sized_symbol<32>*
+Symbol_table::add_from_incrobj(
+ Object* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<32, false>* sym);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+Sized_symbol<32>*
+Symbol_table::add_from_incrobj(
+ Object* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<32, true>* sym);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+Sized_symbol<64>*
+Symbol_table::add_from_incrobj(
+ Object* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<64, false>* sym);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+Sized_symbol<64>*
+Symbol_table::add_from_incrobj(
+ Object* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<64, true>* sym);
+#endif
+
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+template
+void
+Symbol_table::define_with_copy_reloc<32>(
+ Sized_symbol<32>* sym,
+ Output_data* posd,
+ elfcpp::Elf_types<32>::Elf_Addr value);
+#endif
+
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+template
+void
+Symbol_table::define_with_copy_reloc<64>(
+ Sized_symbol<64>* sym,
+ Output_data* posd,
+ elfcpp::Elf_types<64>::Elf_Addr value);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+void
+Warnings::issue_warning<32, false>(const Symbol* sym,
+ const Relocate_info<32, false>* relinfo,
+ size_t relnum, off_t reloffset) const;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+void
+Warnings::issue_warning<32, true>(const Symbol* sym,
+ const Relocate_info<32, true>* relinfo,
+ size_t relnum, off_t reloffset) const;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+void
+Warnings::issue_warning<64, false>(const Symbol* sym,
+ const Relocate_info<64, false>* relinfo,
+ size_t relnum, off_t reloffset) const;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+void
+Warnings::issue_warning<64, true>(const Symbol* sym,
+ const Relocate_info<64, true>* relinfo,
+ size_t relnum, off_t reloffset) const;
+#endif
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/symtab.h b/binutils-2.25/gold/symtab.h
new file mode 100644
index 00000000..9299ea8a
--- /dev/null
+++ b/binutils-2.25/gold/symtab.h
@@ -0,0 +1,1927 @@
+// symtab.h -- the gold symbol table -*- C++ -*-
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+// Symbol_table
+// The symbol table.
+
+#ifndef GOLD_SYMTAB_H
+#define GOLD_SYMTAB_H
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "elfcpp.h"
+#include "parameters.h"
+#include "stringpool.h"
+#include "object.h"
+
+namespace gold
+{
+
+class Mapfile;
+class Object;
+class Relobj;
+template<int size, bool big_endian>
+class Sized_relobj_file;
+template<int size, bool big_endian>
+class Sized_pluginobj;
+class Dynobj;
+template<int size, bool big_endian>
+class Sized_dynobj;
+template<int size, bool big_endian>
+class Sized_incrobj;
+class Versions;
+class Version_script_info;
+class Input_objects;
+class Output_data;
+class Output_section;
+class Output_segment;
+class Output_file;
+class Output_symtab_xindex;
+class Garbage_collection;
+class Icf;
+
+// The base class of an entry in the symbol table. The symbol table
+// can have a lot of entries, so we don't want this class too big.
+// Size dependent fields can be found in the template class
+// Sized_symbol. Targets may support their own derived classes.
+
+class Symbol
+{
+ public:
+ // Because we want the class to be small, we don't use any virtual
+ // functions. But because symbols can be defined in different
+ // places, we need to classify them. This enum is the different
+ // sources of symbols we support.
+ enum Source
+ {
+ // Symbol defined in a relocatable or dynamic input file--this is
+ // the most common case.
+ FROM_OBJECT,
+ // Symbol defined in an Output_data, a special section created by
+ // the target.
+ IN_OUTPUT_DATA,
+ // Symbol defined in an Output_segment, with no associated
+ // section.
+ IN_OUTPUT_SEGMENT,
+ // Symbol value is constant.
+ IS_CONSTANT,
+ // Symbol is undefined.
+ IS_UNDEFINED
+ };
+
+ // When the source is IN_OUTPUT_SEGMENT, we need to describe what
+ // the offset means.
+ enum Segment_offset_base
+ {
+ // From the start of the segment.
+ SEGMENT_START,
+ // From the end of the segment.
+ SEGMENT_END,
+ // From the filesz of the segment--i.e., after the loaded bytes
+ // but before the bytes which are allocated but zeroed.
+ SEGMENT_BSS
+ };
+
+ // Return the symbol name.
+ const char*
+ name() const
+ { return this->name_; }
+
+ // Return the (ANSI) demangled version of the name, if
+ // parameters.demangle() is true. Otherwise, return the name. This
+ // is intended to be used only for logging errors, so it's not
+ // super-efficient.
+ std::string
+ demangled_name() const;
+
+ // Return the symbol version. This will return NULL for an
+ // unversioned symbol.
+ const char*
+ version() const
+ { return this->version_; }
+
+ void
+ clear_version()
+ { this->version_ = NULL; }
+
+ // Return whether this version is the default for this symbol name
+ // (eg, "foo@@V2" is a default version; "foo@V1" is not). Only
+ // meaningful for versioned symbols.
+ bool
+ is_default() const
+ {
+ gold_assert(this->version_ != NULL);
+ return this->is_def_;
+ }
+
+ // Set that this version is the default for this symbol name.
+ void
+ set_is_default()
+ { this->is_def_ = true; }
+
+ // Return the symbol's name as name@version (or name@@version).
+ std::string
+ versioned_name() const;
+
+ // Return the symbol source.
+ Source
+ source() const
+ { return this->source_; }
+
+ // Return the object with which this symbol is associated.
+ Object*
+ object() const
+ {
+ gold_assert(this->source_ == FROM_OBJECT);
+ return this->u_.from_object.object;
+ }
+
+ // Return the index of the section in the input relocatable or
+ // dynamic object file.
+ unsigned int
+ shndx(bool* is_ordinary) const
+ {
+ gold_assert(this->source_ == FROM_OBJECT);
+ *is_ordinary = this->is_ordinary_shndx_;
+ return this->u_.from_object.shndx;
+ }
+
+ // Return the output data section with which this symbol is
+ // associated, if the symbol was specially defined with respect to
+ // an output data section.
+ Output_data*
+ output_data() const
+ {
+ gold_assert(this->source_ == IN_OUTPUT_DATA);
+ return this->u_.in_output_data.output_data;
+ }
+
+ // If this symbol was defined with respect to an output data
+ // section, return whether the value is an offset from end.
+ bool
+ offset_is_from_end() const
+ {
+ gold_assert(this->source_ == IN_OUTPUT_DATA);
+ return this->u_.in_output_data.offset_is_from_end;
+ }
+
+ // Return the output segment with which this symbol is associated,
+ // if the symbol was specially defined with respect to an output
+ // segment.
+ Output_segment*
+ output_segment() const
+ {
+ gold_assert(this->source_ == IN_OUTPUT_SEGMENT);
+ return this->u_.in_output_segment.output_segment;
+ }
+
+ // If this symbol was defined with respect to an output segment,
+ // return the offset base.
+ Segment_offset_base
+ offset_base() const
+ {
+ gold_assert(this->source_ == IN_OUTPUT_SEGMENT);
+ return this->u_.in_output_segment.offset_base;
+ }
+
+ // Return the symbol binding.
+ elfcpp::STB
+ binding() const
+ { return this->binding_; }
+
+ // Return the symbol type.
+ elfcpp::STT
+ type() const
+ { return this->type_; }
+
+ // Return true for function symbol.
+ bool
+ is_func() const
+ {
+ return (this->type_ == elfcpp::STT_FUNC
+ || this->type_ == elfcpp::STT_GNU_IFUNC);
+ }
+
+ // Return the symbol visibility.
+ elfcpp::STV
+ visibility() const
+ { return this->visibility_; }
+
+ // Set the visibility.
+ void
+ set_visibility(elfcpp::STV visibility)
+ { this->visibility_ = visibility; }
+
+ // Override symbol visibility.
+ void
+ override_visibility(elfcpp::STV);
+
+ // Set whether the symbol was originally a weak undef or a regular undef
+ // when resolved by a dynamic def.
+ inline void
+ set_undef_binding(elfcpp::STB bind)
+ {
+ if (!this->undef_binding_set_ || this->undef_binding_weak_)
+ {
+ this->undef_binding_weak_ = bind == elfcpp::STB_WEAK;
+ this->undef_binding_set_ = true;
+ }
+ }
+
+ // Return TRUE if a weak undef was resolved by a dynamic def.
+ inline bool
+ is_undef_binding_weak() const
+ { return this->undef_binding_weak_; }
+
+ // Return the non-visibility part of the st_other field.
+ unsigned char
+ nonvis() const
+ { return this->nonvis_; }
+
+ // Return whether this symbol is a forwarder. This will never be
+ // true of a symbol found in the hash table, but may be true of
+ // symbol pointers attached to object files.
+ bool
+ is_forwarder() const
+ { return this->is_forwarder_; }
+
+ // Mark this symbol as a forwarder.
+ void
+ set_forwarder()
+ { this->is_forwarder_ = true; }
+
+ // Return whether this symbol has an alias in the weak aliases table
+ // in Symbol_table.
+ bool
+ has_alias() const
+ { return this->has_alias_; }
+
+ // Mark this symbol as having an alias.
+ void
+ set_has_alias()
+ { this->has_alias_ = true; }
+
+ // Return whether this symbol needs an entry in the dynamic symbol
+ // table.
+ bool
+ needs_dynsym_entry() const
+ {
+ return (this->needs_dynsym_entry_
+ || (this->in_reg()
+ && this->in_dyn()
+ && this->is_externally_visible()));
+ }
+
+ // Mark this symbol as needing an entry in the dynamic symbol table.
+ void
+ set_needs_dynsym_entry()
+ { this->needs_dynsym_entry_ = true; }
+
+ // Return whether this symbol should be added to the dynamic symbol
+ // table.
+ bool
+ should_add_dynsym_entry(Symbol_table*) const;
+
+ // Return whether this symbol has been seen in a regular object.
+ bool
+ in_reg() const
+ { return this->in_reg_; }
+
+ // Mark this symbol as having been seen in a regular object.
+ void
+ set_in_reg()
+ { this->in_reg_ = true; }
+
+ // Return whether this symbol has been seen in a dynamic object.
+ bool
+ in_dyn() const
+ { return this->in_dyn_; }
+
+ // Mark this symbol as having been seen in a dynamic object.
+ void
+ set_in_dyn()
+ { this->in_dyn_ = true; }
+
+ // Return whether this symbol has been seen in a real ELF object.
+ // (IN_REG will return TRUE if the symbol has been seen in either
+ // a real ELF object or an object claimed by a plugin.)
+ bool
+ in_real_elf() const
+ { return this->in_real_elf_; }
+
+ // Mark this symbol as having been seen in a real ELF object.
+ void
+ set_in_real_elf()
+ { this->in_real_elf_ = true; }
+
+ // Return whether this symbol was defined in a section that was
+ // discarded from the link. This is used to control some error
+ // reporting.
+ bool
+ is_defined_in_discarded_section() const
+ { return this->is_defined_in_discarded_section_; }
+
+ // Mark this symbol as having been defined in a discarded section.
+ void
+ set_is_defined_in_discarded_section()
+ { this->is_defined_in_discarded_section_ = true; }
+
+ // Return the index of this symbol in the output file symbol table.
+ // A value of -1U means that this symbol is not going into the
+ // output file. This starts out as zero, and is set to a non-zero
+ // value by Symbol_table::finalize. It is an error to ask for the
+ // symbol table index before it has been set.
+ unsigned int
+ symtab_index() const
+ {
+ gold_assert(this->symtab_index_ != 0);
+ return this->symtab_index_;
+ }
+
+ // Set the index of the symbol in the output file symbol table.
+ void
+ set_symtab_index(unsigned int index)
+ {
+ gold_assert(index != 0);
+ this->symtab_index_ = index;
+ }
+
+ // Return whether this symbol already has an index in the output
+ // file symbol table.
+ bool
+ has_symtab_index() const
+ { return this->symtab_index_ != 0; }
+
+ // Return the index of this symbol in the dynamic symbol table. A
+ // value of -1U means that this symbol is not going into the dynamic
+ // symbol table. This starts out as zero, and is set to a non-zero
+ // during Layout::finalize. It is an error to ask for the dynamic
+ // symbol table index before it has been set.
+ unsigned int
+ dynsym_index() const
+ {
+ gold_assert(this->dynsym_index_ != 0);
+ return this->dynsym_index_;
+ }
+
+ // Set the index of the symbol in the dynamic symbol table.
+ void
+ set_dynsym_index(unsigned int index)
+ {
+ gold_assert(index != 0);
+ this->dynsym_index_ = index;
+ }
+
+ // Return whether this symbol already has an index in the dynamic
+ // symbol table.
+ bool
+ has_dynsym_index() const
+ { return this->dynsym_index_ != 0; }
+
+ // Return whether this symbol has an entry in the GOT section.
+ // For a TLS symbol, this GOT entry will hold its tp-relative offset.
+ bool
+ has_got_offset(unsigned int got_type) const
+ { return this->got_offsets_.get_offset(got_type) != -1U; }
+
+ // Return the offset into the GOT section of this symbol.
+ unsigned int
+ got_offset(unsigned int got_type) const
+ {
+ unsigned int got_offset = this->got_offsets_.get_offset(got_type);
+ gold_assert(got_offset != -1U);
+ return got_offset;
+ }
+
+ // Set the GOT offset of this symbol.
+ void
+ set_got_offset(unsigned int got_type, unsigned int got_offset)
+ { this->got_offsets_.set_offset(got_type, got_offset); }
+
+ // Return the GOT offset list.
+ const Got_offset_list*
+ got_offset_list() const
+ { return this->got_offsets_.get_list(); }
+
+ // Return whether this symbol has an entry in the PLT section.
+ bool
+ has_plt_offset() const
+ { return this->plt_offset_ != -1U; }
+
+ // Return the offset into the PLT section of this symbol.
+ unsigned int
+ plt_offset() const
+ {
+ gold_assert(this->has_plt_offset());
+ return this->plt_offset_;
+ }
+
+ // Set the PLT offset of this symbol.
+ void
+ set_plt_offset(unsigned int plt_offset)
+ {
+ gold_assert(plt_offset != -1U);
+ this->plt_offset_ = plt_offset;
+ }
+
+ // Return whether this dynamic symbol needs a special value in the
+ // dynamic symbol table.
+ bool
+ needs_dynsym_value() const
+ { return this->needs_dynsym_value_; }
+
+ // Set that this dynamic symbol needs a special value in the dynamic
+ // symbol table.
+ void
+ set_needs_dynsym_value()
+ {
+ gold_assert(this->object()->is_dynamic());
+ this->needs_dynsym_value_ = true;
+ }
+
+ // Return true if the final value of this symbol is known at link
+ // time.
+ bool
+ final_value_is_known() const;
+
+ // Return true if SHNDX represents a common symbol. This depends on
+ // the target.
+ static bool
+ is_common_shndx(unsigned int shndx);
+
+ // Return whether this is a defined symbol (not undefined or
+ // common).
+ bool
+ is_defined() const
+ {
+ bool is_ordinary;
+ if (this->source_ != FROM_OBJECT)
+ return this->source_ != IS_UNDEFINED;
+ unsigned int shndx = this->shndx(&is_ordinary);
+ return (is_ordinary
+ ? shndx != elfcpp::SHN_UNDEF
+ : !Symbol::is_common_shndx(shndx));
+ }
+
+ // Return true if this symbol is from a dynamic object.
+ bool
+ is_from_dynobj() const
+ {
+ return this->source_ == FROM_OBJECT && this->object()->is_dynamic();
+ }
+
+ // Return whether this is a placeholder symbol from a plugin object.
+ bool
+ is_placeholder() const
+ {
+ return this->source_ == FROM_OBJECT && this->object()->pluginobj() != NULL;
+ }
+
+ // Return whether this is an undefined symbol.
+ bool
+ is_undefined() const
+ {
+ bool is_ordinary;
+ return ((this->source_ == FROM_OBJECT
+ && this->shndx(&is_ordinary) == elfcpp::SHN_UNDEF
+ && is_ordinary)
+ || this->source_ == IS_UNDEFINED);
+ }
+
+ // Return whether this is a weak undefined symbol.
+ bool
+ is_weak_undefined() const
+ { return this->is_undefined() && this->binding() == elfcpp::STB_WEAK; }
+
+ // Return whether this is an absolute symbol.
+ bool
+ is_absolute() const
+ {
+ bool is_ordinary;
+ return ((this->source_ == FROM_OBJECT
+ && this->shndx(&is_ordinary) == elfcpp::SHN_ABS
+ && !is_ordinary)
+ || this->source_ == IS_CONSTANT);
+ }
+
+ // Return whether this is a common symbol.
+ bool
+ is_common() const
+ {
+ if (this->source_ != FROM_OBJECT)
+ return false;
+ if (this->type_ == elfcpp::STT_COMMON)
+ return true;
+ bool is_ordinary;
+ unsigned int shndx = this->shndx(&is_ordinary);
+ return !is_ordinary && Symbol::is_common_shndx(shndx);
+ }
+
+ // Return whether this symbol can be seen outside this object.
+ bool
+ is_externally_visible() const
+ {
+ return ((this->visibility_ == elfcpp::STV_DEFAULT
+ || this->visibility_ == elfcpp::STV_PROTECTED)
+ && !this->is_forced_local_);
+ }
+
+ // Return true if this symbol can be preempted by a definition in
+ // another link unit.
+ bool
+ is_preemptible() const
+ {
+ // It doesn't make sense to ask whether a symbol defined in
+ // another object is preemptible.
+ gold_assert(!this->is_from_dynobj());
+
+ // It doesn't make sense to ask whether an undefined symbol
+ // is preemptible.
+ gold_assert(!this->is_undefined());
+
+ // If a symbol does not have default visibility, it can not be
+ // seen outside this link unit and therefore is not preemptible.
+ if (this->visibility_ != elfcpp::STV_DEFAULT)
+ return false;
+
+ // If this symbol has been forced to be a local symbol by a
+ // version script, then it is not visible outside this link unit
+ // and is not preemptible.
+ if (this->is_forced_local_)
+ return false;
+
+ // If we are not producing a shared library, then nothing is
+ // preemptible.
+ if (!parameters->options().shared())
+ return false;
+
+ // If the user used -Bsymbolic, then nothing is preemptible.
+ if (parameters->options().Bsymbolic())
+ return false;
+
+ // If the user used -Bsymbolic-functions, then functions are not
+ // preemptible. We explicitly check for not being STT_OBJECT,
+ // rather than for being STT_FUNC, because that is what the GNU
+ // linker does.
+ if (this->type() != elfcpp::STT_OBJECT
+ && parameters->options().Bsymbolic_functions())
+ return false;
+
+ // Otherwise the symbol is preemptible.
+ return true;
+ }
+
+ // Return true if this symbol is a function that needs a PLT entry.
+ bool
+ needs_plt_entry() const
+ {
+ // An undefined symbol from an executable does not need a PLT entry.
+ if (this->is_undefined() && !parameters->options().shared())
+ return false;
+
+ // An STT_GNU_IFUNC symbol always needs a PLT entry, even when
+ // doing a static link.
+ if (this->type() == elfcpp::STT_GNU_IFUNC)
+ return true;
+
+ // We only need a PLT entry for a function.
+ if (!this->is_func())
+ return false;
+
+ // If we're doing a static link or a -pie link, we don't create
+ // PLT entries.
+ if (parameters->doing_static_link()
+ || parameters->options().pie())
+ return false;
+
+ // We need a PLT entry if the function is defined in a dynamic
+ // object, or is undefined when building a shared object, or if it
+ // is subject to pre-emption.
+ return (this->is_from_dynobj()
+ || this->is_undefined()
+ || this->is_preemptible());
+ }
+
+ // When determining whether a reference to a symbol needs a dynamic
+ // relocation, we need to know several things about the reference.
+ // These flags may be or'ed together. 0 means that the symbol
+ // isn't referenced at all.
+ enum Reference_flags
+ {
+ // A reference to the symbol's absolute address. This includes
+ // references that cause an absolute address to be stored in the GOT.
+ ABSOLUTE_REF = 1,
+ // A reference that calculates the offset of the symbol from some
+ // anchor point, such as the PC or GOT.
+ RELATIVE_REF = 2,
+ // A TLS-related reference.
+ TLS_REF = 4,
+ // A reference that can always be treated as a function call.
+ FUNCTION_CALL = 8
+ };
+
+ // Given a direct absolute or pc-relative static relocation against
+ // the global symbol, this function returns whether a dynamic relocation
+ // is needed.
+
+ bool
+ needs_dynamic_reloc(int flags) const
+ {
+ // No dynamic relocations in a static link!
+ if (parameters->doing_static_link())
+ return false;
+
+ // A reference to an undefined symbol from an executable should be
+ // statically resolved to 0, and does not need a dynamic relocation.
+ // This matches gnu ld behavior.
+ if (this->is_undefined() && !parameters->options().shared())
+ return false;
+
+ // A reference to an absolute symbol does not need a dynamic relocation.
+ if (this->is_absolute())
+ return false;
+
+ // An absolute reference within a position-independent output file
+ // will need a dynamic relocation.
+ if ((flags & ABSOLUTE_REF)
+ && parameters->options().output_is_position_independent())
+ return true;
+
+ // A function call that can branch to a local PLT entry does not need
+ // a dynamic relocation.
+ if ((flags & FUNCTION_CALL) && this->has_plt_offset())
+ return false;
+
+ // A reference to any PLT entry in a non-position-independent executable
+ // does not need a dynamic relocation.
+ if (!parameters->options().output_is_position_independent()
+ && this->has_plt_offset())
+ return false;
+
+ // A reference to a symbol defined in a dynamic object or to a
+ // symbol that is preemptible will need a dynamic relocation.
+ if (this->is_from_dynobj()
+ || this->is_undefined()
+ || this->is_preemptible())
+ return true;
+
+ // For all other cases, return FALSE.
+ return false;
+ }
+
+ // Whether we should use the PLT offset associated with a symbol for
+ // a relocation. FLAGS is a set of Reference_flags.
+
+ bool
+ use_plt_offset(int flags) const
+ {
+ // If the symbol doesn't have a PLT offset, then naturally we
+ // don't want to use it.
+ if (!this->has_plt_offset())
+ return false;
+
+ // For a STT_GNU_IFUNC symbol we always have to use the PLT entry.
+ if (this->type() == elfcpp::STT_GNU_IFUNC)
+ return true;
+
+ // If we are going to generate a dynamic relocation, then we will
+ // wind up using that, so no need to use the PLT entry.
+ if (this->needs_dynamic_reloc(flags))
+ return false;
+
+ // If the symbol is from a dynamic object, we need to use the PLT
+ // entry.
+ if (this->is_from_dynobj())
+ return true;
+
+ // If we are generating a shared object, and this symbol is
+ // undefined or preemptible, we need to use the PLT entry.
+ if (parameters->options().shared()
+ && (this->is_undefined() || this->is_preemptible()))
+ return true;
+
+ // If this is a call to a weak undefined symbol, we need to use
+ // the PLT entry; the symbol may be defined by a library loaded
+ // at runtime.
+ if ((flags & FUNCTION_CALL) && this->is_weak_undefined())
+ return true;
+
+ // Otherwise we can use the regular definition.
+ return false;
+ }
+
+ // Given a direct absolute static relocation against
+ // the global symbol, where a dynamic relocation is needed, this
+ // function returns whether a relative dynamic relocation can be used.
+ // The caller must determine separately whether the static relocation
+ // is compatible with a relative relocation.
+
+ bool
+ can_use_relative_reloc(bool is_function_call) const
+ {
+ // A function call that can branch to a local PLT entry can
+ // use a RELATIVE relocation.
+ if (is_function_call && this->has_plt_offset())
+ return true;
+
+ // A reference to a symbol defined in a dynamic object or to a
+ // symbol that is preemptible can not use a RELATIVE relocation.
+ if (this->is_from_dynobj()
+ || this->is_undefined()
+ || this->is_preemptible())
+ return false;
+
+ // For all other cases, return TRUE.
+ return true;
+ }
+
+ // Return the output section where this symbol is defined. Return
+ // NULL if the symbol has an absolute value.
+ Output_section*
+ output_section() const;
+
+ // Set the symbol's output section. This is used for symbols
+ // defined in scripts. This should only be called after the symbol
+ // table has been finalized.
+ void
+ set_output_section(Output_section*);
+
+ // Return whether there should be a warning for references to this
+ // symbol.
+ bool
+ has_warning() const
+ { return this->has_warning_; }
+
+ // Mark this symbol as having a warning.
+ void
+ set_has_warning()
+ { this->has_warning_ = true; }
+
+ // Return whether this symbol is defined by a COPY reloc from a
+ // dynamic object.
+ bool
+ is_copied_from_dynobj() const
+ { return this->is_copied_from_dynobj_; }
+
+ // Mark this symbol as defined by a COPY reloc.
+ void
+ set_is_copied_from_dynobj()
+ { this->is_copied_from_dynobj_ = true; }
+
+ // Return whether this symbol is forced to visibility STB_LOCAL
+ // by a "local:" entry in a version script.
+ bool
+ is_forced_local() const
+ { return this->is_forced_local_; }
+
+ // Mark this symbol as forced to STB_LOCAL visibility.
+ void
+ set_is_forced_local()
+ { this->is_forced_local_ = true; }
+
+ // Return true if this 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() const
+ {
+ return (!parameters->options().output_is_position_independent()
+ && parameters->options().copyreloc()
+ && this->is_from_dynobj()
+ && !this->is_func());
+ }
+
+ // Return true if this symbol was predefined by the linker.
+ bool
+ is_predefined() const
+ { return this->is_predefined_; }
+
+ // Return true if this is a C++ vtable symbol.
+ bool
+ is_cxx_vtable() const
+ { return is_prefix_of("_ZTV", this->name_); }
+
+ protected:
+ // Instances of this class should always be created at a specific
+ // size.
+ Symbol()
+ { memset(this, 0, sizeof *this); }
+
+ // Initialize the general fields.
+ void
+ init_fields(const char* name, const char* version,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis);
+
+ // Initialize fields from an ELF symbol in OBJECT. ST_SHNDX is the
+ // section index, IS_ORDINARY is whether it is a normal section
+ // index rather than a special code.
+ template<int size, bool big_endian>
+ void
+ init_base_object(const char* name, const char* version, Object* object,
+ const elfcpp::Sym<size, big_endian>&, unsigned int st_shndx,
+ bool is_ordinary);
+
+ // Initialize fields for an Output_data.
+ void
+ init_base_output_data(const char* name, const char* version, Output_data*,
+ elfcpp::STT, elfcpp::STB, elfcpp::STV,
+ unsigned char nonvis, bool offset_is_from_end,
+ bool is_predefined);
+
+ // Initialize fields for an Output_segment.
+ void
+ init_base_output_segment(const char* name, const char* version,
+ Output_segment* os, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis,
+ Segment_offset_base offset_base,
+ bool is_predefined);
+
+ // Initialize fields for a constant.
+ void
+ init_base_constant(const char* name, const char* version, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis, bool is_predefined);
+
+ // Initialize fields for an undefined symbol.
+ void
+ init_base_undefined(const char* name, const char* version, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis);
+
+ // Override existing symbol.
+ template<int size, bool big_endian>
+ void
+ override_base(const elfcpp::Sym<size, big_endian>&, unsigned int st_shndx,
+ bool is_ordinary, Object* object, const char* version);
+
+ // Override existing symbol with a special symbol.
+ void
+ override_base_with_special(const Symbol* from);
+
+ // Override symbol version.
+ void
+ override_version(const char* version);
+
+ // Allocate a common symbol by giving it a location in the output
+ // file.
+ void
+ allocate_base_common(Output_data*);
+
+ private:
+ Symbol(const Symbol&);
+ Symbol& operator=(const Symbol&);
+
+ // Symbol name (expected to point into a Stringpool).
+ const char* name_;
+ // Symbol version (expected to point into a Stringpool). This may
+ // be NULL.
+ const char* version_;
+
+ union
+ {
+ // This struct is used if SOURCE_ == FROM_OBJECT.
+ struct
+ {
+ // Object in which symbol is defined, or in which it was first
+ // seen.
+ Object* object;
+ // Section number in object_ in which symbol is defined.
+ unsigned int shndx;
+ } from_object;
+
+ // This struct is used if SOURCE_ == IN_OUTPUT_DATA.
+ struct
+ {
+ // Output_data in which symbol is defined. Before
+ // Layout::finalize the symbol's value is an offset within the
+ // Output_data.
+ Output_data* output_data;
+ // True if the offset is from the end, false if the offset is
+ // from the beginning.
+ bool offset_is_from_end;
+ } in_output_data;
+
+ // This struct is used if SOURCE_ == IN_OUTPUT_SEGMENT.
+ struct
+ {
+ // Output_segment in which the symbol is defined. Before
+ // Layout::finalize the symbol's value is an offset.
+ Output_segment* output_segment;
+ // The base to use for the offset before Layout::finalize.
+ Segment_offset_base offset_base;
+ } in_output_segment;
+ } u_;
+
+ // The index of this symbol in the output file. If the symbol is
+ // not going into the output file, this value is -1U. This field
+ // starts as always holding zero. It is set to a non-zero value by
+ // Symbol_table::finalize.
+ unsigned int symtab_index_;
+
+ // The index of this symbol in the dynamic symbol table. If the
+ // symbol is not going into the dynamic symbol table, this value is
+ // -1U. This field starts as always holding zero. It is set to a
+ // non-zero value during Layout::finalize.
+ unsigned int dynsym_index_;
+
+ // The GOT section entries for this symbol. 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_offset_list got_offsets_;
+
+ // If this symbol has an entry in the PLT section, then this is the
+ // offset from the start of the PLT section. This is -1U if there
+ // is no PLT entry.
+ unsigned int plt_offset_;
+
+ // Symbol type (bits 0 to 3).
+ elfcpp::STT type_ : 4;
+ // Symbol binding (bits 4 to 7).
+ elfcpp::STB binding_ : 4;
+ // Symbol visibility (bits 8 to 9).
+ elfcpp::STV visibility_ : 2;
+ // Rest of symbol st_other field (bits 10 to 15).
+ unsigned int nonvis_ : 6;
+ // The type of symbol (bits 16 to 18).
+ Source source_ : 3;
+ // True if this is the default version of the symbol (bit 19).
+ bool is_def_ : 1;
+ // True if this symbol really forwards to another symbol. This is
+ // used when we discover after the fact that two different entries
+ // in the hash table really refer to the same symbol. This will
+ // never be set for a symbol found in the hash table, but may be set
+ // for a symbol found in the list of symbols attached to an Object.
+ // It forwards to the symbol found in the forwarders_ map of
+ // Symbol_table (bit 20).
+ bool is_forwarder_ : 1;
+ // True if the symbol has an alias in the weak_aliases table in
+ // Symbol_table (bit 21).
+ bool has_alias_ : 1;
+ // True if this symbol needs to be in the dynamic symbol table (bit
+ // 22).
+ bool needs_dynsym_entry_ : 1;
+ // True if we've seen this symbol in a regular object (bit 23).
+ bool in_reg_ : 1;
+ // True if we've seen this symbol in a dynamic object (bit 24).
+ bool in_dyn_ : 1;
+ // True if this is a dynamic symbol which needs a special value in
+ // the dynamic symbol table (bit 25).
+ bool needs_dynsym_value_ : 1;
+ // True if there is a warning for this symbol (bit 26).
+ bool has_warning_ : 1;
+ // True if we are using a COPY reloc for this symbol, so that the
+ // real definition lives in a dynamic object (bit 27).
+ bool is_copied_from_dynobj_ : 1;
+ // True if this symbol was forced to local visibility by a version
+ // script (bit 28).
+ bool is_forced_local_ : 1;
+ // True if the field u_.from_object.shndx is an ordinary section
+ // index, not one of the special codes from SHN_LORESERVE to
+ // SHN_HIRESERVE (bit 29).
+ bool is_ordinary_shndx_ : 1;
+ // True if we've seen this symbol in a "real" ELF object (bit 30).
+ // If the symbol has been seen in a relocatable, non-IR, object file,
+ // it's known to be referenced from outside the IR. A reference from
+ // a dynamic object doesn't count as a "real" ELF, and we'll simply
+ // mark the symbol as "visible" from outside the IR. The compiler
+ // can use this distinction to guide its handling of COMDAT symbols.
+ bool in_real_elf_ : 1;
+ // True if this symbol is defined in a section which was discarded
+ // (bit 31).
+ bool is_defined_in_discarded_section_ : 1;
+ // True if UNDEF_BINDING_WEAK_ has been set (bit 32).
+ bool undef_binding_set_ : 1;
+ // True if this symbol was a weak undef resolved by a dynamic def
+ // (bit 33).
+ bool undef_binding_weak_ : 1;
+ // True if this symbol is a predefined linker symbol (bit 34).
+ bool is_predefined_ : 1;
+};
+
+// The parts of a symbol which are size specific. Using a template
+// derived class like this helps us use less space on a 32-bit system.
+
+template<int size>
+class Sized_symbol : public Symbol
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Value_type;
+ typedef typename elfcpp::Elf_types<size>::Elf_WXword Size_type;
+
+ Sized_symbol()
+ { }
+
+ // Initialize fields from an ELF symbol in OBJECT. ST_SHNDX is the
+ // section index, IS_ORDINARY is whether it is a normal section
+ // index rather than a special code.
+ template<bool big_endian>
+ void
+ init_object(const char* name, const char* version, Object* object,
+ const elfcpp::Sym<size, big_endian>&, unsigned int st_shndx,
+ bool is_ordinary);
+
+ // Initialize fields for an Output_data.
+ void
+ init_output_data(const char* name, const char* version, Output_data*,
+ Value_type value, Size_type symsize, elfcpp::STT,
+ elfcpp::STB, elfcpp::STV, unsigned char nonvis,
+ bool offset_is_from_end, bool is_predefined);
+
+ // Initialize fields for an Output_segment.
+ void
+ init_output_segment(const char* name, const char* version, Output_segment*,
+ Value_type value, Size_type symsize, elfcpp::STT,
+ elfcpp::STB, elfcpp::STV, unsigned char nonvis,
+ Segment_offset_base offset_base, bool is_predefined);
+
+ // Initialize fields for a constant.
+ void
+ init_constant(const char* name, const char* version, Value_type value,
+ Size_type symsize, elfcpp::STT, elfcpp::STB, elfcpp::STV,
+ unsigned char nonvis, bool is_predefined);
+
+ // Initialize fields for an undefined symbol.
+ void
+ init_undefined(const char* name, const char* version, elfcpp::STT,
+ elfcpp::STB, elfcpp::STV, unsigned char nonvis);
+
+ // Override existing symbol.
+ template<bool big_endian>
+ void
+ override(const elfcpp::Sym<size, big_endian>&, unsigned int st_shndx,
+ bool is_ordinary, Object* object, const char* version);
+
+ // Override existing symbol with a special symbol.
+ void
+ override_with_special(const Sized_symbol<size>*);
+
+ // Return the symbol's value.
+ Value_type
+ value() const
+ { return this->value_; }
+
+ // Return the symbol's size (we can't call this 'size' because that
+ // is a template parameter).
+ Size_type
+ symsize() const
+ { return this->symsize_; }
+
+ // Set the symbol size. This is used when resolving common symbols.
+ void
+ set_symsize(Size_type symsize)
+ { this->symsize_ = symsize; }
+
+ // Set the symbol value. This is called when we store the final
+ // values of the symbols into the symbol table.
+ void
+ set_value(Value_type value)
+ { this->value_ = value; }
+
+ // Allocate a common symbol by giving it a location in the output
+ // file.
+ void
+ allocate_common(Output_data*, Value_type value);
+
+ private:
+ Sized_symbol(const Sized_symbol&);
+ Sized_symbol& operator=(const Sized_symbol&);
+
+ // Symbol value. Before Layout::finalize this is the offset in the
+ // input section. This is set to the final value during
+ // Layout::finalize.
+ Value_type value_;
+ // Symbol size.
+ Size_type symsize_;
+};
+
+// A struct describing a symbol defined by the linker, where the value
+// of the symbol is defined based on an output section. This is used
+// for symbols defined by the linker, like "_init_array_start".
+
+struct Define_symbol_in_section
+{
+ // The symbol name.
+ const char* name;
+ // The name of the output section with which this symbol should be
+ // associated. If there is no output section with that name, the
+ // symbol will be defined as zero.
+ const char* output_section;
+ // The offset of the symbol within the output section. This is an
+ // offset from the start of the output section, unless start_at_end
+ // is true, in which case this is an offset from the end of the
+ // output section.
+ uint64_t value;
+ // The size of the symbol.
+ uint64_t size;
+ // The symbol type.
+ elfcpp::STT type;
+ // The symbol binding.
+ elfcpp::STB binding;
+ // The symbol visibility.
+ elfcpp::STV visibility;
+ // The rest of the st_other field.
+ unsigned char nonvis;
+ // If true, the value field is an offset from the end of the output
+ // section.
+ bool offset_is_from_end;
+ // If true, this symbol is defined only if we see a reference to it.
+ bool only_if_ref;
+};
+
+// A struct describing a symbol defined by the linker, where the value
+// of the symbol is defined based on a segment. This is used for
+// symbols defined by the linker, like "_end". We describe the
+// segment with which the symbol should be associated by its
+// characteristics. If no segment meets these characteristics, the
+// symbol will be defined as zero. If there is more than one segment
+// which meets these characteristics, we will use the first one.
+
+struct Define_symbol_in_segment
+{
+ // The symbol name.
+ const char* name;
+ // The segment type where the symbol should be defined, typically
+ // PT_LOAD.
+ elfcpp::PT segment_type;
+ // Bitmask of segment flags which must be set.
+ elfcpp::PF segment_flags_set;
+ // Bitmask of segment flags which must be clear.
+ elfcpp::PF segment_flags_clear;
+ // The offset of the symbol within the segment. The offset is
+ // calculated from the position set by offset_base.
+ uint64_t value;
+ // The size of the symbol.
+ uint64_t size;
+ // The symbol type.
+ elfcpp::STT type;
+ // The symbol binding.
+ elfcpp::STB binding;
+ // The symbol visibility.
+ elfcpp::STV visibility;
+ // The rest of the st_other field.
+ unsigned char nonvis;
+ // The base from which we compute the offset.
+ Symbol::Segment_offset_base offset_base;
+ // If true, this symbol is defined only if we see a reference to it.
+ bool only_if_ref;
+};
+
+// Specify an object/section/offset location. Used by ODR code.
+
+struct Symbol_location
+{
+ // Object where the symbol is defined.
+ Object* object;
+ // Section-in-object where the symbol is defined.
+ unsigned int shndx;
+ // For relocatable objects, offset-in-section where the symbol is defined.
+ // For dynamic objects, address where the symbol is defined.
+ off_t offset;
+ bool operator==(const Symbol_location& that) const
+ {
+ return (this->object == that.object
+ && this->shndx == that.shndx
+ && this->offset == that.offset);
+ }
+};
+
+// This class manages warnings. Warnings are a GNU extension. When
+// we see a section named .gnu.warning.SYM in an object file, and if
+// we wind using the definition of SYM from that object file, then we
+// will issue a warning for any relocation against SYM from a
+// different object file. The text of the warning is the contents of
+// the section. This is not precisely the definition used by the old
+// GNU linker; the old GNU linker treated an occurrence of
+// .gnu.warning.SYM as defining a warning symbol. A warning symbol
+// would trigger a warning on any reference. However, it was
+// inconsistent in that a warning in a dynamic object only triggered
+// if there was no definition in a regular object. This linker is
+// different in that we only issue a warning if we use the symbol
+// definition from the same object file as the warning section.
+
+class Warnings
+{
+ public:
+ Warnings()
+ : warnings_()
+ { }
+
+ // Add a warning for symbol NAME in object OBJ. WARNING is the text
+ // of the warning.
+ void
+ add_warning(Symbol_table* symtab, const char* name, Object* obj,
+ const std::string& warning);
+
+ // For each symbol for which we should give a warning, make a note
+ // on the symbol.
+ void
+ note_warnings(Symbol_table* symtab);
+
+ // Issue a warning for a reference to SYM at RELINFO's location.
+ template<int size, bool big_endian>
+ void
+ issue_warning(const Symbol* sym, const Relocate_info<size, big_endian>*,
+ size_t relnum, off_t reloffset) const;
+
+ private:
+ Warnings(const Warnings&);
+ Warnings& operator=(const Warnings&);
+
+ // What we need to know to get the warning text.
+ struct Warning_location
+ {
+ // The object the warning is in.
+ Object* object;
+ // The warning text.
+ std::string text;
+
+ Warning_location()
+ : object(NULL), text()
+ { }
+
+ void
+ set(Object* o, const std::string& t)
+ {
+ this->object = o;
+ this->text = t;
+ }
+ };
+
+ // A mapping from warning symbol names (canonicalized in
+ // Symbol_table's namepool_ field) to warning information.
+ typedef Unordered_map<const char*, Warning_location> Warning_table;
+
+ Warning_table warnings_;
+};
+
+// The main linker symbol table.
+
+class Symbol_table
+{
+ public:
+ // The different places where a symbol definition can come from.
+ enum Defined
+ {
+ // Defined in an object file--the normal case.
+ OBJECT,
+ // Defined for a COPY reloc.
+ COPY,
+ // Defined on the command line using --defsym.
+ DEFSYM,
+ // Defined (so to speak) on the command line using -u.
+ UNDEFINED,
+ // Defined in a linker script.
+ SCRIPT,
+ // Predefined by the linker.
+ PREDEFINED,
+ // Defined by the linker during an incremental base link, but not
+ // a predefined symbol (e.g., common, defined in script).
+ INCREMENTAL_BASE,
+ };
+
+ // The order in which we sort common symbols.
+ enum Sort_commons_order
+ {
+ SORT_COMMONS_BY_SIZE_DESCENDING,
+ SORT_COMMONS_BY_ALIGNMENT_DESCENDING,
+ SORT_COMMONS_BY_ALIGNMENT_ASCENDING
+ };
+
+ // COUNT is an estimate of how many symbols will be inserted in the
+ // symbol table. It's ok to put 0 if you don't know; a correct
+ // guess will just save some CPU by reducing hashtable resizes.
+ Symbol_table(unsigned int count, const Version_script_info& version_script);
+
+ ~Symbol_table();
+
+ void
+ set_icf(Icf* icf)
+ { this->icf_ = icf;}
+
+ Icf*
+ icf() const
+ { return this->icf_; }
+
+ // Returns true if ICF determined that this is a duplicate section.
+ bool
+ is_section_folded(Object* obj, unsigned int shndx) const;
+
+ void
+ set_gc(Garbage_collection* gc)
+ { this->gc_ = gc; }
+
+ Garbage_collection*
+ gc() const
+ { return this->gc_; }
+
+ // During garbage collection, this keeps undefined symbols.
+ void
+ gc_mark_undef_symbols(Layout*);
+
+ // This tells garbage collection that this symbol is referenced.
+ void
+ gc_mark_symbol(Symbol* sym);
+
+ // During garbage collection, this keeps sections that correspond to
+ // symbols seen in dynamic objects.
+ inline void
+ gc_mark_dyn_syms(Symbol* sym);
+
+ // Add COUNT external symbols from the relocatable object RELOBJ to
+ // the symbol table. SYMS is the symbols, SYMNDX_OFFSET is the
+ // offset in the symbol table of the first symbol, SYM_NAMES is
+ // their names, SYM_NAME_SIZE is the size of SYM_NAMES. This sets
+ // SYMPOINTERS to point to the symbols in the symbol table. It sets
+ // *DEFINED to the number of defined symbols.
+ template<int size, bool big_endian>
+ void
+ add_from_relobj(Sized_relobj_file<size, big_endian>* relobj,
+ const unsigned char* syms, size_t count,
+ size_t symndx_offset, const char* sym_names,
+ size_t sym_name_size,
+ typename Sized_relobj_file<size, big_endian>::Symbols*,
+ size_t* defined);
+
+ // Add one external symbol from the plugin object OBJ to the symbol table.
+ // Returns a pointer to the resolved symbol in the symbol table.
+ template<int size, bool big_endian>
+ Symbol*
+ add_from_pluginobj(Sized_pluginobj<size, big_endian>* obj,
+ const char* name, const char* ver,
+ elfcpp::Sym<size, big_endian>* sym);
+
+ // Add COUNT dynamic symbols from the dynamic object DYNOBJ to the
+ // symbol table. SYMS is the symbols. SYM_NAMES is their names.
+ // SYM_NAME_SIZE is the size of SYM_NAMES. The other parameters are
+ // symbol version data.
+ template<int size, bool big_endian>
+ void
+ add_from_dynobj(Sized_dynobj<size, big_endian>* dynobj,
+ const unsigned char* syms, size_t count,
+ const char* sym_names, size_t sym_name_size,
+ const unsigned char* versym, size_t versym_size,
+ const std::vector<const char*>*,
+ typename Sized_relobj_file<size, big_endian>::Symbols*,
+ size_t* defined);
+
+ // Add one external symbol from the incremental object OBJ to the symbol
+ // table. Returns a pointer to the resolved symbol in the symbol table.
+ template<int size, bool big_endian>
+ Sized_symbol<size>*
+ add_from_incrobj(Object* obj, const char* name,
+ const char* ver, elfcpp::Sym<size, big_endian>* sym);
+
+ // Define a special symbol based on an Output_data. It is a
+ // multiple definition error if this symbol is already defined.
+ Symbol*
+ define_in_output_data(const char* name, const char* version, Defined,
+ Output_data*, uint64_t value, uint64_t symsize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ bool offset_is_from_end, bool only_if_ref);
+
+ // Define a special symbol based on an Output_segment. It is a
+ // multiple definition error if this symbol is already defined.
+ Symbol*
+ define_in_output_segment(const char* name, const char* version, Defined,
+ Output_segment*, uint64_t value, uint64_t symsize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ Symbol::Segment_offset_base, bool only_if_ref);
+
+ // Define a special symbol with a constant value. It is a multiple
+ // definition error if this symbol is already defined.
+ Symbol*
+ define_as_constant(const char* name, const char* version, Defined,
+ uint64_t value, uint64_t symsize, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis, bool only_if_ref,
+ bool force_override);
+
+ // Define a set of symbols in output sections. If ONLY_IF_REF is
+ // true, only define them if they are referenced.
+ void
+ define_symbols(const Layout*, int count, const Define_symbol_in_section*,
+ bool only_if_ref);
+
+ // Define a set of symbols in output segments. If ONLY_IF_REF is
+ // true, only defined them if they are referenced.
+ void
+ define_symbols(const Layout*, int count, const Define_symbol_in_segment*,
+ bool only_if_ref);
+
+ // Define SYM using a COPY reloc. POSD is the Output_data where the
+ // symbol should be defined--typically a .dyn.bss section. VALUE is
+ // the offset within POSD.
+ template<int size>
+ void
+ define_with_copy_reloc(Sized_symbol<size>* sym, Output_data* posd,
+ typename elfcpp::Elf_types<size>::Elf_Addr);
+
+ // Look up a symbol.
+ Symbol*
+ lookup(const char*, const char* version = NULL) const;
+
+ // Return the real symbol associated with the forwarder symbol FROM.
+ Symbol*
+ resolve_forwards(const Symbol* from) const;
+
+ // Return the sized version of a symbol in this table.
+ template<int size>
+ Sized_symbol<size>*
+ get_sized_symbol(Symbol*) const;
+
+ template<int size>
+ const Sized_symbol<size>*
+ get_sized_symbol(const Symbol*) const;
+
+ // Return the count of undefined symbols seen.
+ size_t
+ saw_undefined() const
+ { return this->saw_undefined_; }
+
+ // Allocate the common symbols
+ void
+ allocate_commons(Layout*, Mapfile*);
+
+ // Add a warning for symbol NAME in object OBJ. WARNING is the text
+ // of the warning.
+ void
+ add_warning(const char* name, Object* obj, const std::string& warning)
+ { this->warnings_.add_warning(this, name, obj, warning); }
+
+ // Canonicalize a symbol name for use in the hash table.
+ const char*
+ canonicalize_name(const char* name)
+ { return this->namepool_.add(name, true, NULL); }
+
+ // Possibly issue a warning for a reference to SYM at LOCATION which
+ // is in OBJ.
+ template<int size, bool big_endian>
+ void
+ issue_warning(const Symbol* sym,
+ const Relocate_info<size, big_endian>* relinfo,
+ size_t relnum, off_t reloffset) const
+ { this->warnings_.issue_warning(sym, relinfo, relnum, reloffset); }
+
+ // Check candidate_odr_violations_ to find symbols with the same name
+ // but apparently different definitions (different source-file/line-no).
+ void
+ detect_odr_violations(const Task*, const char* output_file_name) const;
+
+ // Add any undefined symbols named on the command line to the symbol
+ // table.
+ void
+ add_undefined_symbols_from_command_line(Layout*);
+
+ // SYM is defined using a COPY reloc. Return the dynamic object
+ // where the original definition was found.
+ Dynobj*
+ get_copy_source(const Symbol* sym) const;
+
+ // Set the dynamic symbol indexes. INDEX is the index of the first
+ // global dynamic symbol. Pointers to the symbols are stored into
+ // the vector. The names are stored into the Stringpool. This
+ // returns an updated dynamic symbol index.
+ unsigned int
+ set_dynsym_indexes(unsigned int index, std::vector<Symbol*>*,
+ Stringpool*, Versions*);
+
+ // Finalize the symbol table after we have set the final addresses
+ // of all the input sections. This sets the final symbol indexes,
+ // values and adds the names to *POOL. *PLOCAL_SYMCOUNT is the
+ // index of the first global symbol. OFF is the file offset of the
+ // global symbol table, DYNOFF is the offset of the globals in the
+ // dynamic symbol table, DYN_GLOBAL_INDEX is the index of the first
+ // global dynamic symbol, and DYNCOUNT is the number of global
+ // dynamic symbols. This records the parameters, and returns the
+ // new file offset. It updates *PLOCAL_SYMCOUNT if it created any
+ // local symbols.
+ off_t
+ finalize(off_t off, off_t dynoff, size_t dyn_global_index, size_t dyncount,
+ Stringpool* pool, unsigned int* plocal_symcount);
+
+ // Set the final file offset of the symbol table.
+ void
+ set_file_offset(off_t off)
+ { this->offset_ = off; }
+
+ // Status code of Symbol_table::compute_final_value.
+ enum Compute_final_value_status
+ {
+ // No error.
+ CFVS_OK,
+ // Unsupported symbol section.
+ CFVS_UNSUPPORTED_SYMBOL_SECTION,
+ // No output section.
+ CFVS_NO_OUTPUT_SECTION
+ };
+
+ // Compute the final value of SYM and store status in location PSTATUS.
+ // During relaxation, this may be called multiple times for a symbol to
+ // compute its would-be final value in each relaxation pass.
+
+ template<int size>
+ typename Sized_symbol<size>::Value_type
+ compute_final_value(const Sized_symbol<size>* sym,
+ Compute_final_value_status* pstatus) const;
+
+ // Return the index of the first global symbol.
+ unsigned int
+ first_global_index() const
+ { return this->first_global_index_; }
+
+ // Return the total number of symbols in the symbol table.
+ unsigned int
+ output_count() const
+ { return this->output_count_; }
+
+ // Write out the global symbols.
+ void
+ write_globals(const Stringpool*, const Stringpool*,
+ Output_symtab_xindex*, Output_symtab_xindex*,
+ Output_file*) const;
+
+ // Write out a section symbol. Return the updated offset.
+ void
+ write_section_symbol(const Output_section*, Output_symtab_xindex*,
+ Output_file*, off_t) const;
+
+ // Loop over all symbols, applying the function F to each.
+ template<int size, typename F>
+ void
+ for_all_symbols(F f) const
+ {
+ for (Symbol_table_type::const_iterator p = this->table_.begin();
+ p != this->table_.end();
+ ++p)
+ {
+ Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
+ f(sym);
+ }
+ }
+
+ // Dump statistical information to stderr.
+ void
+ print_stats() const;
+
+ // Return the version script information.
+ const Version_script_info&
+ version_script() const
+ { return version_script_; }
+
+ private:
+ Symbol_table(const Symbol_table&);
+ Symbol_table& operator=(const Symbol_table&);
+
+ // The type of the list of common symbols.
+ typedef std::vector<Symbol*> Commons_type;
+
+ // The type of the symbol hash table.
+
+ typedef std::pair<Stringpool::Key, Stringpool::Key> Symbol_table_key;
+
+ // The hash function. The key values are Stringpool keys.
+ struct Symbol_table_hash
+ {
+ inline size_t
+ operator()(const Symbol_table_key& key) const
+ {
+ return key.first ^ key.second;
+ }
+ };
+
+ struct Symbol_table_eq
+ {
+ bool
+ operator()(const Symbol_table_key&, const Symbol_table_key&) const;
+ };
+
+ typedef Unordered_map<Symbol_table_key, Symbol*, Symbol_table_hash,
+ Symbol_table_eq> Symbol_table_type;
+
+ // A map from symbol name (as a pointer into the namepool) to all
+ // the locations the symbols is (weakly) defined (and certain other
+ // conditions are met). This map will be used later to detect
+ // possible One Definition Rule (ODR) violations.
+ struct Symbol_location_hash
+ {
+ size_t operator()(const Symbol_location& loc) const
+ { return reinterpret_cast<uintptr_t>(loc.object) ^ loc.offset ^ loc.shndx; }
+ };
+
+ typedef Unordered_map<const char*,
+ Unordered_set<Symbol_location, Symbol_location_hash> >
+ Odr_map;
+
+ // Make FROM a forwarder symbol to TO.
+ void
+ make_forwarder(Symbol* from, Symbol* to);
+
+ // Add a symbol.
+ template<int size, bool big_endian>
+ Sized_symbol<size>*
+ add_from_object(Object*, const char* name, Stringpool::Key name_key,
+ const char* version, Stringpool::Key version_key,
+ bool def, const elfcpp::Sym<size, big_endian>& sym,
+ unsigned int st_shndx, bool is_ordinary,
+ unsigned int orig_st_shndx);
+
+ // Define a default symbol.
+ template<int size, bool big_endian>
+ void
+ define_default_version(Sized_symbol<size>*, bool,
+ Symbol_table_type::iterator);
+
+ // Resolve symbols.
+ template<int size, bool big_endian>
+ void
+ resolve(Sized_symbol<size>* to,
+ const elfcpp::Sym<size, big_endian>& sym,
+ unsigned int st_shndx, bool is_ordinary,
+ unsigned int orig_st_shndx,
+ Object*, const char* version);
+
+ template<int size, bool big_endian>
+ void
+ resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from);
+
+ // Record that a symbol is forced to be local by a version script or
+ // by visibility.
+ void
+ force_local(Symbol*);
+
+ // Adjust NAME and *NAME_KEY for wrapping.
+ const char*
+ wrap_symbol(const char* name, Stringpool::Key* name_key);
+
+ // Whether we should override a symbol, based on flags in
+ // resolve.cc.
+ static bool
+ should_override(const Symbol*, unsigned int, elfcpp::STT, Defined,
+ Object*, bool*, bool*);
+
+ // Report a problem in symbol resolution.
+ static void
+ report_resolve_problem(bool is_error, const char* msg, const Symbol* to,
+ Defined, Object* object);
+
+ // Override a symbol.
+ template<int size, bool big_endian>
+ void
+ override(Sized_symbol<size>* tosym,
+ const elfcpp::Sym<size, big_endian>& fromsym,
+ unsigned int st_shndx, bool is_ordinary,
+ Object* object, const char* version);
+
+ // Whether we should override a symbol with a special symbol which
+ // is automatically defined by the linker.
+ static bool
+ should_override_with_special(const Symbol*, elfcpp::STT, Defined);
+
+ // Override a symbol with a special symbol.
+ template<int size>
+ void
+ override_with_special(Sized_symbol<size>* tosym,
+ const Sized_symbol<size>* fromsym);
+
+ // Record all weak alias sets for a dynamic object.
+ template<int size>
+ void
+ record_weak_aliases(std::vector<Sized_symbol<size>*>*);
+
+ // Define a special symbol.
+ template<int size, bool big_endian>
+ Sized_symbol<size>*
+ define_special_symbol(const char** pname, const char** pversion,
+ bool only_if_ref, Sized_symbol<size>** poldsym,
+ bool* resolve_oldsym);
+
+ // Define a symbol in an Output_data, sized version.
+ template<int size>
+ Sized_symbol<size>*
+ do_define_in_output_data(const char* name, const char* version, Defined,
+ Output_data*,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword ssize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ bool offset_is_from_end, bool only_if_ref);
+
+ // Define a symbol in an Output_segment, sized version.
+ template<int size>
+ Sized_symbol<size>*
+ do_define_in_output_segment(
+ const char* name, const char* version, Defined, Output_segment* os,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword ssize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ Symbol::Segment_offset_base offset_base, bool only_if_ref);
+
+ // Define a symbol as a constant, sized version.
+ template<int size>
+ Sized_symbol<size>*
+ do_define_as_constant(
+ const char* name, const char* version, Defined,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword ssize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ bool only_if_ref, bool force_override);
+
+ // Add any undefined symbols named on the command line to the symbol
+ // table, sized version.
+ template<int size>
+ void
+ do_add_undefined_symbols_from_command_line(Layout*);
+
+ // Add one undefined symbol.
+ template<int size>
+ void
+ add_undefined_symbol_from_command_line(const char* name);
+
+ // Types of common symbols.
+
+ enum Commons_section_type
+ {
+ COMMONS_NORMAL,
+ COMMONS_TLS,
+ COMMONS_SMALL,
+ COMMONS_LARGE
+ };
+
+ // Allocate the common symbols, sized version.
+ template<int size>
+ void
+ do_allocate_commons(Layout*, Mapfile*, Sort_commons_order);
+
+ // Allocate the common symbols from one list.
+ template<int size>
+ void
+ do_allocate_commons_list(Layout*, Commons_section_type, Commons_type*,
+ Mapfile*, Sort_commons_order);
+
+ // Returns all of the lines attached to LOC, not just the one the
+ // instruction actually came from. This helps the ODR checker avoid
+ // false positives.
+ static std::vector<std::string>
+ linenos_from_loc(const Task* task, const Symbol_location& loc);
+
+ // Implement detect_odr_violations.
+ template<int size, bool big_endian>
+ void
+ sized_detect_odr_violations() const;
+
+ // Finalize symbols specialized for size.
+ template<int size>
+ off_t
+ sized_finalize(off_t, Stringpool*, unsigned int*);
+
+ // Finalize a symbol. Return whether it should be added to the
+ // symbol table.
+ template<int size>
+ bool
+ sized_finalize_symbol(Symbol*);
+
+ // Add a symbol the final symtab by setting its index.
+ template<int size>
+ void
+ add_to_final_symtab(Symbol*, Stringpool*, unsigned int* pindex, off_t* poff);
+
+ // Write globals specialized for size and endianness.
+ template<int size, bool big_endian>
+ void
+ sized_write_globals(const Stringpool*, const Stringpool*,
+ Output_symtab_xindex*, Output_symtab_xindex*,
+ Output_file*) const;
+
+ // Write out a symbol to P.
+ template<int size, bool big_endian>
+ void
+ sized_write_symbol(Sized_symbol<size>*,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ unsigned int shndx, elfcpp::STB,
+ const Stringpool*, unsigned char* p) const;
+
+ // Possibly warn about an undefined symbol from a dynamic object.
+ void
+ warn_about_undefined_dynobj_symbol(Symbol*) const;
+
+ // Write out a section symbol, specialized for size and endianness.
+ template<int size, bool big_endian>
+ void
+ sized_write_section_symbol(const Output_section*, Output_symtab_xindex*,
+ Output_file*, off_t) const;
+
+ // The type of the list of symbols which have been forced local.
+ typedef std::vector<Symbol*> Forced_locals;
+
+ // A map from symbols with COPY relocs to the dynamic objects where
+ // they are defined.
+ typedef Unordered_map<const Symbol*, Dynobj*> Copied_symbol_dynobjs;
+
+ // We increment this every time we see a new undefined symbol, for
+ // use in archive groups.
+ size_t saw_undefined_;
+ // The index of the first global symbol in the output file.
+ unsigned int first_global_index_;
+ // The file offset within the output symtab section where we should
+ // write the table.
+ off_t offset_;
+ // The number of global symbols we want to write out.
+ unsigned int output_count_;
+ // The file offset of the global dynamic symbols, or 0 if none.
+ off_t dynamic_offset_;
+ // The index of the first global dynamic symbol.
+ unsigned int first_dynamic_global_index_;
+ // The number of global dynamic symbols, or 0 if none.
+ unsigned int dynamic_count_;
+ // The symbol hash table.
+ Symbol_table_type table_;
+ // A pool of symbol names. This is used for all global symbols.
+ // Entries in the hash table point into this pool.
+ Stringpool namepool_;
+ // Forwarding symbols.
+ Unordered_map<const Symbol*, Symbol*> forwarders_;
+ // Weak aliases. A symbol in this list points to the next alias.
+ // The aliases point to each other in a circular list.
+ Unordered_map<Symbol*, Symbol*> weak_aliases_;
+ // We don't expect there to be very many common symbols, so we keep
+ // a list of them. When we find a common symbol we add it to this
+ // list. It is possible that by the time we process the list the
+ // symbol is no longer a common symbol. It may also have become a
+ // forwarder.
+ Commons_type commons_;
+ // This is like the commons_ field, except that it holds TLS common
+ // symbols.
+ Commons_type tls_commons_;
+ // This is for small common symbols.
+ Commons_type small_commons_;
+ // This is for large common symbols.
+ Commons_type large_commons_;
+ // A list of symbols which have been forced to be local. We don't
+ // expect there to be very many of them, so we keep a list of them
+ // rather than walking the whole table to find them.
+ Forced_locals forced_locals_;
+ // Manage symbol warnings.
+ Warnings warnings_;
+ // Manage potential One Definition Rule (ODR) violations.
+ Odr_map candidate_odr_violations_;
+
+ // When we emit a COPY reloc for a symbol, we define it in an
+ // Output_data. When it's time to emit version information for it,
+ // we need to know the dynamic object in which we found the original
+ // definition. This maps symbols with COPY relocs to the dynamic
+ // object where they were defined.
+ Copied_symbol_dynobjs copied_symbol_dynobjs_;
+ // Information parsed from the version script, if any.
+ const Version_script_info& version_script_;
+ Garbage_collection* gc_;
+ Icf* icf_;
+};
+
+// We inline get_sized_symbol for efficiency.
+
+template<int size>
+Sized_symbol<size>*
+Symbol_table::get_sized_symbol(Symbol* sym) const
+{
+ gold_assert(size == parameters->target().get_size());
+ return static_cast<Sized_symbol<size>*>(sym);
+}
+
+template<int size>
+const Sized_symbol<size>*
+Symbol_table::get_sized_symbol(const Symbol* sym) const
+{
+ gold_assert(size == parameters->target().get_size());
+ return static_cast<const Sized_symbol<size>*>(sym);
+}
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_SYMTAB_H)
diff --git a/binutils-2.25/gold/system.h b/binutils-2.25/gold/system.h
new file mode 100644
index 00000000..3e6fe1d4
--- /dev/null
+++ b/binutils-2.25/gold/system.h
@@ -0,0 +1,158 @@
+// system.h -- general definitions for gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This 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 SYSTEM_H
+#define SYSTEM_H 1
+
+#ifndef ENABLE_NLS
+ // The Solaris version of locale.h always includes libintl.h. If we
+ // have been configured with --disable-nls then ENABLE_NLS will not
+ // be defined and the dummy definitions of bindtextdomain (et al)
+ // below will conflict with the definitions in libintl.h. So we
+ // define these values to prevent the bogus inclusion of libintl.h.
+# define _LIBINTL_H
+# define _LIBGETTEXT_H
+#endif
+
+#ifdef ENABLE_NLS
+// On some systems, things go awry when <libintl.h> comes after <clocale>.
+# include <libintl.h>
+# include <clocale>
+# define _(String) gettext (String)
+# ifdef gettext_noop
+# define N_(String) gettext_noop (String)
+# else
+# define N_(String) (String)
+# endif
+#else
+// Include <clocale> first to avoid conflicts with these macros.
+# include <clocale>
+# define gettext(Msgid) (Msgid)
+# define dgettext(Domainname, Msgid) (Msgid)
+# define dcgettext(Domainname, Msgid, Category) (Msgid)
+# define textdomain(Domainname) do {} while (0) /* nothing */
+# define bindtextdomain(Domainname, Dirname) do {} while (0) /* nothing */
+# define _(String) (String)
+# define N_(String) (String)
+#endif
+
+// Figure out how to get a hash set and a hash map.
+
+#if defined(HAVE_TR1_UNORDERED_SET) && defined(HAVE_TR1_UNORDERED_MAP) \
+ && defined(HAVE_TR1_UNORDERED_MAP_REHASH)
+
+#include <tr1/unordered_set>
+#include <tr1/unordered_map>
+
+// We need a template typedef here.
+
+#define Unordered_set std::tr1::unordered_set
+#define Unordered_map std::tr1::unordered_map
+#define Unordered_multimap std::tr1::unordered_multimap
+
+#define reserve_unordered_map(map, n) ((map)->rehash(n))
+
+#ifndef HAVE_TR1_HASH_OFF_T
+// The library does not support hashes of off_t values. Add support
+// here. This is likely to be specific to libstdc++. This issue
+// arises with GCC 4.1.x when compiling in 32-bit mode with a 64-bit
+// off_t type.
+namespace std { namespace tr1 {
+template<>
+struct hash<off_t> : public std::unary_function<off_t, std::size_t>
+{
+ std::size_t
+ operator()(off_t val) const
+ { return static_cast<std::size_t>(val); }
+};
+} } // Close namespaces.
+#endif // !defined(HAVE_TR1_HASH_OFF_T)
+
+#elif defined(HAVE_EXT_HASH_MAP) && defined(HAVE_EXT_HASH_SET)
+
+#include <ext/hash_map>
+#include <ext/hash_set>
+#include <string>
+
+#define Unordered_set __gnu_cxx::hash_set
+#define Unordered_map __gnu_cxx::hash_map
+#define Unordered_multimap __gnu_cxx::hash_multimap
+
+namespace __gnu_cxx
+{
+
+template<>
+struct hash<std::string>
+{
+ size_t
+ operator()(std::string s) const
+ { return __stl_hash_string(s.c_str()); }
+};
+
+template<typename T>
+struct hash<T*>
+{
+ size_t
+ operator()(T* p) const
+ { return reinterpret_cast<size_t>(p); }
+};
+
+}
+
+#define reserve_unordered_map(map, n) ((map)->resize(n))
+
+#else
+
+// The fallback is to just use set and map.
+
+#include <set>
+#include <map>
+
+#define Unordered_set std::set
+#define Unordered_map std::map
+#define Unordered_multimap std::multimap
+
+#define reserve_unordered_map(map, n)
+
+#endif
+
+#ifndef HAVE_PREAD
+extern "C" ssize_t pread(int, void*, size_t, off_t);
+#endif
+
+#ifndef HAVE_FTRUNCATE
+extern "C" int ftruncate(int, off_t);
+#endif
+
+#ifndef HAVE_FFSLL
+extern "C" int ffsll(long long);
+#endif
+
+#if !HAVE_DECL_MEMMEM
+extern "C" void *memmem(const void *, size_t, const void *, size_t);
+#endif
+
+#if !HAVE_DECL_STRNDUP
+extern "C" char *strndup(const char *, size_t);
+#endif
+
+#endif // !defined(SYSTEM_H)
diff --git a/binutils-2.25/gold/target-reloc.h b/binutils-2.25/gold/target-reloc.h
new file mode 100644
index 00000000..b544c78f
--- /dev/null
+++ b/binutils-2.25/gold/target-reloc.h
@@ -0,0 +1,835 @@
+// target-reloc.h -- target specific relocation support -*- C++ -*-
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
+// Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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_TARGET_RELOC_H
+#define GOLD_TARGET_RELOC_H
+
+#include "elfcpp.h"
+#include "symtab.h"
+#include "object.h"
+#include "reloc.h"
+#include "reloc-types.h"
+
+namespace gold
+{
+
+// This function implements the generic part of reloc scanning. The
+// template parameter Scan must be a class type which provides two
+// functions: local() and global(). Those functions implement the
+// machine specific part of scanning. We do it this way to
+// avoid making a function call for each relocation, and to avoid
+// repeating the generic code for each target.
+
+template<int size, bool big_endian, typename Target_type, int sh_type,
+ typename Scan>
+inline void
+scan_relocs(
+ Symbol_table* symtab,
+ Layout* layout,
+ Target_type* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_count,
+ const unsigned char* plocal_syms)
+{
+ typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+ const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ Scan scan;
+
+ for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+ Reltype reloc(prelocs);
+
+ if (needs_special_offset_handling
+ && !output_section->is_input_address_mapped(object, data_shndx,
+ reloc.get_r_offset()))
+ continue;
+
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+ if (r_sym < local_count)
+ {
+ gold_assert(plocal_syms != NULL);
+ typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
+ + r_sym * sym_size);
+ unsigned int shndx = lsym.get_st_shndx();
+ bool is_ordinary;
+ shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+ // If RELOC is a relocation against a local symbol in a
+ // section we are discarding then we can ignore it. It will
+ // eventually become a reloc against the value zero.
+ //
+ // FIXME: We should issue a warning if this is an
+ // allocated section; is this the best place to do it?
+ //
+ // FIXME: The old GNU linker would in some cases look
+ // for the linkonce section which caused this section to
+ // be discarded, and, if the other section was the same
+ // size, change the reloc to refer to the other section.
+ // That seems risky and weird to me, and I don't know of
+ // any case where it is actually required.
+ bool is_discarded = (is_ordinary
+ && shndx != elfcpp::SHN_UNDEF
+ && !object->is_section_included(shndx)
+ && !symtab->is_section_folded(object, shndx));
+ scan.local(symtab, layout, target, object, data_shndx,
+ output_section, reloc, r_type, lsym, is_discarded);
+ }
+ else
+ {
+ Symbol* gsym = object->global_symbol(r_sym);
+ gold_assert(gsym != NULL);
+ if (gsym->is_forwarder())
+ gsym = symtab->resolve_forwards(gsym);
+
+ scan.global(symtab, layout, target, object, data_shndx,
+ output_section, reloc, r_type, gsym);
+ }
+ }
+}
+
+// Behavior for relocations to discarded comdat sections.
+
+enum Comdat_behavior
+{
+ CB_UNDETERMINED, // Not yet determined -- need to look at section name.
+ CB_PRETEND, // Attempt to map to the corresponding kept section.
+ CB_IGNORE, // Ignore the relocation.
+ CB_WARNING // Print a warning.
+};
+
+class Default_comdat_behavior
+{
+ public:
+ // Decide what the linker should do for relocations that refer to
+ // discarded comdat sections. This decision is based on the name of
+ // the section being relocated.
+
+ inline Comdat_behavior
+ get(const char* name)
+ {
+ if (Layout::is_debug_info_section(name))
+ return CB_PRETEND;
+ if (strcmp(name, ".eh_frame") == 0
+ || strcmp(name, ".gcc_except_table") == 0)
+ return CB_IGNORE;
+ return CB_WARNING;
+ }
+};
+
+// Give an error for a symbol with non-default visibility which is not
+// defined locally.
+
+inline void
+visibility_error(const Symbol* sym)
+{
+ const char* v;
+ switch (sym->visibility())
+ {
+ case elfcpp::STV_INTERNAL:
+ v = _("internal");
+ break;
+ case elfcpp::STV_HIDDEN:
+ v = _("hidden");
+ break;
+ case elfcpp::STV_PROTECTED:
+ v = _("protected");
+ break;
+ default:
+ gold_unreachable();
+ }
+ gold_error(_("%s symbol '%s' is not defined locally"),
+ v, sym->name());
+}
+
+// Return true if we are should issue an error saying that SYM is an
+// undefined symbol. This is called if there is a relocation against
+// SYM.
+
+inline bool
+issue_undefined_symbol_error(const Symbol* sym)
+{
+ // We only report global symbols.
+ if (sym == NULL)
+ return false;
+
+ // We only report undefined symbols.
+ if (!sym->is_undefined() && !sym->is_placeholder())
+ return false;
+
+ // We don't report weak symbols.
+ if (sym->binding() == elfcpp::STB_WEAK)
+ return false;
+
+ // We don't report symbols defined in discarded sections.
+ if (sym->is_defined_in_discarded_section())
+ return false;
+
+ // If the target defines this symbol, don't report it here.
+ if (parameters->target().is_defined_by_abi(sym))
+ return false;
+
+ // See if we've been told to ignore whether this symbol is
+ // undefined.
+ const char* const u = parameters->options().unresolved_symbols();
+ if (u != NULL)
+ {
+ if (strcmp(u, "ignore-all") == 0)
+ return false;
+ if (strcmp(u, "report-all") == 0)
+ return true;
+ if (strcmp(u, "ignore-in-object-files") == 0 && !sym->in_dyn())
+ return false;
+ if (strcmp(u, "ignore-in-shared-libs") == 0 && !sym->in_reg())
+ return false;
+ }
+
+ // When creating a shared library, only report unresolved symbols if
+ // -z defs was used.
+ if (parameters->options().shared() && !parameters->options().defs())
+ return false;
+
+ // Otherwise issue a warning.
+ return true;
+}
+
+// This function implements the generic part of relocation processing.
+// The template parameter Relocate must be a class type which provides
+// a single function, relocate(), which implements the machine
+// specific part of a relocation.
+
+// The template parameter Relocate_comdat_behavior is a class type
+// which provides a single function, get(), which determines what the
+// linker should do for relocations that refer to discarded comdat
+// sections.
+
+// SIZE is the ELF size: 32 or 64. BIG_ENDIAN is the endianness of
+// the data. SH_TYPE is the section type: SHT_REL or SHT_RELA.
+// RELOCATE implements operator() to do a relocation.
+
+// 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.
+
+// RELOC_SYMBOL_CHANGES is used for -fsplit-stack support. If it is
+// not NULL, it is a vector indexed by relocation index. If that
+// entry is not NULL, it points to a global symbol which used as the
+// symbol for the relocation, ignoring the symbol index in the
+// relocation.
+
+template<int size, bool big_endian, typename Target_type, int sh_type,
+ typename Relocate,
+ typename Relocate_comdat_behavior>
+inline void
+relocate_section(
+ const Relocate_info<size, big_endian>* relinfo,
+ Target_type* target,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+ section_size_type view_size,
+ const Reloc_symbol_changes* reloc_symbol_changes)
+{
+ typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+ const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+ Relocate relocate;
+ Relocate_comdat_behavior relocate_comdat_behavior;
+
+ Sized_relobj_file<size, big_endian>* object = relinfo->object;
+ unsigned int local_count = object->local_symbol_count();
+
+ Comdat_behavior comdat_behavior = CB_UNDETERMINED;
+
+ for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+ Reltype reloc(prelocs);
+
+ 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;
+ }
+
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+ const Sized_symbol<size>* sym;
+
+ Symbol_value<size> symval;
+ const Symbol_value<size> *psymval;
+ bool is_defined_in_discarded_section;
+ unsigned int shndx;
+ if (r_sym < local_count
+ && (reloc_symbol_changes == NULL
+ || (*reloc_symbol_changes)[i] == NULL))
+ {
+ sym = NULL;
+ psymval = 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
+ && !object->is_section_included(shndx)
+ && !relinfo->symtab->is_section_folded(object, shndx));
+ }
+ else
+ {
+ const Symbol* gsym;
+ if (reloc_symbol_changes != NULL
+ && (*reloc_symbol_changes)[i] != NULL)
+ gsym = (*reloc_symbol_changes)[i];
+ else
+ {
+ gsym = object->global_symbol(r_sym);
+ gold_assert(gsym != NULL);
+ if (gsym->is_forwarder())
+ gsym = relinfo->symtab->resolve_forwards(gsym);
+ }
+
+ sym = static_cast<const Sized_symbol<size>*>(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();
+ symval.set_output_value(sym->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<size> symval2;
+ if (is_defined_in_discarded_section)
+ {
+ if (comdat_behavior == CB_UNDETERMINED)
+ {
+ std::string name = object->section_name(relinfo->data_shndx);
+ comdat_behavior = relocate_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<size>::Elf_Addr value =
+ 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 OFFSET is out of range, still let the target decide to
+ // ignore the relocation. Pass in NULL as the VIEW argument so
+ // that it can return quickly without trashing an invalid memory
+ // address.
+ unsigned char *v = view + offset;
+ if (offset < 0 || static_cast<section_size_type>(offset) >= view_size)
+ v = NULL;
+
+ if (!relocate.relocate(relinfo, target, output_section, i, reloc,
+ r_type, sym, psymval, v, view_address + offset,
+ view_size))
+ continue;
+
+ if (v == NULL)
+ {
+ gold_error_at_location(relinfo, i, offset,
+ _("reloc has bad offset %zu"),
+ static_cast<size_t>(offset));
+ continue;
+ }
+
+ if (issue_undefined_symbol_error(sym))
+ {
+ gold_undefined_symbol_at_location(sym, relinfo, i, offset);
+ if (sym->is_cxx_vtable())
+ gold_info(_("%s: the vtable symbol may be undefined because "
+ "the class is missing its key function"),
+ program_name);
+ }
+ else if (sym != NULL
+ && sym->visibility() != elfcpp::STV_DEFAULT
+ && (sym->is_undefined() || sym->is_from_dynobj()))
+ visibility_error(sym);
+
+ if (sym != NULL && sym->has_warning())
+ relinfo->symtab->issue_warning(sym, relinfo, i, offset);
+ }
+}
+
+// Apply an incremental relocation.
+
+template<int size, bool big_endian, typename Target_type,
+ typename Relocate>
+void
+apply_relocation(const Relocate_info<size, big_endian>* relinfo,
+ Target_type* target,
+ typename elfcpp::Elf_types<size>::Elf_Addr r_offset,
+ unsigned int r_type,
+ typename elfcpp::Elf_types<size>::Elf_Swxword r_addend,
+ const Symbol* gsym,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size)
+{
+ // Construct the ELF relocation in a temporary buffer.
+ const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+ unsigned char relbuf[reloc_size];
+ elfcpp::Rela<size, big_endian> rel(relbuf);
+ elfcpp::Rela_write<size, big_endian> orel(relbuf);
+ orel.put_r_offset(r_offset);
+ orel.put_r_info(elfcpp::elf_r_info<size>(0, r_type));
+ orel.put_r_addend(r_addend);
+
+ // Setup a Symbol_value for the global symbol.
+ const Sized_symbol<size>* sym = static_cast<const Sized_symbol<size>*>(gsym);
+ Symbol_value<size> symval;
+ gold_assert(sym->has_symtab_index() && sym->symtab_index() != -1U);
+ symval.set_output_symtab_index(sym->symtab_index());
+ symval.set_output_value(sym->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();
+
+ Relocate relocate;
+ relocate.relocate(relinfo, target, NULL, -1U, rel, r_type, sym, &symval,
+ view + r_offset, address + r_offset, view_size);
+}
+
+// This class may be used as a typical class for the
+// Scan_relocatable_reloc parameter to scan_relocatable_relocs. The
+// template parameter Classify_reloc must be a class type which
+// provides a function get_size_for_reloc which returns the number of
+// bytes to which a reloc applies. This class is intended to capture
+// the most typical target behaviour, while still permitting targets
+// to define their own independent class for Scan_relocatable_reloc.
+
+template<int sh_type, typename Classify_reloc>
+class Default_scan_relocatable_relocs
+{
+ public:
+ // Return the strategy to use for a local symbol which is not a
+ // section symbol, given the relocation type.
+ inline Relocatable_relocs::Reloc_strategy
+ local_non_section_strategy(unsigned int r_type, Relobj*, unsigned int r_sym)
+ {
+ // We assume that relocation type 0 is NONE. Targets which are
+ // different must override.
+ if (r_type == 0 && r_sym == 0)
+ return Relocatable_relocs::RELOC_DISCARD;
+ return Relocatable_relocs::RELOC_COPY;
+ }
+
+ // 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* object)
+ {
+ if (sh_type == elfcpp::SHT_RELA)
+ return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA;
+ else
+ {
+ Classify_reloc classify;
+ switch (classify.get_size_for_reloc(r_type, object))
+ {
+ case 0:
+ return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0;
+ case 1:
+ return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1;
+ case 2:
+ return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_2;
+ case 4:
+ return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4;
+ case 8:
+ return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_8;
+ default:
+ gold_unreachable();
+ }
+ }
+ }
+
+ // Return the strategy to use for a global symbol, given the
+ // relocation type, the object, and the symbol index.
+ inline Relocatable_relocs::Reloc_strategy
+ global_strategy(unsigned int, Relobj*, unsigned int)
+ { return Relocatable_relocs::RELOC_COPY; }
+};
+
+// Scan relocs during a relocatable link. This is a default
+// definition which should work for most targets.
+// Scan_relocatable_reloc must name a class type which provides three
+// functions which return a Relocatable_relocs::Reloc_strategy code:
+// global_strategy, local_non_section_strategy, and
+// local_section_strategy. Most targets should be able to use
+// Default_scan_relocatable_relocs as this class.
+
+template<int size, bool big_endian, int sh_type,
+ typename Scan_relocatable_reloc>
+void
+scan_relocatable_relocs(
+ Symbol_table*,
+ Layout*,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ 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_syms,
+ Relocatable_relocs* rr)
+{
+ typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+ const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ Scan_relocatable_reloc scan;
+
+ for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+ Reltype reloc(prelocs);
+
+ Relocatable_relocs::Reloc_strategy strategy;
+
+ if (needs_special_offset_handling
+ && !output_section->is_input_address_mapped(object, data_shndx,
+ reloc.get_r_offset()))
+ strategy = Relocatable_relocs::RELOC_DISCARD;
+ else
+ {
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info =
+ reloc.get_r_info();
+ const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ const unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+ if (r_sym >= local_symbol_count)
+ strategy = scan.global_strategy(r_type, object, r_sym);
+ else
+ {
+ gold_assert(plocal_syms != NULL);
+ typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
+ + r_sym * sym_size);
+ unsigned int shndx = lsym.get_st_shndx();
+ bool is_ordinary;
+ shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+ if (is_ordinary
+ && shndx != elfcpp::SHN_UNDEF
+ && !object->is_section_included(shndx))
+ {
+ // RELOC is a relocation against a local symbol
+ // defined in a section we are discarding. Discard
+ // the reloc. FIXME: Should we issue a warning?
+ strategy = Relocatable_relocs::RELOC_DISCARD;
+ }
+ else if (lsym.get_st_type() != elfcpp::STT_SECTION)
+ strategy = scan.local_non_section_strategy(r_type, object,
+ r_sym);
+ else
+ {
+ strategy = scan.local_section_strategy(r_type, object);
+ if (strategy != Relocatable_relocs::RELOC_DISCARD)
+ object->output_section(shndx)->set_needs_symtab_index();
+ }
+
+ if (strategy == Relocatable_relocs::RELOC_COPY)
+ object->set_must_have_output_symtab_entry(r_sym);
+ }
+ }
+
+ rr->set_next_reloc_strategy(strategy);
+ }
+}
+
+// Relocate relocs. Called for a relocatable link, and for --emit-relocs.
+// This is a default definition which should work for most targets.
+
+template<int size, bool big_endian, int sh_type>
+void
+relocate_relocs(
+ const Relocate_info<size, big_endian>* relinfo,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
+ const Relocatable_relocs* rr,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+ section_size_type view_size,
+ unsigned char* reloc_view,
+ section_size_type reloc_view_size)
+{
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+ typedef typename Reloc_types<sh_type, size, big_endian>::Reloc_write
+ Reltype_write;
+ const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+ const Address invalid_address = static_cast<Address>(0) - 1;
+
+ Sized_relobj_file<size, big_endian>* const object = relinfo->object;
+ const unsigned int local_count = object->local_symbol_count();
+
+ unsigned char* pwrite = reloc_view;
+
+ for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+ Relocatable_relocs::Reloc_strategy strategy = rr->strategy(i);
+ if (strategy == Relocatable_relocs::RELOC_DISCARD)
+ continue;
+
+ if (strategy == Relocatable_relocs::RELOC_SPECIAL)
+ {
+ // Target wants to handle this relocation.
+ Sized_target<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
+ target->relocate_special_relocatable(relinfo, sh_type, prelocs,
+ i, output_section,
+ offset_in_output_section,
+ view, view_address,
+ view_size, pwrite);
+ pwrite += reloc_size;
+ continue;
+ }
+ Reltype reloc(prelocs);
+ Reltype_write reloc_write(pwrite);
+
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+ const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ const unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+ // Get the new symbol index.
+
+ unsigned int new_symndx;
+ if (r_sym < local_count)
+ {
+ switch (strategy)
+ {
+ case Relocatable_relocs::RELOC_COPY:
+ if (r_sym == 0)
+ new_symndx = 0;
+ else
+ {
+ new_symndx = object->symtab_index(r_sym);
+ gold_assert(new_symndx != -1U);
+ }
+ break;
+
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA:
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0:
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1:
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_2:
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4:
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_8:
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4_UNALIGNED:
+ {
+ // 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.
+ gold_assert(r_sym < local_count);
+ 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());
+ new_symndx = os->symtab_index();
+ }
+ break;
+
+ default:
+ gold_unreachable();
+ }
+ }
+ else
+ {
+ const Symbol* gsym = object->global_symbol(r_sym);
+ gold_assert(gsym != NULL);
+ if (gsym->is_forwarder())
+ gsym = relinfo->symtab->resolve_forwards(gsym);
+
+ gold_assert(gsym->has_symtab_index());
+ new_symndx = gsym->symtab_index();
+ }
+
+ // Get the new offset--the location in the output section where
+ // this relocation should be applied.
+
+ Address offset = reloc.get_r_offset();
+ 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<section_offset_type, Address>(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<size>(new_symndx, r_type));
+
+ // Handle the reloc addend based on the strategy.
+
+ if (strategy == Relocatable_relocs::RELOC_COPY)
+ {
+ if (sh_type == elfcpp::SHT_RELA)
+ Reloc_types<sh_type, size, big_endian>::
+ copy_reloc_addend(&reloc_write,
+ &reloc);
+ }
+ else
+ {
+ // 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<size>* psymval = object->local_symbol(r_sym);
+
+ unsigned char* padd = view + offset;
+ switch (strategy)
+ {
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA:
+ {
+ typename elfcpp::Elf_types<size>::Elf_Swxword addend;
+ addend = Reloc_types<sh_type, size, big_endian>::
+ get_reloc_addend(&reloc);
+ addend = psymval->value(object, addend);
+ Reloc_types<sh_type, size, big_endian>::
+ set_reloc_addend(&reloc_write, addend);
+ }
+ break;
+
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0:
+ break;
+
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1:
+ Relocate_functions<size, big_endian>::rel8(padd, object,
+ psymval);
+ break;
+
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_2:
+ Relocate_functions<size, big_endian>::rel16(padd, object,
+ psymval);
+ break;
+
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4:
+ Relocate_functions<size, big_endian>::rel32(padd, object,
+ psymval);
+ break;
+
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_8:
+ Relocate_functions<size, big_endian>::rel64(padd, object,
+ psymval);
+ break;
+
+ case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4_UNALIGNED:
+ Relocate_functions<size, big_endian>::rel32_unaligned(padd,
+ object,
+ psymval);
+ break;
+
+ default:
+ gold_unreachable();
+ }
+ }
+
+ pwrite += reloc_size;
+ }
+
+ gold_assert(static_cast<section_size_type>(pwrite - reloc_view)
+ == reloc_view_size);
+}
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_TARGET_RELOC_H)
diff --git a/binutils-2.25/gold/target-select.cc b/binutils-2.25/gold/target-select.cc
new file mode 100644
index 00000000..e17cb7d4
--- /dev/null
+++ b/binutils-2.25/gold/target-select.cc
@@ -0,0 +1,220 @@
+// target-select.cc -- select a target for an object file
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include "gold.h"
+
+#include <cstdio>
+#include <cstring>
+
+#include "elfcpp.h"
+#include "options.h"
+#include "parameters.h"
+#include "target-select.h"
+
+namespace
+{
+
+// The start of the list of target selectors.
+
+gold::Target_selector* target_selectors;
+
+} // End anonymous namespace.
+
+namespace gold
+{
+
+// Class Set_target_once.
+
+void
+Set_target_once::do_run_once(void*)
+{
+ this->target_selector_->set_target();
+}
+
+// Construct a Target_selector, which means adding it to the linked
+// list. This runs at global constructor time, so we want it to be
+// fast.
+
+Target_selector::Target_selector(int machine, int size, bool is_big_endian,
+ const char* bfd_name, const char* emulation)
+ : machine_(machine), size_(size), is_big_endian_(is_big_endian),
+ bfd_name_(bfd_name), emulation_(emulation), instantiated_target_(NULL),
+ set_target_once_(this)
+{
+ this->next_ = target_selectors;
+ target_selectors = this;
+}
+
+// Instantiate the target and return it. Use SET_TARGET_ONCE_ to
+// avoid instantiating two instances of the same target.
+
+Target*
+Target_selector::instantiate_target()
+{
+ this->set_target_once_.run_once(NULL);
+ return this->instantiated_target_;
+}
+
+// Instantiate the target. This is called at most once.
+
+void
+Target_selector::set_target()
+{
+ gold_assert(this->instantiated_target_ == NULL);
+ this->instantiated_target_ = this->do_instantiate_target();
+}
+
+// If we instantiated TARGET, return the corresponding BFD name.
+
+const char*
+Target_selector::do_target_bfd_name(const Target* target)
+{
+ if (!this->is_our_target(target))
+ return NULL;
+ const char* my_bfd_name = this->bfd_name();
+ gold_assert(my_bfd_name != NULL);
+ return my_bfd_name;
+}
+
+// Find the target for an ELF file.
+
+Target*
+select_target(Input_file* input_file, off_t offset,
+ int machine, int size, bool is_big_endian,
+ int osabi, int abiversion)
+{
+ for (Target_selector* p = target_selectors; p != NULL; p = p->next())
+ {
+ int pmach = p->machine();
+ if ((pmach == machine || pmach == elfcpp::EM_NONE)
+ && p->get_size() == size
+ && (p->is_big_endian() ? is_big_endian : !is_big_endian))
+ {
+ Target* ret = p->recognize(input_file, offset,
+ machine, osabi, abiversion);
+ if (ret != NULL)
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+// Find a target using a BFD name. This is used to support the
+// --oformat option.
+
+Target*
+select_target_by_bfd_name(const char* name)
+{
+ for (Target_selector* p = target_selectors; p != NULL; p = p->next())
+ {
+ const char* pname = p->bfd_name();
+ if (pname == NULL || strcmp(pname, name) == 0)
+ {
+ Target* ret = p->recognize_by_bfd_name(name);
+ if (ret != NULL)
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+// Find a target using a GNU linker emulation. This is used to
+// support the -m option.
+
+Target*
+select_target_by_emulation(const char* name)
+{
+ for (Target_selector* p = target_selectors; p != NULL; p = p->next())
+ {
+ const char* pname = p->emulation();
+ if (pname == NULL || strcmp(pname, name) == 0)
+ {
+ Target* ret = p->recognize_by_emulation(name);
+ if (ret != NULL)
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+// Push all the supported BFD names onto a vector.
+
+void
+supported_target_names(std::vector<const char*>* names)
+{
+ for (Target_selector* p = target_selectors; p != NULL; p = p->next())
+ p->supported_bfd_names(names);
+}
+
+// Push all the supported emulations onto a vector.
+
+void
+supported_emulation_names(std::vector<const char*>* names)
+{
+ for (Target_selector* p = target_selectors; p != NULL; p = p->next())
+ p->supported_emulations(names);
+}
+
+// Implement the --print-output-format option.
+
+void
+print_output_format()
+{
+ if (!parameters->target_valid())
+ {
+ // This case arises when --print-output-format is used with no
+ // input files. We need to come up with the right string to
+ // print based on the other options. If the user specified the
+ // format using a --oformat option, use that. That saves each
+ // target from having to remember the name that was used to
+ // select it. In other cases, we will just have to ask the
+ // target.
+ if (parameters->options().user_set_oformat())
+ {
+ const char* bfd_name = parameters->options().oformat();
+ Target* target = select_target_by_bfd_name(bfd_name);
+ if (target != NULL)
+ printf("%s\n", bfd_name);
+ else
+ gold_error(_("unrecognized output format %s"), bfd_name);
+ return;
+ }
+
+ parameters_force_valid_target();
+ }
+
+ const Target* target = &parameters->target();
+ for (Target_selector* p = target_selectors; p != NULL; p = p->next())
+ {
+ const char* bfd_name = p->target_bfd_name(target);
+ if (bfd_name != NULL)
+ {
+ printf("%s\n", bfd_name);
+ return;
+ }
+ }
+
+ gold_unreachable();
+}
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/target-select.h b/binutils-2.25/gold/target-select.h
new file mode 100644
index 00000000..2e16c2a8
--- /dev/null
+++ b/binutils-2.25/gold/target-select.h
@@ -0,0 +1,279 @@
+// target-select.h -- select a target for an object file -*- C++ -*-
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This 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_TARGET_SELECT_H
+#define GOLD_TARGET_SELECT_H
+
+#include <vector>
+
+#include "gold-threads.h"
+
+namespace gold
+{
+
+class Input_file;
+class Target;
+class Target_selector;
+
+// Used to set the target only once.
+
+class Set_target_once : public Once
+{
+ public:
+ Set_target_once(Target_selector* target_selector)
+ : target_selector_(target_selector)
+ { }
+
+ protected:
+ void
+ do_run_once(void*);
+
+ private:
+ Target_selector* target_selector_;
+};
+
+// We want to avoid a master list of targets, which implies using a
+// global constructor. And we also want the program to start up as
+// quickly as possible, which implies avoiding global constructors.
+// We compromise on a very simple global constructor. We use a target
+// selector, which specifies an ELF machine number and a recognition
+// function. We use global constructors to build a linked list of
+// target selectors--a simple pointer list, not a std::list.
+
+class Target_selector
+{
+ public:
+ // Create a target selector for a specific machine number, size (32
+ // or 64), and endianness. The machine number can be EM_NONE to
+ // test for any machine number. BFD_NAME is the name of the target
+ // used by the GNU linker, for backward compatibility; it may be
+ // NULL. EMULATION is the name of the emulation used by the GNU
+ // linker; it is similar to BFD_NAME.
+ Target_selector(int machine, int size, bool is_big_endian,
+ const char* bfd_name, const char* emulation);
+
+ virtual ~Target_selector()
+ { }
+
+ // If we can handle this target, return a pointer to a target
+ // structure. The size and endianness are known.
+ Target*
+ recognize(Input_file* input_file, off_t offset,
+ int machine, int osabi, int abiversion)
+ { return this->do_recognize(input_file, offset, machine, osabi, abiversion); }
+
+ // If NAME matches the target, return a pointer to a target
+ // structure.
+ Target*
+ recognize_by_bfd_name(const char* name)
+ { return this->do_recognize_by_bfd_name(name); }
+
+ // Push all supported BFD names onto the vector. This is only used
+ // for help output.
+ void
+ supported_bfd_names(std::vector<const char*>* names)
+ { this->do_supported_bfd_names(names); }
+
+ // If NAME matches the target emulation, return a pointer to a
+ // target structure.
+ Target*
+ recognize_by_emulation(const char* name)
+ { return this->do_recognize_by_emulation(name); }
+
+ // Push all supported emulations onto the vector. This is only used
+ // for help output.
+ void
+ supported_emulations(std::vector<const char*>* names)
+ { this->do_supported_emulations(names); }
+
+ // Return the next Target_selector in the linked list.
+ Target_selector*
+ next() const
+ { return this->next_; }
+
+ // Return the machine number this selector is looking for. This can
+ // be EM_NONE to match any machine number, in which case the
+ // do_recognize hook will be responsible for matching the machine
+ // number.
+ int
+ machine() const
+ { return this->machine_; }
+
+ // Return the size this is looking for (32 or 64).
+ int
+ get_size() const
+ { return this->size_; }
+
+ // Return the endianness this is looking for.
+ bool
+ is_big_endian() const
+ { return this->is_big_endian_; }
+
+ // Return the BFD name. This may return NULL, in which case the
+ // do_recognize_by_bfd_name hook will be responsible for matching
+ // the BFD name.
+ const char*
+ bfd_name() const
+ { return this->bfd_name_; }
+
+ // Return the emulation. This may return NULL, in which case the
+ // do_recognize_by_emulation hook will be responsible for matching
+ // the emulation.
+ const char*
+ emulation() const
+ { return this->emulation_; }
+
+ // The reverse mapping, for --print-output-format: if we
+ // instantiated TARGET, return our BFD_NAME. If we did not
+ // instantiate it, return NULL.
+ const char*
+ target_bfd_name(const Target* target)
+ { return this->do_target_bfd_name(target); }
+
+ protected:
+ // Return an instance of the real target. This must be implemented
+ // by the child class.
+ virtual Target*
+ do_instantiate_target() = 0;
+
+ // Recognize an object file given a machine code, OSABI code, and
+ // ELF version value. When this is called we already know that they
+ // match the machine_, size_, and is_big_endian_ fields. The child
+ // class may implement a different version of this to do additional
+ // checks, or to check for multiple machine codes if the machine_
+ // field is EM_NONE.
+ virtual Target*
+ do_recognize(Input_file*, off_t, int, int, int)
+ { return this->instantiate_target(); }
+
+ // Recognize a target by name. When this is called we already know
+ // that the name matches (or that the bfd_name_ field is NULL). The
+ // child class may implement a different version of this to
+ // recognize more than one name.
+ virtual Target*
+ do_recognize_by_bfd_name(const char*)
+ { return this->instantiate_target(); }
+
+ // Return a list of supported BFD names. The child class may
+ // implement a different version of this to handle more than one
+ // name.
+ virtual void
+ do_supported_bfd_names(std::vector<const char*>* names)
+ {
+ gold_assert(this->bfd_name_ != NULL);
+ names->push_back(this->bfd_name_);
+ }
+
+ // Recognize a target by emulation. When this is called we already
+ // know that the name matches (or that the emulation_ field is
+ // NULL). The child class may implement a different version of this
+ // to recognize more than one emulation.
+ virtual Target*
+ do_recognize_by_emulation(const char*)
+ { return this->instantiate_target(); }
+
+ // Return a list of supported emulations. The child class may
+ // implement a different version of this to handle more than one
+ // emulation.
+ virtual void
+ do_supported_emulations(std::vector<const char*>* emulations)
+ {
+ gold_assert(this->emulation_ != NULL);
+ emulations->push_back(this->emulation_);
+ }
+
+ // Map from target to BFD name.
+ virtual const char*
+ do_target_bfd_name(const Target*);
+
+ // Instantiate the target and return it.
+ Target*
+ instantiate_target();
+
+ // Return whether TARGET is the target we instantiated.
+ bool
+ is_our_target(const Target* target)
+ { return target == this->instantiated_target_; }
+
+ private:
+ // Set the target.
+ void
+ set_target();
+
+ friend class Set_target_once;
+
+ // ELF machine code.
+ const int machine_;
+ // Target size--32 or 64.
+ const int size_;
+ // Whether the target is big endian.
+ const bool is_big_endian_;
+ // BFD name of target, for compatibility.
+ const char* const bfd_name_;
+ // GNU linker emulation for this target, for compatibility.
+ const char* const emulation_;
+ // Next entry in list built at global constructor time.
+ Target_selector* next_;
+ // The singleton Target structure--this points to an instance of the
+ // real implementation.
+ Target* instantiated_target_;
+ // Used to set the target only once.
+ Set_target_once set_target_once_;
+};
+
+// Select the target for an ELF file.
+
+extern Target*
+select_target(Input_file*, off_t,
+ int machine, int size, bool big_endian, int osabi,
+ int abiversion);
+
+// Select a target using a BFD name.
+
+extern Target*
+select_target_by_bfd_name(const char* name);
+
+// Select a target using a GNU linker emulation.
+
+extern Target*
+select_target_by_emulation(const char* name);
+
+// Fill in a vector with the list of supported targets. This returns
+// a list of BFD names.
+
+extern void
+supported_target_names(std::vector<const char*>*);
+
+// Fill in a vector with the list of supported emulations.
+
+extern void
+supported_emulation_names(std::vector<const char*>*);
+
+// Print the output format, for the --print-output-format option.
+
+extern void
+print_output_format();
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_TARGET_SELECT_H)
diff --git a/binutils-2.25/gold/target.cc b/binutils-2.25/gold/target.cc
new file mode 100644
index 00000000..cad3c95f
--- /dev/null
+++ b/binutils-2.25/gold/target.cc
@@ -0,0 +1,260 @@
+// target.cc -- target support for gold.
+
+// Copyright 2009, 2010, 2011, 2013 Free Software Foundation, Inc.
+// Written by Doug Kwan <dougkwan@google.com>.
+
+// 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 "elfcpp.h"
+#include "dynobj.h"
+#include "symtab.h"
+#include "output.h"
+#include "target.h"
+
+namespace gold
+{
+
+// Return whether NAME is a local label name. This is used to implement the
+// --discard-locals options and can be overridden by child classes to
+// implement system-specific behaviour. The logic here is the same as that
+// in _bfd_elf_is_local_label_name().
+
+bool
+Target::do_is_local_label_name(const char* name) const
+{
+ // Normal local symbols start with ``.L''.
+ if (name[0] == '.' && name[1] == 'L')
+ return true;
+
+ // At least some SVR4 compilers (e.g., UnixWare 2.1 cc) generate
+ // DWARF debugging symbols starting with ``..''.
+ if (name[0] == '.' && name[1] == '.')
+ return true;
+
+ // gcc will sometimes generate symbols beginning with ``_.L_'' when
+ // emitting DWARF debugging output. I suspect this is actually a
+ // small bug in gcc (it calls ASM_OUTPUT_LABEL when it should call
+ // ASM_GENERATE_INTERNAL_LABEL, and this causes the leading
+ // underscore to be emitted on some ELF targets). For ease of use,
+ // we treat such symbols as local.
+ if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')
+ return true;
+
+ return false;
+}
+
+// Implementations of methods Target::do_make_elf_object are almost identical
+// except for the address sizes and endianities. So we extract this
+// into a template.
+
+template<int size, bool big_endian>
+inline Object*
+Target::do_make_elf_object_implementation(
+ const std::string& name,
+ Input_file* input_file,
+ off_t offset,
+ const elfcpp::Ehdr<size, 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()))
+ {
+ Sized_relobj_file<size, big_endian>* obj =
+ new Sized_relobj_file<size, big_endian>(name, input_file, offset, ehdr);
+ obj->setup();
+ return obj;
+ }
+ else if (et == elfcpp::ET_DYN)
+ {
+ Sized_dynobj<size, big_endian>* obj =
+ new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
+ obj->setup();
+ return obj;
+ }
+ else
+ {
+ gold_error(_("%s: unsupported ELF file type %d"),
+ name.c_str(), et);
+ return NULL;
+ }
+}
+
+// Make an ELF object called NAME by reading INPUT_FILE at OFFSET. EHDR
+// is the ELF header of the object. There are four versions of this
+// for different address sizes and endianities.
+
+#ifdef HAVE_TARGET_32_LITTLE
+Object*
+Target::do_make_elf_object(const std::string& name, Input_file* input_file,
+ off_t offset, const elfcpp::Ehdr<32, false>& ehdr)
+{
+ return this->do_make_elf_object_implementation<32, false>(name, input_file,
+ offset, ehdr);
+}
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+Object*
+Target::do_make_elf_object(const std::string& name, Input_file* input_file,
+ off_t offset, const elfcpp::Ehdr<32, true>& ehdr)
+{
+ return this->do_make_elf_object_implementation<32, true>(name, input_file,
+ offset, ehdr);
+}
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+Object*
+Target::do_make_elf_object(const std::string& name, Input_file* input_file,
+ off_t offset, const elfcpp::Ehdr<64, false>& ehdr)
+{
+ return this->do_make_elf_object_implementation<64, false>(name, input_file,
+ offset, ehdr);
+}
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+Object*
+Target::do_make_elf_object(const std::string& name, Input_file* input_file,
+ off_t offset, const elfcpp::Ehdr<64, true>& ehdr)
+{
+ return this->do_make_elf_object_implementation<64, true>(name, input_file,
+ offset, ehdr);
+}
+#endif
+
+Output_section*
+Target::do_make_output_section(const char* name, elfcpp::Elf_Word type,
+ elfcpp::Elf_Xword flags)
+{
+ return new Output_section(name, type, flags);
+}
+
+// Default for whether a reloc is a call to a non-split function is
+// whether the symbol is a function.
+
+bool
+Target::do_is_call_to_non_split(const Symbol* sym, unsigned int) const
+{
+ return sym->type() == elfcpp::STT_FUNC;
+}
+
+// Default conversion for -fsplit-stack is to give an error.
+
+void
+Target::do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
+ section_size_type, unsigned char*, section_size_type,
+ std::string*, std::string*) const
+{
+ static bool warned;
+ if (!warned)
+ {
+ gold_error(_("linker does not include stack split support "
+ "required by %s"),
+ object->name().c_str());
+ warned = true;
+ }
+}
+
+// Return whether BYTES/LEN matches VIEW/VIEW_SIZE at OFFSET.
+
+bool
+Target::match_view(const unsigned char* view, section_size_type view_size,
+ section_offset_type offset, const char* bytes,
+ size_t len) const
+{
+ if (offset + len > view_size)
+ return false;
+ return memcmp(view + offset, bytes, len) == 0;
+}
+
+// Set the contents of a VIEW/VIEW_SIZE to nops starting at OFFSET
+// for LEN bytes.
+
+void
+Target::set_view_to_nop(unsigned char* view, section_size_type view_size,
+ section_offset_type offset, size_t len) const
+{
+ gold_assert(offset >= 0 && offset + len <= view_size);
+ if (!this->has_code_fill())
+ memset(view + offset, 0, len);
+ else
+ {
+ std::string fill = this->code_fill(len);
+ memcpy(view + offset, fill.data(), len);
+ }
+}
+
+// Return address and size to plug into eh_frame FDEs associated with a PLT.
+void
+Target::do_plt_fde_location(const Output_data* plt, unsigned char*,
+ uint64_t* address, off_t* len) const
+{
+ *address = plt->address();
+ *len = plt->data_size();
+}
+
+// Class Sized_target.
+
+// Set the EI_OSABI field of the ELF header if requested.
+
+template<int size, bool big_endian>
+void
+Sized_target<size, big_endian>::do_adjust_elf_header(unsigned char* view,
+ int len)
+{
+ elfcpp::ELFOSABI osabi = this->osabi();
+ if (osabi != elfcpp::ELFOSABI_NONE)
+ {
+ gold_assert(len == elfcpp::Elf_sizes<size>::ehdr_size);
+
+ elfcpp::Ehdr<size, big_endian> ehdr(view);
+ unsigned char e_ident[elfcpp::EI_NIDENT];
+ memcpy(e_ident, ehdr.get_e_ident(), elfcpp::EI_NIDENT);
+
+ e_ident[elfcpp::EI_OSABI] = osabi;
+
+ elfcpp::Ehdr_write<size, big_endian> oehdr(view);
+ oehdr.put_e_ident(e_ident);
+ }
+}
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Sized_target<32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Sized_target<32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Sized_target<64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Sized_target<64, true>;
+#endif
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/target.h b/binutils-2.25/gold/target.h
new file mode 100644
index 00000000..415b7edc
--- /dev/null
+++ b/binutils-2.25/gold/target.h
@@ -0,0 +1,1037 @@
+// target.h -- target support for gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
+// Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 abstract class Target is the interface for target specific
+// support. It defines abstract methods which each target must
+// implement. Typically there will be one target per processor, but
+// in some cases it may be necessary to have subclasses.
+
+// For speed and consistency we want to use inline functions to handle
+// relocation processing. So besides implementations of the abstract
+// methods, each target is expected to define a template
+// specialization of the relocation functions.
+
+#ifndef GOLD_TARGET_H
+#define GOLD_TARGET_H
+
+#include "elfcpp.h"
+#include "options.h"
+#include "parameters.h"
+#include "debug.h"
+
+namespace gold
+{
+
+class Object;
+class Relobj;
+template<int size, bool big_endian>
+class Sized_relobj;
+template<int size, bool big_endian>
+class Sized_relobj_file;
+class Relocatable_relocs;
+template<int size, bool big_endian>
+struct Relocate_info;
+class Reloc_symbol_changes;
+class Symbol;
+template<int size>
+class Sized_symbol;
+class Symbol_table;
+class Output_data;
+class Output_data_got_base;
+class Output_section;
+class Input_objects;
+class Task;
+struct Symbol_location;
+
+// The abstract class for target specific handling.
+
+class Target
+{
+ public:
+ virtual ~Target()
+ { }
+
+ // Return the bit size that this target implements. This should
+ // return 32 or 64.
+ int
+ get_size() const
+ { return this->pti_->size; }
+
+ // Return whether this target is big-endian.
+ bool
+ is_big_endian() const
+ { return this->pti_->is_big_endian; }
+
+ // Machine code to store in e_machine field of ELF header.
+ elfcpp::EM
+ machine_code() const
+ { return this->pti_->machine_code; }
+
+ // Processor specific flags to store in e_flags field of ELF header.
+ elfcpp::Elf_Word
+ processor_specific_flags() const
+ { return this->processor_specific_flags_; }
+
+ // Whether processor specific flags are set at least once.
+ bool
+ are_processor_specific_flags_set() const
+ { return this->are_processor_specific_flags_set_; }
+
+ // Whether this target has a specific make_symbol function.
+ bool
+ has_make_symbol() const
+ { return this->pti_->has_make_symbol; }
+
+ // Whether this target has a specific resolve function.
+ bool
+ has_resolve() const
+ { return this->pti_->has_resolve; }
+
+ // Whether this target has a specific code fill function.
+ bool
+ has_code_fill() const
+ { return this->pti_->has_code_fill; }
+
+ // Return the default name of the dynamic linker.
+ const char*
+ dynamic_linker() const
+ { return this->pti_->dynamic_linker; }
+
+ // Return the default address to use for the text segment.
+ uint64_t
+ default_text_segment_address() const
+ { return this->pti_->default_text_segment_address; }
+
+ // Return the ABI specified page size.
+ uint64_t
+ abi_pagesize() const
+ {
+ if (parameters->options().max_page_size() > 0)
+ return parameters->options().max_page_size();
+ else
+ return this->pti_->abi_pagesize;
+ }
+
+ // Return the common page size used on actual systems.
+ uint64_t
+ common_pagesize() const
+ {
+ if (parameters->options().common_page_size() > 0)
+ return std::min(parameters->options().common_page_size(),
+ this->abi_pagesize());
+ else
+ return std::min(this->pti_->common_pagesize,
+ this->abi_pagesize());
+ }
+
+ // Return whether PF_X segments must contain nothing but the contents of
+ // SHF_EXECINSTR sections (no non-executable data, no headers).
+ bool
+ isolate_execinstr() const
+ { return this->pti_->isolate_execinstr; }
+
+ uint64_t
+ rosegment_gap() const
+ { return this->pti_->rosegment_gap; }
+
+ // If we see some object files with .note.GNU-stack sections, and
+ // some objects files without them, this returns whether we should
+ // consider the object files without them to imply that the stack
+ // should be executable.
+ bool
+ is_default_stack_executable() const
+ { return this->pti_->is_default_stack_executable; }
+
+ // Return a character which may appear as a prefix for a wrap
+ // symbol. If this character appears, we strip it when checking for
+ // wrapping and add it back when forming the final symbol name.
+ // This should be '\0' if not special prefix is required, which is
+ // the normal case.
+ char
+ wrap_char() const
+ { return this->pti_->wrap_char; }
+
+ // Return the special section index which indicates a small common
+ // symbol. This will return SHN_UNDEF if there are no small common
+ // symbols.
+ elfcpp::Elf_Half
+ small_common_shndx() const
+ { return this->pti_->small_common_shndx; }
+
+ // Return values to add to the section flags for the section holding
+ // small common symbols.
+ elfcpp::Elf_Xword
+ small_common_section_flags() const
+ {
+ gold_assert(this->pti_->small_common_shndx != elfcpp::SHN_UNDEF);
+ return this->pti_->small_common_section_flags;
+ }
+
+ // Return the special section index which indicates a large common
+ // symbol. This will return SHN_UNDEF if there are no large common
+ // symbols.
+ elfcpp::Elf_Half
+ large_common_shndx() const
+ { return this->pti_->large_common_shndx; }
+
+ // Return values to add to the section flags for the section holding
+ // large common symbols.
+ elfcpp::Elf_Xword
+ large_common_section_flags() const
+ {
+ gold_assert(this->pti_->large_common_shndx != elfcpp::SHN_UNDEF);
+ return this->pti_->large_common_section_flags;
+ }
+
+ // This hook is called when an output section is created.
+ void
+ new_output_section(Output_section* os) const
+ { this->do_new_output_section(os); }
+
+ // This is called to tell the target to complete any sections it is
+ // handling. After this all sections must have their final size.
+ void
+ finalize_sections(Layout* layout, const Input_objects* input_objects,
+ Symbol_table* symtab)
+ { return this->do_finalize_sections(layout, input_objects, symtab); }
+
+ // Return the value to use for a global symbol which needs a special
+ // value in the dynamic symbol table. This will only be called if
+ // the backend first calls symbol->set_needs_dynsym_value().
+ uint64_t
+ dynsym_value(const Symbol* sym) const
+ { return this->do_dynsym_value(sym); }
+
+ // Return a string to use to fill out a code section. This is
+ // basically one or more NOPS which must fill out the specified
+ // length in bytes.
+ std::string
+ code_fill(section_size_type length) const
+ { return this->do_code_fill(length); }
+
+ // Return whether SYM is known to be defined by the ABI. This is
+ // used to avoid inappropriate warnings about undefined symbols.
+ bool
+ is_defined_by_abi(const Symbol* sym) const
+ { return this->do_is_defined_by_abi(sym); }
+
+ // Adjust the output file header before it is written out. VIEW
+ // points to the header in external form. LEN is the length.
+ void
+ adjust_elf_header(unsigned char* view, int len)
+ { return this->do_adjust_elf_header(view, len); }
+
+ // Return address and size to plug into eh_frame FDEs associated with a PLT.
+ void
+ plt_fde_location(const Output_data* plt, unsigned char* oview,
+ uint64_t* address, off_t* len) const
+ { return this->do_plt_fde_location(plt, oview, address, len); }
+
+ // Return whether NAME is a local label name. This is used to implement the
+ // --discard-locals options.
+ bool
+ is_local_label_name(const char* name) const
+ { return this->do_is_local_label_name(name); }
+
+ // Get the symbol index to use for a target specific reloc.
+ unsigned int
+ reloc_symbol_index(void* arg, unsigned int type) const
+ { return this->do_reloc_symbol_index(arg, type); }
+
+ // Get the addend to use for a target specific reloc.
+ uint64_t
+ reloc_addend(void* arg, unsigned int type, uint64_t addend) const
+ { return this->do_reloc_addend(arg, type, addend); }
+
+ // Return the PLT address to use for a global symbol.
+ uint64_t
+ plt_address_for_global(const Symbol* sym) const
+ { return this->do_plt_address_for_global(sym); }
+
+ // Return the PLT address to use for a local symbol.
+ uint64_t
+ plt_address_for_local(const Relobj* object, unsigned int symndx) const
+ { return this->do_plt_address_for_local(object, symndx); }
+
+ // Return the offset to use for the GOT_INDX'th got entry which is
+ // for a local tls symbol specified by OBJECT, SYMNDX.
+ int64_t
+ tls_offset_for_local(const Relobj* object,
+ unsigned int symndx,
+ unsigned int got_indx) const
+ { return do_tls_offset_for_local(object, symndx, got_indx); }
+
+ // Return the offset to use for the GOT_INDX'th got entry which is
+ // for global tls symbol GSYM.
+ int64_t
+ tls_offset_for_global(Symbol* gsym, unsigned int got_indx) const
+ { return do_tls_offset_for_global(gsym, got_indx); }
+
+ // For targets that use function descriptors, if LOC is the location
+ // of a function, modify it to point at the function entry location.
+ void
+ function_location(Symbol_location* loc) const
+ { return do_function_location(loc); }
+
+ // Return whether this target can use relocation types to determine
+ // if a function's address is taken.
+ bool
+ can_check_for_function_pointers() const
+ { return this->do_can_check_for_function_pointers(); }
+
+ // Return whether a relocation to a merged section can be processed
+ // to retrieve the contents.
+ bool
+ can_icf_inline_merge_sections () const
+ { return this->pti_->can_icf_inline_merge_sections; }
+
+ // Whether a section called SECTION_NAME may have function pointers to
+ // sections not eligible for safe ICF folding.
+ virtual bool
+ section_may_have_icf_unsafe_pointers(const char* section_name) const
+ { return this->do_section_may_have_icf_unsafe_pointers(section_name); }
+
+ // Return the base to use for the PC value in an FDE when it is
+ // encoded using DW_EH_PE_datarel. This does not appear to be
+ // documented anywhere, but it is target specific. Any use of
+ // DW_EH_PE_datarel in gcc requires defining a special macro
+ // (ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX) to output the value.
+ uint64_t
+ ehframe_datarel_base() const
+ { return this->do_ehframe_datarel_base(); }
+
+ // Return true if a reference to SYM from a reloc of type R_TYPE
+ // means that the current function may call an object compiled
+ // without -fsplit-stack. SYM is known to be defined in an object
+ // compiled without -fsplit-stack.
+ bool
+ is_call_to_non_split(const Symbol* sym, unsigned int r_type) const
+ { return this->do_is_call_to_non_split(sym, r_type); }
+
+ // A function starts at OFFSET in section SHNDX in OBJECT. That
+ // function was compiled with -fsplit-stack, but it refers to a
+ // function which was compiled without -fsplit-stack. VIEW is a
+ // modifiable view of the section; VIEW_SIZE is the size of the
+ // view. The target has to adjust the function so that it allocates
+ // enough stack.
+ void
+ 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
+ {
+ this->do_calls_non_split(object, shndx, fnoffset, fnsize, view, view_size,
+ from, to);
+ }
+
+ // Make an ELF object.
+ template<int size, bool big_endian>
+ Object*
+ make_elf_object(const std::string& name, Input_file* input_file,
+ off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
+ { return this->do_make_elf_object(name, input_file, offset, ehdr); }
+
+ // Make an output section.
+ Output_section*
+ make_output_section(const char* name, elfcpp::Elf_Word type,
+ elfcpp::Elf_Xword flags)
+ { return this->do_make_output_section(name, type, flags); }
+
+ // Return true if target wants to perform relaxation.
+ bool
+ may_relax() const
+ {
+ // Run the dummy relaxation pass twice if relaxation debugging is enabled.
+ if (is_debugging_enabled(DEBUG_RELAXATION))
+ return true;
+
+ return this->do_may_relax();
+ }
+
+ // Perform a relaxation pass. Return true if layout may be changed.
+ bool
+ relax(int pass, const Input_objects* input_objects, Symbol_table* symtab,
+ Layout* layout, const Task* task)
+ {
+ // Run the dummy relaxation pass twice if relaxation debugging is enabled.
+ if (is_debugging_enabled(DEBUG_RELAXATION))
+ return pass < 2;
+
+ return this->do_relax(pass, input_objects, symtab, layout, task);
+ }
+
+ // Return the target-specific name of attributes section. This is
+ // NULL if a target does not use attributes section or if it uses
+ // the default section name ".gnu.attributes".
+ const char*
+ attributes_section() const
+ { return this->pti_->attributes_section; }
+
+ // Return the vendor name of vendor attributes.
+ const char*
+ attributes_vendor() const
+ { return this->pti_->attributes_vendor; }
+
+ // Whether a section called NAME is an attribute section.
+ bool
+ is_attributes_section(const char* name) const
+ {
+ return ((this->pti_->attributes_section != NULL
+ && strcmp(name, this->pti_->attributes_section) == 0)
+ || strcmp(name, ".gnu.attributes") == 0);
+ }
+
+ // Return a bit mask of argument types for attribute with TAG.
+ int
+ attribute_arg_type(int tag) const
+ { return this->do_attribute_arg_type(tag); }
+
+ // Return the attribute tag of the position NUM in the list of fixed
+ // attributes. Normally there is no reordering and
+ // attributes_order(NUM) == NUM.
+ int
+ attributes_order(int num) const
+ { return this->do_attributes_order(num); }
+
+ // When a target is selected as the default target, we call this method,
+ // which may be used for expensive, target-specific initialization.
+ void
+ select_as_default_target()
+ { this->do_select_as_default_target(); }
+
+ // Return the value to store in the EI_OSABI field in the ELF
+ // header.
+ elfcpp::ELFOSABI
+ osabi() const
+ { return this->osabi_; }
+
+ // Set the value to store in the EI_OSABI field in the ELF header.
+ void
+ set_osabi(elfcpp::ELFOSABI osabi)
+ { this->osabi_ = osabi; }
+
+ // Define target-specific standard symbols.
+ void
+ define_standard_symbols(Symbol_table* symtab, Layout* layout)
+ { this->do_define_standard_symbols(symtab, layout); }
+
+ // Return the output section name to use given an input section
+ // name, or NULL if no target specific name mapping is required.
+ // Set *PLEN to the length of the name if returning non-NULL.
+ const char*
+ output_section_name(const Relobj* relobj,
+ const char* name,
+ size_t* plen) const
+ { return this->do_output_section_name(relobj, name, plen); }
+
+ // Add any special sections for this symbol to the gc work list.
+ void
+ gc_mark_symbol(Symbol_table* symtab, Symbol* sym) const
+ { this->do_gc_mark_symbol(symtab, sym); }
+
+ // Return the name of the entry point symbol.
+ const char*
+ entry_symbol_name() const
+ { return this->pti_->entry_symbol_name; }
+
+ protected:
+ // This struct holds the constant information for a child class. We
+ // use a struct to avoid the overhead of virtual function calls for
+ // simple information.
+ struct Target_info
+ {
+ // Address size (32 or 64).
+ int size;
+ // Whether the target is big endian.
+ bool is_big_endian;
+ // The code to store in the e_machine field of the ELF header.
+ elfcpp::EM machine_code;
+ // Whether this target has a specific make_symbol function.
+ bool has_make_symbol;
+ // Whether this target has a specific resolve function.
+ bool has_resolve;
+ // Whether this target has a specific code fill function.
+ bool has_code_fill;
+ // Whether an object file with no .note.GNU-stack sections implies
+ // that the stack should be executable.
+ bool is_default_stack_executable;
+ // Whether a relocation to a merged section can be processed to
+ // retrieve the contents.
+ bool can_icf_inline_merge_sections;
+ // Prefix character to strip when checking for wrapping.
+ char wrap_char;
+ // The default dynamic linker name.
+ const char* dynamic_linker;
+ // The default text segment address.
+ uint64_t default_text_segment_address;
+ // The ABI specified page size.
+ uint64_t abi_pagesize;
+ // The common page size used by actual implementations.
+ uint64_t common_pagesize;
+ // Whether PF_X segments must contain nothing but the contents of
+ // SHF_EXECINSTR sections (no non-executable data, no headers).
+ bool isolate_execinstr;
+ // If nonzero, distance from the text segment to the read-only segment.
+ uint64_t rosegment_gap;
+ // The special section index for small common symbols; SHN_UNDEF
+ // if none.
+ elfcpp::Elf_Half small_common_shndx;
+ // The special section index for large common symbols; SHN_UNDEF
+ // if none.
+ elfcpp::Elf_Half large_common_shndx;
+ // Section flags for small common section.
+ elfcpp::Elf_Xword small_common_section_flags;
+ // Section flags for large common section.
+ elfcpp::Elf_Xword large_common_section_flags;
+ // Name of attributes section if it is not ".gnu.attributes".
+ const char* attributes_section;
+ // Vendor name of vendor attributes.
+ const char* attributes_vendor;
+ // Name of the main entry point to the program.
+ const char* entry_symbol_name;
+ };
+
+ Target(const Target_info* pti)
+ : pti_(pti), processor_specific_flags_(0),
+ are_processor_specific_flags_set_(false), osabi_(elfcpp::ELFOSABI_NONE)
+ { }
+
+ // Virtual function which may be implemented by the child class.
+ virtual void
+ do_new_output_section(Output_section*) const
+ { }
+
+ // Virtual function which may be implemented by the child class.
+ virtual void
+ do_finalize_sections(Layout*, const Input_objects*, Symbol_table*)
+ { }
+
+ // Virtual function which may be implemented by the child class.
+ virtual uint64_t
+ do_dynsym_value(const Symbol*) const
+ { gold_unreachable(); }
+
+ // Virtual function which must be implemented by the child class if
+ // needed.
+ virtual std::string
+ do_code_fill(section_size_type) const
+ { gold_unreachable(); }
+
+ // Virtual function which may be implemented by the child class.
+ virtual bool
+ do_is_defined_by_abi(const Symbol*) const
+ { return false; }
+
+ // Adjust the output file header before it is written out. VIEW
+ // points to the header in external form. LEN is the length, and
+ // will be one of the values of elfcpp::Elf_sizes<size>::ehdr_size.
+ // By default, we set the EI_OSABI field if requested (in
+ // Sized_target).
+ virtual void
+ do_adjust_elf_header(unsigned char*, int) = 0;
+
+ // Return address and size to plug into eh_frame FDEs associated with a PLT.
+ virtual void
+ do_plt_fde_location(const Output_data* plt, unsigned char* oview,
+ uint64_t* address, off_t* len) const;
+
+ // Virtual function which may be overridden by the child class.
+ virtual bool
+ do_is_local_label_name(const char*) const;
+
+ // Virtual function that must be overridden by a target which uses
+ // target specific relocations.
+ virtual unsigned int
+ do_reloc_symbol_index(void*, unsigned int) const
+ { gold_unreachable(); }
+
+ // Virtual function that must be overridden by a target which uses
+ // target specific relocations.
+ virtual uint64_t
+ do_reloc_addend(void*, unsigned int, uint64_t) const
+ { gold_unreachable(); }
+
+ // Virtual functions that must be overridden by a target that uses
+ // STT_GNU_IFUNC symbols.
+ virtual uint64_t
+ do_plt_address_for_global(const Symbol*) const
+ { gold_unreachable(); }
+
+ virtual uint64_t
+ do_plt_address_for_local(const Relobj*, unsigned int) const
+ { gold_unreachable(); }
+
+ virtual int64_t
+ do_tls_offset_for_local(const Relobj*, unsigned int, unsigned int) const
+ { gold_unreachable(); }
+
+ virtual int64_t
+ do_tls_offset_for_global(Symbol*, unsigned int) const
+ { gold_unreachable(); }
+
+ virtual void
+ do_function_location(Symbol_location*) const = 0;
+
+ // Virtual function which may be overriden by the child class.
+ virtual bool
+ do_can_check_for_function_pointers() const
+ { return false; }
+
+ // Virtual function which may be overridden by the child class. We
+ // recognize some default sections for which we don't care whether
+ // they have function pointers.
+ virtual bool
+ do_section_may_have_icf_unsafe_pointers(const char* section_name) const
+ {
+ // We recognize sections for normal vtables, construction vtables and
+ // EH frames.
+ return (!is_prefix_of(".rodata._ZTV", section_name)
+ && !is_prefix_of(".data.rel.ro._ZTV", section_name)
+ && !is_prefix_of(".rodata._ZTC", section_name)
+ && !is_prefix_of(".data.rel.ro._ZTC", section_name)
+ && !is_prefix_of(".eh_frame", section_name));
+ }
+
+ virtual uint64_t
+ do_ehframe_datarel_base() const
+ { gold_unreachable(); }
+
+ // Virtual function which may be overridden by the child class. The
+ // default implementation is that any function not defined by the
+ // ABI is a call to a non-split function.
+ virtual bool
+ do_is_call_to_non_split(const Symbol* sym, unsigned int) const;
+
+ // Virtual function which may be overridden by the child class.
+ virtual void
+ do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
+ section_size_type, unsigned char*, section_size_type,
+ std::string*, std::string*) const;
+
+ // make_elf_object hooks. There are four versions of these for
+ // different address sizes and endianness.
+
+ // Set processor specific flags.
+ void
+ set_processor_specific_flags(elfcpp::Elf_Word flags)
+ {
+ this->processor_specific_flags_ = flags;
+ this->are_processor_specific_flags_set_ = true;
+ }
+
+#ifdef HAVE_TARGET_32_LITTLE
+ // Virtual functions which may be overridden by the child class.
+ virtual Object*
+ do_make_elf_object(const std::string&, Input_file*, off_t,
+ const elfcpp::Ehdr<32, false>&);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+ // Virtual functions which may be overridden by the child class.
+ virtual Object*
+ do_make_elf_object(const std::string&, Input_file*, off_t,
+ const elfcpp::Ehdr<32, true>&);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+ // Virtual functions which may be overridden by the child class.
+ virtual Object*
+ do_make_elf_object(const std::string&, Input_file*, off_t,
+ const elfcpp::Ehdr<64, false>& ehdr);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+ // Virtual functions which may be overridden by the child class.
+ virtual Object*
+ do_make_elf_object(const std::string& name, Input_file* input_file,
+ off_t offset, const elfcpp::Ehdr<64, true>& ehdr);
+#endif
+
+ // Virtual functions which may be overridden by the child class.
+ virtual Output_section*
+ do_make_output_section(const char* name, elfcpp::Elf_Word type,
+ elfcpp::Elf_Xword flags);
+
+ // Virtual function which may be overridden by the child class.
+ virtual bool
+ do_may_relax() const
+ { return parameters->options().relax(); }
+
+ // Virtual function which may be overridden by the child class.
+ virtual bool
+ do_relax(int, const Input_objects*, Symbol_table*, Layout*, const Task*)
+ { return false; }
+
+ // A function for targets to call. Return whether BYTES/LEN matches
+ // VIEW/VIEW_SIZE at OFFSET.
+ bool
+ match_view(const unsigned char* view, section_size_type view_size,
+ section_offset_type offset, const char* bytes, size_t len) const;
+
+ // Set the contents of a VIEW/VIEW_SIZE to nops starting at OFFSET
+ // for LEN bytes.
+ void
+ set_view_to_nop(unsigned char* view, section_size_type view_size,
+ section_offset_type offset, size_t len) const;
+
+ // This must be overridden by the child class if it has target-specific
+ // attributes subsection in the attribute section.
+ virtual int
+ do_attribute_arg_type(int) const
+ { gold_unreachable(); }
+
+ // This may be overridden by the child class.
+ virtual int
+ do_attributes_order(int num) const
+ { return num; }
+
+ // This may be overridden by the child class.
+ virtual void
+ do_select_as_default_target()
+ { }
+
+ // This may be overridden by the child class.
+ virtual void
+ do_define_standard_symbols(Symbol_table*, Layout*)
+ { }
+
+ // This may be overridden by the child class.
+ virtual const char*
+ do_output_section_name(const Relobj*, const char*, size_t*) const
+ { return NULL; }
+
+ // This may be overridden by the child class.
+ virtual void
+ do_gc_mark_symbol(Symbol_table*, Symbol*) const
+ { }
+
+ private:
+ // The implementations of the four do_make_elf_object virtual functions are
+ // almost identical except for their sizes and endianness. We use a template.
+ // for their implementations.
+ template<int size, bool big_endian>
+ inline Object*
+ do_make_elf_object_implementation(const std::string&, Input_file*, off_t,
+ const elfcpp::Ehdr<size, big_endian>&);
+
+ Target(const Target&);
+ Target& operator=(const Target&);
+
+ // The target information.
+ const Target_info* pti_;
+ // Processor-specific flags.
+ elfcpp::Elf_Word processor_specific_flags_;
+ // Whether the processor-specific flags are set at least once.
+ bool are_processor_specific_flags_set_;
+ // If not ELFOSABI_NONE, the value to put in the EI_OSABI field of
+ // the ELF header. This is handled at this level because it is
+ // OS-specific rather than processor-specific.
+ elfcpp::ELFOSABI osabi_;
+};
+
+// The abstract class for a specific size and endianness of target.
+// Each actual target implementation class should derive from an
+// instantiation of Sized_target.
+
+template<int size, bool big_endian>
+class Sized_target : public Target
+{
+ public:
+ // Make a new symbol table entry for the target. This should be
+ // overridden by a target which needs additional information in the
+ // symbol table. This will only be called if has_make_symbol()
+ // returns true.
+ virtual Sized_symbol<size>*
+ make_symbol() const
+ { gold_unreachable(); }
+
+ // Resolve a symbol for the target. This should be overridden by a
+ // target which needs to take special action. TO is the
+ // pre-existing symbol. SYM is the new symbol, seen in OBJECT.
+ // VERSION is the version of SYM. This will only be called if
+ // has_resolve() returns true.
+ virtual void
+ resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*,
+ const char*)
+ { gold_unreachable(); }
+
+ // Process the relocs for a section, and record information of the
+ // mapping from source to destination sections. This mapping is later
+ // used to determine unreferenced garbage sections. This procedure is
+ // only called during garbage collection.
+ virtual void
+ gc_process_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols) = 0;
+
+ // Scan the relocs for a section, and record any information
+ // required for the symbol. SYMTAB is the symbol table. OBJECT is
+ // the object in which the section appears. DATA_SHNDX is the
+ // section index that these relocs apply to. SH_TYPE is the type of
+ // the relocation section, SHT_REL or SHT_RELA. PRELOCS points to
+ // the relocation data. RELOC_COUNT is the number of relocs.
+ // LOCAL_SYMBOL_COUNT is the number of local symbols.
+ // OUTPUT_SECTION is the output section.
+ // NEEDS_SPECIAL_OFFSET_HANDLING is true if offsets to the output
+ // sections are not mapped as usual. PLOCAL_SYMBOLS points to the
+ // local symbol data from OBJECT. GLOBAL_SYMBOLS is the array of
+ // pointers to the global symbol table from OBJECT.
+ virtual void
+ scan_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols) = 0;
+
+ // Relocate section data. SH_TYPE is the type of the relocation
+ // section, SHT_REL or SHT_RELA. PRELOCS points to the relocation
+ // information. RELOC_COUNT is the number of relocs.
+ // OUTPUT_SECTION is the output section.
+ // NEEDS_SPECIAL_OFFSET_HANDLING is true if offsets must be mapped
+ // to correspond to the output section. VIEW is a view into the
+ // output file holding the section contents, VIEW_ADDRESS is the
+ // virtual address of the view, and VIEW_SIZE is the size of the
+ // view. If NEEDS_SPECIAL_OFFSET_HANDLING is true, the VIEW_xx
+ // parameters refer to the complete output section data, not just
+ // the input section data.
+ virtual void
+ relocate_section(const Relocate_info<size, 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,
+ typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+ section_size_type view_size,
+ const Reloc_symbol_changes*) = 0;
+
+ // Scan the relocs during a relocatable link. The parameters are
+ // like scan_relocs, with an additional Relocatable_relocs
+ // parameter, used to record the disposition of the relocs.
+ virtual void
+ scan_relocatable_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols,
+ Relocatable_relocs*) = 0;
+
+ // Emit relocations for a section during a relocatable link, and for
+ // --emit-relocs. The parameters are like relocate_section, with
+ // additional parameters for the view of the output reloc section.
+ virtual void
+ relocate_relocs(const Relocate_info<size, big_endian>*,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ typename elfcpp::Elf_types<size>::Elf_Off
+ offset_in_output_section,
+ const Relocatable_relocs*,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+ section_size_type view_size,
+ unsigned char* reloc_view,
+ section_size_type reloc_view_size) = 0;
+
+ // Perform target-specific processing in a relocatable link. This is
+ // only used if we use the relocation strategy RELOC_SPECIAL.
+ // RELINFO points to a Relocation_info structure. SH_TYPE is the relocation
+ // section type. PRELOC_IN points to the original relocation. RELNUM is
+ // the index number of the relocation in the relocation section.
+ // OUTPUT_SECTION is the output section to which the relocation is applied.
+ // OFFSET_IN_OUTPUT_SECTION is the offset of the relocation input section
+ // within the output section. VIEW points to the output view of the
+ // output section. VIEW_ADDRESS is output address of the view. VIEW_SIZE
+ // is the size of the output view and PRELOC_OUT points to the new
+ // relocation in the output object.
+ //
+ // A target only needs to override this if the generic code in
+ // target-reloc.h cannot handle some relocation types.
+
+ virtual void
+ relocate_special_relocatable(const Relocate_info<size, big_endian>*
+ /*relinfo */,
+ unsigned int /* sh_type */,
+ const unsigned char* /* preloc_in */,
+ size_t /* relnum */,
+ Output_section* /* output_section */,
+ typename elfcpp::Elf_types<size>::Elf_Off
+ /* offset_in_output_section */,
+ unsigned char* /* view */,
+ typename elfcpp::Elf_types<size>::Elf_Addr
+ /* view_address */,
+ section_size_type /* view_size */,
+ unsigned char* /* preloc_out*/)
+ { gold_unreachable(); }
+
+ // Return the number of entries in the GOT. This is only used for
+ // laying out the incremental link info sections. A target needs
+ // to implement this to support incremental linking.
+
+ virtual unsigned int
+ got_entry_count() const
+ { gold_unreachable(); }
+
+ // Return the number of entries in the PLT. This is only used for
+ // laying out the incremental link info sections. A target needs
+ // to implement this to support incremental linking.
+
+ virtual unsigned int
+ plt_entry_count() const
+ { gold_unreachable(); }
+
+ // Return the offset of the first non-reserved PLT entry. This is
+ // only used for laying out the incremental link info sections.
+ // A target needs to implement this to support incremental linking.
+
+ virtual unsigned int
+ first_plt_entry_offset() const
+ { gold_unreachable(); }
+
+ // Return the size of each PLT entry. This is only used for
+ // laying out the incremental link info sections. A target needs
+ // to implement this to support incremental linking.
+
+ virtual unsigned int
+ plt_entry_size() const
+ { gold_unreachable(); }
+
+ // Create the GOT and PLT sections for an incremental update.
+ // A target needs to implement this to support incremental linking.
+
+ virtual Output_data_got_base*
+ init_got_plt_for_update(Symbol_table*,
+ Layout*,
+ unsigned int /* got_count */,
+ unsigned int /* plt_count */)
+ { gold_unreachable(); }
+
+ // Reserve a GOT entry for a local symbol, and regenerate any
+ // necessary dynamic relocations.
+ virtual void
+ reserve_local_got_entry(unsigned int /* got_index */,
+ Sized_relobj<size, big_endian>* /* obj */,
+ unsigned int /* r_sym */,
+ unsigned int /* got_type */)
+ { gold_unreachable(); }
+
+ // Reserve a GOT entry for a global symbol, and regenerate any
+ // necessary dynamic relocations.
+ virtual void
+ reserve_global_got_entry(unsigned int /* got_index */, Symbol* /* gsym */,
+ unsigned int /* got_type */)
+ { gold_unreachable(); }
+
+ // Register an existing PLT entry for a global symbol.
+ // A target needs to implement this to support incremental linking.
+
+ virtual void
+ register_global_plt_entry(Symbol_table*, Layout*,
+ unsigned int /* plt_index */,
+ Symbol*)
+ { gold_unreachable(); }
+
+ // Force a COPY relocation for a given symbol.
+ // A target needs to implement this to support incremental linking.
+
+ virtual void
+ emit_copy_reloc(Symbol_table*, Symbol*, Output_section*, off_t)
+ { gold_unreachable(); }
+
+ // Apply an incremental relocation.
+
+ virtual void
+ apply_relocation(const Relocate_info<size, big_endian>* /* relinfo */,
+ typename elfcpp::Elf_types<size>::Elf_Addr /* r_offset */,
+ unsigned int /* r_type */,
+ typename elfcpp::Elf_types<size>::Elf_Swxword /* r_addend */,
+ const Symbol* /* gsym */,
+ unsigned char* /* view */,
+ typename elfcpp::Elf_types<size>::Elf_Addr /* address */,
+ section_size_type /* view_size */)
+ { gold_unreachable(); }
+
+ // Handle target specific gc actions when adding a gc reference from
+ // SRC_OBJ, SRC_SHNDX to a location specified by DST_OBJ, DST_SHNDX
+ // and DST_OFF.
+ void
+ gc_add_reference(Symbol_table* symtab,
+ Object* src_obj,
+ unsigned int src_shndx,
+ Object* dst_obj,
+ unsigned int dst_shndx,
+ typename elfcpp::Elf_types<size>::Elf_Addr dst_off) const
+ {
+ this->do_gc_add_reference(symtab, src_obj, src_shndx,
+ dst_obj, dst_shndx, dst_off);
+ }
+
+ protected:
+ Sized_target(const Target::Target_info* pti)
+ : Target(pti)
+ {
+ gold_assert(pti->size == size);
+ gold_assert(pti->is_big_endian ? big_endian : !big_endian);
+ }
+
+ // Set the EI_OSABI field if requested.
+ virtual void
+ do_adjust_elf_header(unsigned char*, int);
+
+ // Handle target specific gc actions when adding a gc reference.
+ virtual void
+ do_gc_add_reference(Symbol_table*, Object*, unsigned int,
+ Object*, unsigned int,
+ typename elfcpp::Elf_types<size>::Elf_Addr) const
+ { }
+
+ virtual void
+ do_function_location(Symbol_location*) const
+ { }
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_TARGET_H)
diff --git a/binutils-2.25/gold/testsuite/Makefile.am b/binutils-2.25/gold/testsuite/Makefile.am
new file mode 100644
index 00000000..0d40e3ff
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/Makefile.am
@@ -0,0 +1,2901 @@
+# Process this file with automake to generate Makefile.in
+
+# As far as I can tell automake testing support assumes that the build
+# system and the host system are the same. So these tests will not
+# work when building with a cross-compiler.
+
+# Ignore warning about AM_PROG_CC_C_O due to large_CFLAGS
+AUTOMAKE_OPTIONS = foreign -Wno-portability
+
+# The two_file_test tests -fmerge-constants, so we simply always turn
+# it on. For compilers that do not support the command-line option,
+# we assume they just always emit SHF_MERGE sections unconditionally.
+AM_CFLAGS = $(WARN_CFLAGS) $(LFS_CFLAGS) $(MERGE_CONSTANTS_FLAG)
+AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CFLAGS) $(MERGE_CONSTANTS_FLAG)
+
+AM_CPPFLAGS = \
+ -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../include \
+ -I$(srcdir)/../../elfcpp -I.. \
+ -DLOCALEDIR="\"$(datadir)/locale\"" \
+ @INCINTL@
+
+# COMPILE1, LINK1, CXXCOMPILE1, CXXLINK1 are renamed from COMPILE, LINK,
+# CXXCOMPILE and CXXLINK generated by automake 1.11.1. FIXME: they should
+# be updated if they are different from automake used by gold.
+COMPILE1 = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LINK1 = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CXXCOMPILE1 = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLINK1 = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+
+# Strip out -Wp,-D_FORTIFY_SOURCE=, which is rrelevant for the gold
+# testsuite and incompatible with -O0 used in gold tests, from
+# COMPILE, LINK, CXXCOMPILE and CXXLINK.
+COMPILE = `echo $(COMPILE1) | sed -e 's/-Wp,-D_FORTIFY_SOURCE=[0-9[0-9]]*//'`
+LINK = `echo $(LINK1) | sed -e 's/-Wp,-D_FORTIFY_SOURCE=[0-9][0-9]*//'`
+CXXCOMPILE = `echo $(CXXCOMPILE1) | sed -e 's/-Wp,-D_FORTIFY_SOURCE=[0-9][0-9]*//'`
+CXXLINK = `echo $(CXXLINK1) | sed -e 's/-Wp,-D_FORTIFY_SOURCE=[0-9][0-9]*//'`
+
+# Strip out -static-libgcc and -static-libstdc++ options, for tests
+# that must have these libraries linked dynamically. The -shared-libgcc
+# option does not work correctly, and there is no -shared-libstdc++ option.
+# (See GCC PR 55781 and PR 55782.)
+CXXLINK_S = `echo $(CXXLINK1) | sed -e 's/-static-lib\\(gcc\\|stdc++\\)//g'`
+
+TEST_READELF = $(top_builddir)/../binutils/readelf
+TEST_OBJDUMP = $(top_builddir)/../binutils/objdump
+TEST_OBJCOPY = $(top_builddir)/../binutils/objcopy
+TEST_CXXFILT = $(top_builddir)/../binutils/cxxfilt
+TEST_STRIP = $(top_builddir)/../binutils/strip-new
+TEST_AR = $(top_builddir)/../binutils/ar
+TEST_NM = $(top_builddir)/../binutils/nm-new
+TEST_AS = $(top_builddir)/../gas/as-new
+
+if PLUGINS
+LIBDL = -ldl
+endif
+
+if THREADS
+THREADSLIB = -lpthread
+endif
+
+if OMP_SUPPORT
+TLS_TEST_C_CFLAGS = -fopenmp
+endif
+
+# 'make clean' is good about deleting some intermediate files (such as
+# .o's), but not all of them (such as .so's and .err files). We
+# improve on that here. automake-1.9 info docs say "mostlyclean" is
+# the right choice for files 'make' builds that people rebuild.
+MOSTLYCLEANFILES = *.so *.syms *.stdout
+
+# Export make variables to the shell scripts so that they can see
+# (for example) DEFAULT_TARGET.
+.EXPORT_ALL_VARIABLES:
+
+# We will add to these later, for each individual test. Note
+# that we add each test under check_SCRIPTS or check_PROGRAMS;
+# the TESTS variable is automatically populated from these.
+check_SCRIPTS =
+check_DATA =
+check_PROGRAMS =
+BUILT_SOURCES =
+
+TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
+
+# ---------------------------------------------------------------------
+# These tests test the internals of gold (unittests).
+
+# Infrastucture needed for the unittests
+check_LIBRARIES = libgoldtest.a
+libgoldtest_a_SOURCES = test.cc testmain.cc testfile.cc
+
+DEPENDENCIES = \
+ libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL_DEP)
+LDADD = libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL) \
+ $(THREADSLIB) $(LIBDL)
+
+
+# The unittests themselves
+if NATIVE_OR_CROSS_LINKER
+if GCC
+
+# Infrastucture needed for the unittests: a directory where the linker
+# is named 'ld'. This is because the -B flag appends 'ld' to its arg.
+gcctestdir/ld: ../ld-new
+ test -d gcctestdir || mkdir -p gcctestdir
+ rm -f gcctestdir/ld
+ (cd gcctestdir && $(LN_S) ../../ld-new ld)
+
+# Some tests require the latest features of an in-tree assembler.
+gcctestdir/as: $(TEST_AS)
+ test -d gcctestdir || mkdir -p gcctestdir
+ rm -f gcctestdir/as
+ (cd gcctestdir && $(LN_S) $(abs_top_builddir)/../gas/as-new as)
+
+endif GCC
+
+check_PROGRAMS += object_unittest
+object_unittest_SOURCES = object_unittest.cc
+
+check_PROGRAMS += binary_unittest
+binary_unittest_SOURCES = binary_unittest.cc
+
+check_PROGRAMS += leb128_unittest
+leb128_unittest_SOURCES = leb128_unittest.cc
+
+endif NATIVE_OR_CROSS_LINKER
+
+# ---------------------------------------------------------------------
+# These tests test the output of gold (end-to-end tests). In
+# particular, they make sure that gold can link "difficult" object
+# files, and the resulting object files run correctly. These can only
+# run if we've built ld-new for the native architecture (that is,
+# we're not cross-compiling it), since we run ld-new as part of these
+# tests. We use the gcc-specific flag '-B' to use our linker instead
+# of the default linker, which is why we only run our tests under gcc.
+
+if NATIVE_LINKER
+if GCC
+
+# Each of these .o's is a useful, small complete program. They're
+# particularly useful for making sure ld-new's flags do what they're
+# supposed to (hence their names), but are used for many tests that
+# don't actually involve analyzing input data.
+flagstest_debug.o: constructor_test.cc
+ $(CXXCOMPILE) -O0 -g -c -o $@ $<
+flagstest_ndebug.o: constructor_test.cc
+ $(CXXCOMPILE) -O0 -c -o $@ $<
+
+check_SCRIPTS += incremental_test.sh
+check_DATA += incremental_test.stdout
+MOSTLYCLEANFILES += incremental_test incremental_test.cmdline
+incremental_test_1.o: incremental_test_1.c
+ $(COMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+incremental_test_2.o: incremental_test_2.c
+ $(COMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+incremental_test: incremental_test_1.o incremental_test_2.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -Wl,--incremental-full incremental_test_1.o incremental_test_2.o -Wl,-debug 2> incremental_test.cmdline
+incremental_test.stdout: incremental_test ../incremental-dump
+ ../incremental-dump incremental_test > $@
+
+check_SCRIPTS += gc_comdat_test.sh
+check_DATA += gc_comdat_test.stdout
+MOSTLYCLEANFILES += gc_comdat_test
+gc_comdat_test_1.o: gc_comdat_test_1.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+gc_comdat_test_2.o: gc_comdat_test_2.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+gc_comdat_test: gc_comdat_test_1.o gc_comdat_test_2.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--gc-sections gc_comdat_test_1.o gc_comdat_test_2.o
+gc_comdat_test.stdout: gc_comdat_test
+ $(TEST_NM) -C gc_comdat_test > gc_comdat_test.stdout
+
+check_SCRIPTS += gc_tls_test.sh
+check_DATA += gc_tls_test.stdout
+MOSTLYCLEANFILES += gc_tls_test
+gc_tls_test.o: gc_tls_test.cc
+ $(CXXCOMPILE) -O0 -c -g -o $@ $<
+gc_tls_test:gc_tls_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--gc-sections gc_tls_test.o
+gc_tls_test.stdout: gc_tls_test
+ $(TEST_NM) -C gc_tls_test > gc_tls_test.stdout
+
+check_SCRIPTS += gc_orphan_section_test.sh
+check_DATA += gc_orphan_section_test.stdout
+MOSTLYCLEANFILES += gc_orphan_section_test
+gc_orphan_section_test.o: gc_orphan_section_test.cc
+ $(CXXCOMPILE) -O0 -c -g -o $@ $<
+gc_orphan_section_test:gc_orphan_section_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--gc-sections gc_orphan_section_test.o
+gc_orphan_section_test.stdout: gc_orphan_section_test
+ $(TEST_NM) gc_orphan_section_test > gc_orphan_section_test.stdout
+
+check_SCRIPTS += pr14265.sh
+check_DATA += pr14265.stdout
+MOSTLYCLEANFILES += pr14265
+pr14265.o: pr14265.c
+ $(COMPILE) -O0 -c -o $@ $<
+pr14265: pr14265.o
+ $(LINK) -Bgcctestdir/ -Wl,--gc-sections -Wl,-T,$(srcdir)/pr14265.t -o $@ $<
+pr14265.stdout: pr14265
+ $(TEST_NM) --format=bsd --numeric-sort $< > $@
+
+check_SCRIPTS += icf_test.sh
+check_DATA += icf_test.map
+MOSTLYCLEANFILES += icf_test icf_test.map
+icf_test.o: icf_test.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+icf_test: icf_test.o gcctestdir/ld
+ $(CXXLINK) -o icf_test -Bgcctestdir/ -Wl,--icf=all,-Map,icf_test.map icf_test.o
+icf_test.map: icf_test
+ @touch icf_test.map
+
+check_SCRIPTS += icf_keep_unique_test.sh
+check_DATA += icf_keep_unique_test.stdout
+MOSTLYCLEANFILES += icf_keep_unique_test
+icf_keep_unique_test.o: icf_keep_unique_test.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+icf_keep_unique_test: icf_keep_unique_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all -Wl,--keep-unique,_Z11unique_funcv icf_keep_unique_test.o
+icf_keep_unique_test.stdout: icf_keep_unique_test
+ $(TEST_NM) -C $< > $@
+
+check_SCRIPTS += icf_safe_test.sh
+check_DATA += icf_safe_test_1.stdout icf_safe_test_2.stdout icf_safe_test.map
+MOSTLYCLEANFILES += icf_safe_test icf_safe_test.map
+icf_safe_test.o: icf_safe_test.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+icf_safe_test: icf_safe_test.o gcctestdir/ld
+ $(CXXLINK) -o icf_safe_test -Bgcctestdir/ -Wl,--icf=safe,-Map,icf_safe_test.map icf_safe_test.o
+icf_safe_test.map: icf_safe_test
+ @touch icf_safe_test.map
+icf_safe_test_1.stdout: icf_safe_test
+ $(TEST_NM) $< > $@
+icf_safe_test_2.stdout: icf_safe_test
+ $(TEST_READELF) -h $< > $@
+
+check_SCRIPTS += icf_safe_so_test.sh
+check_DATA += icf_safe_so_test_1.stdout icf_safe_so_test_2.stdout icf_safe_so_test.map
+MOSTLYCLEANFILES += icf_safe_so_test icf_safe_so_test.map
+icf_safe_so_test.o: icf_safe_so_test.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $<
+icf_safe_so_test: icf_safe_so_test.o gcctestdir/ld
+ $(CXXLINK) -o icf_safe_so_test -Bgcctestdir/ -Wl,--icf=safe,-Map,icf_safe_so_test.map icf_safe_so_test.o -fPIC -shared
+icf_safe_so_test.map:
+ @touch icf_safe_so_test.map
+icf_safe_so_test_1.stdout: icf_safe_so_test
+ $(TEST_NM) $< > $@
+icf_safe_so_test_2.stdout: icf_safe_so_test
+ $(TEST_READELF) -h $< > $@
+
+check_SCRIPTS += final_layout.sh
+check_DATA += final_layout.stdout
+MOSTLYCLEANFILES += final_layout final_layout_sequence.txt final_layout_script.lds
+final_layout.o: final_layout.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -fdata-sections -g -o $@ $<
+final_layout_sequence.txt:
+ (echo "*_Z3barv*" && echo ".text._Z3bazv" && echo "*_Z3foov*" && echo "*global_varb*" && echo "*global_vara*" && echo "*global_varc*") > final_layout_sequence.txt
+final_layout_script.lds:
+ (echo "SECTIONS { .text : { *(.text*) } .got : { *(.got .toc) } .sbss : { *(.sbss*) } .bss : { *(.bss*) } }") > final_layout_script.lds
+final_layout: final_layout.o final_layout_sequence.txt final_layout_script.lds gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--section-ordering-file,final_layout_sequence.txt -Wl,-T,final_layout_script.lds final_layout.o
+final_layout.stdout: final_layout
+ $(TEST_NM) -n --synthetic final_layout > final_layout.stdout
+
+check_SCRIPTS += text_section_grouping.sh
+check_DATA += text_section_grouping.stdout text_section_no_grouping.stdout
+MOSTLYCLEANFILES += text_section_grouping text_section_no_grouping
+text_section_grouping.o: text_section_grouping.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+text_section_grouping: text_section_grouping.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ text_section_grouping.o
+text_section_no_grouping: text_section_grouping.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--no-text-reorder text_section_grouping.o
+text_section_grouping.stdout: text_section_grouping
+ $(TEST_NM) -n --synthetic text_section_grouping > text_section_grouping.stdout
+text_section_no_grouping.stdout: text_section_no_grouping
+ $(TEST_NM) -n --synthetic text_section_no_grouping > text_section_no_grouping.stdout
+
+check_SCRIPTS += section_sorting_name.sh
+check_DATA += section_sorting_name.stdout
+MOSTLYCLEANFILES += section_sorting_name
+section_sorting_name.o: section_sorting_name.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+section_sorting_name: section_sorting_name.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--sort-section=name section_sorting_name.o
+section_sorting_name.stdout: section_sorting_name
+ $(TEST_NM) -n --synthetic section_sorting_name > section_sorting_name.stdout
+
+check_PROGRAMS += icf_virtual_function_folding_test
+MOSTLYCLEANFILES += icf_virtual_function_folding_test icf_virtual_function_folding_test.map
+icf_virtual_function_folding_test.o: icf_virtual_function_folding_test.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIE -g -o $@ $<
+icf_virtual_function_folding_test: icf_virtual_function_folding_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_virtual_function_folding_test.o -pie
+
+check_SCRIPTS += icf_preemptible_functions_test.sh
+check_DATA += icf_preemptible_functions_test.stdout
+MOSTLYCLEANFILES += icf_preemptible_functions_test
+icf_preemptible_functions_test.o: icf_preemptible_functions_test.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $<
+icf_preemptible_functions_test: icf_preemptible_functions_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_preemptible_functions_test.o -fPIC -shared
+icf_preemptible_functions_test.stdout: icf_preemptible_functions_test
+ $(TEST_NM) icf_preemptible_functions_test > icf_preemptible_functions_test.stdout
+
+check_SCRIPTS += icf_string_merge_test.sh
+check_DATA += icf_string_merge_test.stdout
+MOSTLYCLEANFILES += icf_string_merge_test
+icf_string_merge_test.o: icf_string_merge_test.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $<
+icf_string_merge_test: icf_string_merge_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_string_merge_test.o
+icf_string_merge_test.stdout: icf_string_merge_test
+ $(TEST_NM) icf_string_merge_test > icf_string_merge_test.stdout
+
+check_SCRIPTS += icf_sht_rel_addend_test.sh
+check_DATA += icf_sht_rel_addend_test.stdout
+MOSTLYCLEANFILES += icf_sht_rel_addend_test
+icf_sht_rel_addend_test_1.o: icf_sht_rel_addend_test_1.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $<
+icf_sht_rel_addend_test_2.o: icf_sht_rel_addend_test_2.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $<
+icf_sht_rel_addend_test: icf_sht_rel_addend_test_1.o icf_sht_rel_addend_test_2.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_sht_rel_addend_test_1.o icf_sht_rel_addend_test_2.o
+icf_sht_rel_addend_test.stdout: icf_sht_rel_addend_test
+ $(TEST_NM) icf_sht_rel_addend_test > icf_sht_rel_addend_test.stdout
+
+check_PROGRAMS += large_symbol_alignment
+large_symbol_alignment_SOURCES = large_symbol_alignment.cc
+large_symbol_alignment_DEPENDENCIES = gcctestdir/ld
+large_symbol_alignment_LDFLAGS = -Bgcctestdir/
+large_symbol_alignment_LDADD =
+
+check_SCRIPTS += merge_string_literals.sh
+check_DATA += merge_string_literals.stdout
+MOSTLYCLEANFILES += merge_string_literals
+merge_string_literals_1.o: merge_string_literals_1.cc
+ $(CXXCOMPILE) -O2 -c -fPIC -g -o $@ $<
+merge_string_literals_2.o: merge_string_literals_2.cc
+ $(CXXCOMPILE) -O2 -c -fPIC -g -o $@ $<
+merge_string_literals: merge_string_literals_1.o merge_string_literals_2.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ merge_string_literals_1.o merge_string_literals_2.o -O2 -shared -nostdlib
+merge_string_literals.stdout: merge_string_literals
+ $(TEST_OBJDUMP) -s -j.rodata merge_string_literals > merge_string_literals.stdout
+
+check_PROGRAMS += basic_test
+check_PROGRAMS += basic_pic_test
+basic_test.o: basic_test.cc
+ $(CXXCOMPILE) -O0 -c -o $@ $<
+basic_test: basic_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ basic_test.o
+
+if HAVE_STATIC
+check_PROGRAMS += basic_static_test
+basic_static_test: basic_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -static basic_test.o
+endif
+
+basic_pic_test.o: basic_test.cc
+ $(CXXCOMPILE) -O0 -c -fpic -o $@ $<
+basic_pic_test: basic_pic_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ basic_pic_test.o
+
+if HAVE_STATIC
+check_PROGRAMS += basic_static_pic_test
+basic_static_pic_test: basic_pic_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -static basic_pic_test.o
+endif
+
+check_PROGRAMS += basic_pie_test
+basic_pie_test.o: basic_test.cc
+ $(CXXCOMPILE) -O0 -c -fpie -o $@ $<
+basic_pie_test: basic_pie_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -pie basic_pie_test.o
+
+check_PROGRAMS += constructor_test
+constructor_test_SOURCES = constructor_test.cc
+constructor_test_DEPENDENCIES = gcctestdir/ld
+constructor_test_LDFLAGS = -Bgcctestdir/
+constructor_test_LDADD =
+
+if HAVE_STATIC
+check_PROGRAMS += constructor_static_test
+constructor_static_test_SOURCES = $(constructor_test_SOURCES)
+constructor_static_test_DEPENDENCIES = $(constructor_test_DEPENDENCIES)
+constructor_static_test_LDFLAGS = $(constructor_test_LDFLAGS) -static
+constructor_static_test_LDADD = $(constructor_test_LDADD)
+endif
+
+check_PROGRAMS += two_file_test
+check_PROGRAMS += two_file_pic_test
+two_file_test_SOURCES = \
+ two_file_test_1.cc \
+ two_file_test_1b.cc \
+ two_file_test_2.cc \
+ two_file_test_main.cc \
+ two_file_test.h
+two_file_test_DEPENDENCIES = gcctestdir/ld
+two_file_test_LDFLAGS = -Bgcctestdir/
+two_file_test_LDADD =
+
+if HAVE_STATIC
+check_PROGRAMS += two_file_static_test
+two_file_static_test_SOURCES = $(two_file_test_SOURCES)
+two_file_static_test_DEPENDENCIES = $(two_file_test_DEPENDENCIES)
+two_file_static_test_LDFLAGS = $(two_file_test_LDFLAGS) -static
+two_file_static_test_LDADD = $(two_file_test_LDADD)
+endif
+
+two_file_pic_test_SOURCES = two_file_test_main.cc
+two_file_pic_test_DEPENDENCIES = \
+ gcctestdir/ld two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2_pic.o
+two_file_pic_test_LDFLAGS = -Bgcctestdir/
+two_file_pic_test_LDADD = two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2_pic.o
+
+
+check_PROGRAMS += two_file_shared_1_test
+check_PROGRAMS += two_file_shared_2_test
+check_PROGRAMS += two_file_shared_1_pic_2_test
+check_PROGRAMS += two_file_shared_2_pic_1_test
+check_PROGRAMS += two_file_same_shared_test
+check_PROGRAMS += two_file_separate_shared_12_test
+check_PROGRAMS += two_file_separate_shared_21_test
+two_file_test_1_pic.o: two_file_test_1.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+two_file_test_1b_pic.o: two_file_test_1b.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+two_file_test_2_pic.o: two_file_test_2.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+two_file_shared_1.so: two_file_test_1_pic.o two_file_test_1b_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_1b_pic.o
+two_file_shared_2.so: two_file_test_2_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2_pic.o
+two_file_shared.so: two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2_pic.o
+
+two_file_shared_1_test_SOURCES = two_file_test_2.cc two_file_test_main.cc
+two_file_shared_1_test_DEPENDENCIES = gcctestdir/ld two_file_shared_1.so
+two_file_shared_1_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_shared_1_test_LDADD = two_file_shared_1.so
+
+two_file_shared_2_test_SOURCES = two_file_test_1.cc two_file_test_1b.cc two_file_test_main.cc
+two_file_shared_2_test_DEPENDENCIES = gcctestdir/ld two_file_shared_2.so
+two_file_shared_2_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_shared_2_test_LDADD = two_file_shared_2.so
+
+two_file_shared_1_pic_2_test_SOURCES = two_file_test_main.cc
+two_file_shared_1_pic_2_test_DEPENDENCIES = \
+ gcctestdir/ld two_file_shared_2.so two_file_test_1_pic.o two_file_test_1b_pic.o
+two_file_shared_1_pic_2_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_shared_1_pic_2_test_LDADD = two_file_test_1_pic.o two_file_test_1b_pic.o two_file_shared_2.so
+
+two_file_shared_2_pic_1_test_SOURCES = two_file_test_main.cc
+two_file_shared_2_pic_1_test_DEPENDENCIES = \
+ gcctestdir/ld two_file_shared_2.so two_file_test_2_pic.o
+two_file_shared_2_pic_1_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_shared_2_pic_1_test_LDADD = two_file_test_2_pic.o two_file_shared_1.so
+
+two_file_same_shared_test_SOURCES = two_file_test_main.cc
+two_file_same_shared_test_DEPENDENCIES = gcctestdir/ld two_file_shared.so
+two_file_same_shared_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_same_shared_test_LDADD = two_file_shared.so
+
+two_file_separate_shared_12_test_SOURCES = two_file_test_main.cc
+two_file_separate_shared_12_test_DEPENDENCIES = \
+ gcctestdir/ld two_file_shared_1.so two_file_shared_2.so
+two_file_separate_shared_12_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_separate_shared_12_test_LDADD = \
+ two_file_shared_1.so two_file_shared_2.so
+
+two_file_separate_shared_21_test_SOURCES = two_file_test_main.cc
+two_file_separate_shared_21_test_DEPENDENCIES = \
+ gcctestdir/ld two_file_shared_1.so two_file_shared_2.so
+two_file_separate_shared_21_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_separate_shared_21_test_LDADD = \
+ two_file_shared_2.so two_file_shared_1.so
+
+check_PROGRAMS += two_file_relocatable_test
+two_file_relocatable_test_SOURCES = two_file_test_main.cc
+two_file_relocatable_test_DEPENDENCIES = \
+ gcctestdir/ld two_file_relocatable.o
+two_file_relocatable_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_relocatable_test_LDADD = two_file_relocatable.o
+two_file_relocatable.o: gcctestdir/ld two_file_test_1.o two_file_test_1b.o two_file_test_2.o
+ gcctestdir/ld -r -o $@ two_file_test_1.o two_file_test_1b.o two_file_test_2.o
+
+check_PROGRAMS += two_file_pie_test
+two_file_test_1_pie.o: two_file_test_1.cc
+ $(CXXCOMPILE) -c -fpie -o $@ $<
+two_file_test_1b_pie.o: two_file_test_1b.cc
+ $(CXXCOMPILE) -c -fpie -o $@ $<
+two_file_test_2_pie.o: two_file_test_2.cc
+ $(CXXCOMPILE) -c -fpie -o $@ $<
+two_file_test_main_pie.o: two_file_test_main.cc
+ $(CXXCOMPILE) -c -fpie -o $@ $<
+two_file_pie_test: two_file_test_1_pie.o two_file_test_1b_pie.o \
+ two_file_test_2_pie.o two_file_test_main_pie.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -pie two_file_test_1_pie.o two_file_test_1b_pie.o two_file_test_2_pie.o two_file_test_main_pie.o
+
+check_SCRIPTS += two_file_shared.sh
+check_DATA += two_file_shared.dbg
+MOSTLYCLEANFILES += two_file_shared.dbg
+two_file_shared.dbg: two_file_shared.so
+ $(TEST_READELF) -w $< >$@ 2>/dev/null
+
+# The nonpic tests will fail on platforms which can not put non-PIC
+# code into shared libraries, so we just don't run them in that case.
+if FN_PTRS_IN_SO_WITHOUT_PIC
+
+check_PROGRAMS += two_file_shared_1_nonpic_test
+check_PROGRAMS += two_file_shared_2_nonpic_test
+check_PROGRAMS += two_file_same_shared_nonpic_test
+check_PROGRAMS += two_file_separate_shared_12_nonpic_test
+check_PROGRAMS += two_file_separate_shared_21_nonpic_test
+check_PROGRAMS += two_file_mixed_shared_test
+check_PROGRAMS += two_file_mixed_2_shared_test
+two_file_shared_1_nonpic.so: two_file_test_1.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o two_file_test_1b.o -Wl,-z,notext
+two_file_shared_2_nonpic.so: two_file_test_2.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2.o
+two_file_shared_nonpic.so: two_file_test_1.o two_file_test_1b.o two_file_test_2.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o two_file_test_1b.o two_file_test_2.o -Wl,-z,notext
+two_file_shared_mixed.so: two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2.o -Wl,-z,notext
+two_file_shared_mixed_1.so: two_file_test_1.o two_file_test_1b_pic.o two_file_shared_2.so gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o two_file_test_1b_pic.o two_file_shared_2.so -Wl,-z,notext
+
+two_file_shared_1_nonpic_test_SOURCES = \
+ two_file_test_2.cc two_file_test_main.cc
+two_file_shared_1_nonpic_test_DEPENDENCIES = \
+ gcctestdir/ld two_file_shared_1_nonpic.so
+two_file_shared_1_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_shared_1_nonpic_test_LDADD = two_file_shared_1_nonpic.so
+
+two_file_shared_2_nonpic_test_SOURCES = \
+ two_file_test_1.cc two_file_test_1b.cc two_file_test_main.cc
+two_file_shared_2_nonpic_test_DEPENDENCIES = \
+ gcctestdir/ld two_file_shared_2_nonpic.so
+two_file_shared_2_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_shared_2_nonpic_test_LDADD = two_file_shared_2_nonpic.so
+
+two_file_same_shared_nonpic_test_SOURCES = two_file_test_main.cc
+two_file_same_shared_nonpic_test_DEPENDENCIES = \
+ gcctestdir/ld two_file_shared_nonpic.so
+two_file_same_shared_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_same_shared_nonpic_test_LDADD = two_file_shared_nonpic.so
+
+two_file_separate_shared_12_nonpic_test_SOURCES = two_file_test_main.cc
+two_file_separate_shared_12_nonpic_test_DEPENDENCIES = \
+ gcctestdir/ld two_file_shared_1_nonpic.so two_file_shared_2_nonpic.so
+two_file_separate_shared_12_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_separate_shared_12_nonpic_test_LDADD = \
+ two_file_shared_1_nonpic.so two_file_shared_2_nonpic.so
+
+two_file_separate_shared_21_nonpic_test_SOURCES = two_file_test_main.cc
+two_file_separate_shared_21_nonpic_test_DEPENDENCIES = \
+ gcctestdir/ld two_file_shared_1_nonpic.so two_file_shared_2_nonpic.so
+two_file_separate_shared_21_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_separate_shared_21_nonpic_test_LDADD = \
+ two_file_shared_2_nonpic.so two_file_shared_1_nonpic.so
+
+two_file_mixed_shared_test_SOURCES = two_file_test_main.cc
+two_file_mixed_shared_test_DEPENDENCIES = gcctestdir/ld two_file_shared_mixed.so
+two_file_mixed_shared_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_mixed_shared_test_LDADD = two_file_shared_mixed.so
+
+two_file_mixed_2_shared_test_SOURCES = two_file_test_main.cc
+two_file_mixed_2_shared_test_DEPENDENCIES = gcctestdir/ld two_file_shared_mixed_1.so two_file_shared_2.so
+two_file_mixed_2_shared_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+two_file_mixed_2_shared_test_LDADD = two_file_shared_mixed_1.so two_file_shared_2.so
+
+check_PROGRAMS += two_file_mixed_pie_test
+two_file_mixed_pie_test: two_file_test_1.o two_file_test_1b_pie.o \
+ two_file_test_main_pie.o two_file_shared_2.so gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,-R,. -pie two_file_test_1.o two_file_test_1b_pie.o two_file_test_main_pie.o two_file_shared_2.so
+
+endif FN_PTRS_IN_SO_WITHOUT_PIC
+
+check_PROGRAMS += two_file_strip_test
+two_file_strip_test: two_file_test
+ $(TEST_STRIP) -o two_file_strip_test two_file_test
+
+check_PROGRAMS += two_file_same_shared_strip_test
+two_file_same_shared_strip_test_SOURCES = two_file_test_main.cc
+two_file_same_shared_strip_test_DEPENDENCIES = \
+ gcctestdir/ld two_file_shared_strip.so
+two_file_same_shared_strip_test_LDFLAGS = -Bgcctestdir/ -Wl,-R.
+two_file_same_shared_strip_test_LDADD = two_file_shared_strip.so
+two_file_shared_strip.so: two_file_shared.so
+ $(TEST_STRIP) -S -o two_file_shared_strip.so two_file_shared.so
+
+check_PROGRAMS += common_test_1
+common_test_1_SOURCES = common_test_1.c
+common_test_1_DEPENDENCIES = gcctestdir/ld
+common_test_1_LDFLAGS = -Bgcctestdir/
+common_test_1_LDADD =
+
+check_PROGRAMS += common_test_2
+common_test_2_SOURCES = common_test_1.c
+common_test_2_DEPENDENCIES = common_test_2.so common_test_3.so gcctestdir/ld
+common_test_2_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+common_test_2_LDADD = common_test_2.so common_test_3.so
+common_test_2_pic.o: common_test_2.c
+ $(COMPILE) -c -fpic -o $@ $<
+common_test_2.so: common_test_2_pic.o common_test_3.so gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -shared common_test_2_pic.o common_test_3.so
+common_test_3_pic.o: common_test_3.c
+ $(COMPILE) -c -fpic -o $@ $<
+common_test_3.so: common_test_3_pic.o ver_test_2.script gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -shared common_test_3_pic.o -Wl,--version-script,$(srcdir)/ver_test_2.script
+
+check_PROGRAMS += exception_test
+check_PROGRAMS += exception_shared_1_test
+check_PROGRAMS += exception_shared_2_test
+check_PROGRAMS += exception_same_shared_test
+check_PROGRAMS += exception_separate_shared_12_test
+check_PROGRAMS += exception_separate_shared_21_test
+exception_test_1_pic.o: exception_test_1.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+exception_test_2_pic.o: exception_test_2.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+exception_shared_1.so: exception_test_1_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared exception_test_1_pic.o
+exception_shared_2.so: exception_test_2_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared exception_test_2_pic.o
+exception_shared.so: exception_test_1_pic.o exception_test_2_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared exception_test_1_pic.o exception_test_2_pic.o
+
+exception_test_SOURCES = \
+ exception_test_main.cc \
+ exception_test_1.cc \
+ exception_test_2.cc \
+ exception_test.h
+exception_test_DEPENDENCIES = gcctestdir/ld
+exception_test_LDFLAGS = -Bgcctestdir/
+exception_test_LDADD =
+
+if HAVE_STATIC
+check_PROGRAMS += exception_static_test
+exception_static_test_SOURCES = $(exception_test_SOURCES)
+exception_static_test_DEPENDENCIES = $(exception_test_DEPENDENCIES)
+exception_static_test_LDFLAGS = $(exception_test_LDFLAGS) -static
+exception_static_test_LDADD = $(exception_test_LDADD)
+endif
+
+exception_shared_1_test_SOURCES = exception_test_2.cc exception_test_main.cc
+exception_shared_1_test_DEPENDENCIES = gcctestdir/ld exception_shared_1.so
+exception_shared_1_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+exception_shared_1_test_LDADD = exception_shared_1.so
+
+exception_shared_2_test_SOURCES = exception_test_1.cc exception_test_main.cc
+exception_shared_2_test_DEPENDENCIES = gcctestdir/ld exception_shared_2.so
+exception_shared_2_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+exception_shared_2_test_LDADD = exception_shared_2.so
+
+exception_same_shared_test_SOURCES = exception_test_main.cc
+exception_same_shared_test_DEPENDENCIES = gcctestdir/ld exception_shared.so
+exception_same_shared_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+exception_same_shared_test_LDADD = exception_shared.so
+
+exception_separate_shared_12_test_SOURCES = exception_test_main.cc
+exception_separate_shared_12_test_DEPENDENCIES = \
+ gcctestdir/ld exception_shared_1.so exception_shared_2.so
+exception_separate_shared_12_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,. \
+ -Wl,--no-as-needed
+exception_separate_shared_12_test_LDADD = \
+ exception_shared_1.so exception_shared_2.so
+
+exception_separate_shared_21_test_SOURCES = exception_test_main.cc
+exception_separate_shared_21_test_DEPENDENCIES = \
+ gcctestdir/ld exception_shared_1.so exception_shared_2.so
+exception_separate_shared_21_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,. \
+ -Wl,--no-as-needed
+exception_separate_shared_21_test_LDADD = \
+ exception_shared_2.so exception_shared_1.so
+
+
+check_PROGRAMS += weak_test
+weak_test_SOURCES = weak_test.cc
+weak_test_DEPENDENCIES = gcctestdir/ld
+weak_test_LDFLAGS = -Bgcctestdir/
+weak_test_LDADD =
+
+check_PROGRAMS += weak_undef_test
+MOSTLYCLEANFILES += alt/weak_undef_lib.so
+weak_undef_test_SOURCES = weak_undef_test.cc
+weak_undef_test_DEPENDENCIES = gcctestdir/ld weak_undef_lib.so alt/weak_undef_lib.so
+weak_undef_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,alt
+weak_undef_test_LDADD = -L . weak_undef_lib.so
+weak_undef_file1.o: weak_undef_file1.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+weak_undef_file2.o: weak_undef_file2.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+weak_undef_lib.so: weak_undef_file1.o
+ $(CXXLINK) -Bgcctestdir/ -shared weak_undef_file1.o
+alt/weak_undef_lib.so: weak_undef_file2.o
+ test -d alt || mkdir -p alt
+ $(CXXLINK) -Bgcctestdir/ -shared weak_undef_file2.o
+
+if FN_PTRS_IN_SO_WITHOUT_PIC
+check_PROGRAMS += weak_undef_nonpic_test
+MOSTLYCLEANFILES += alt/weak_undef_lib_nonpic.so
+weak_undef_nonpic_test_SOURCES = weak_undef_test.cc
+weak_undef_nonpic_test_DEPENDENCIES = gcctestdir/ld weak_undef_lib_nonpic.so alt/weak_undef_lib_nonpic.so
+weak_undef_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,alt
+weak_undef_nonpic_test_LDADD = -L . weak_undef_lib_nonpic.so
+weak_undef_file1_nonpic.o: weak_undef_file1.cc
+ $(CXXCOMPILE) -c -o $@ $<
+weak_undef_file2_nonpic.o: weak_undef_file2.cc
+ $(CXXCOMPILE) -c -o $@ $<
+weak_undef_lib_nonpic.so: weak_undef_file1_nonpic.o
+ $(CXXLINK) -Bgcctestdir/ -shared weak_undef_file1_nonpic.o -Wl,-z,notext
+alt/weak_undef_lib_nonpic.so: weak_undef_file2_nonpic.o
+ test -d alt || mkdir -p alt
+ $(CXXLINK) -Bgcctestdir/ -shared weak_undef_file2_nonpic.o -Wl,-z,notext
+endif FN_PTRS_IN_SO_WITHOUT_PIC
+
+
+check_PROGRAMS += weak_alias_test
+weak_alias_test_SOURCES = weak_alias_test_main.cc
+weak_alias_test_DEPENDENCIES = \
+ gcctestdir/ld weak_alias_test_1.so weak_alias_test_2.so \
+ weak_alias_test_3.o weak_alias_test_4.so weak_alias_test_5.so
+weak_alias_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+weak_alias_test_LDADD = \
+ weak_alias_test_1.so weak_alias_test_2.so weak_alias_test_3.o \
+ weak_alias_test_4.so weak_alias_test_5.so
+weak_alias_test_1_pic.o: weak_alias_test_1.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+weak_alias_test_1.so: weak_alias_test_1_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared weak_alias_test_1_pic.o
+weak_alias_test_2_pic.o: weak_alias_test_2.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+weak_alias_test_2.so: weak_alias_test_2_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared weak_alias_test_2_pic.o
+weak_alias_test_3.o: weak_alias_test_3.cc
+ $(CXXCOMPILE) -c -o $@ $<
+weak_alias_test_4_pic.o: weak_alias_test_4.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+weak_alias_test_4.so: weak_alias_test_4_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared weak_alias_test_4_pic.o
+weak_alias_test_5_pic.o: weak_alias_test_5.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+weak_alias_test_5.so: weak_alias_test_5_pic.o $(srcdir)/weak_alias_test.script gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared weak_alias_test_5_pic.o \
+ -Wl,--version-script,$(srcdir)/weak_alias_test.script
+
+check_SCRIPTS += weak_plt.sh
+check_PROGRAMS += weak_plt
+check_DATA += weak_plt_shared.so
+weak_plt_main_pic.o: weak_plt_main.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+weak_plt: weak_plt_main_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ weak_plt_main_pic.o
+weak_plt_shared_pic.o: weak_plt_shared.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+weak_plt_shared.so: weak_plt_shared_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared weak_plt_shared_pic.o
+
+check_PROGRAMS += copy_test
+copy_test_SOURCES = copy_test.cc
+copy_test_DEPENDENCIES = gcctestdir/ld copy_test_1.so copy_test_2.so
+copy_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+copy_test_LDADD = copy_test_1.so copy_test_2.so
+copy_test_1_pic.o: copy_test_1.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+copy_test_1.so: gcctestdir/ld copy_test_1_pic.o
+ $(CXXLINK) -Bgcctestdir/ -shared copy_test_1_pic.o
+copy_test_2_pic.o: copy_test_2.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+copy_test_2.so: gcctestdir/ld copy_test_2_pic.o
+ $(CXXLINK) -Bgcctestdir/ -shared copy_test_2_pic.o
+
+if TLS
+
+check_PROGRAMS += tls_test
+check_PROGRAMS += tls_pic_test
+check_PROGRAMS += tls_pie_test
+check_PROGRAMS += tls_pie_pic_test
+check_PROGRAMS += tls_shared_test
+check_PROGRAMS += tls_shared_ie_test
+check_PROGRAMS += tls_shared_gd_to_ie_test
+tls_test_pic.o: tls_test.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+tls_test_file2_pic.o: tls_test_file2.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+tls_test_c_pic.o: tls_test_c.c
+ $(COMPILE) -c -fpic $(TLS_TEST_C_CFLAGS) -o $@ $<
+tls_test_shared.so: tls_test_pic.o tls_test_file2_pic.o tls_test_c_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared tls_test_pic.o tls_test_file2_pic.o tls_test_c_pic.o -Wl,-z,defs
+tls_test_shared2.so: tls_test_file2_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared tls_test_file2_pic.o
+
+tls_test_pic_ie.o: tls_test.cc
+ $(CXXCOMPILE) -c -fpic -ftls-model=initial-exec -o $@ $<
+tls_test_file2_pic_ie.o: tls_test_file2.cc
+ $(CXXCOMPILE) -c -fpic -ftls-model=initial-exec -o $@ $<
+tls_test_c_pic_ie.o: tls_test_c.c
+ $(COMPILE) -c -fpic -ftls-model=initial-exec $(TLS_TEST_C_CFLAGS) -o $@ $<
+tls_test_ie_shared.so: tls_test_pic_ie.o tls_test_file2_pic_ie.o tls_test_c_pic_ie.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared tls_test_pic_ie.o tls_test_file2_pic_ie.o tls_test_c_pic_ie.o
+
+tls_test_SOURCES = tls_test.cc tls_test_file2.cc tls_test_main.cc tls_test.h
+tls_test_DEPENDENCIES = gcctestdir/ld tls_test_c.o
+tls_test_LDFLAGS = -Bgcctestdir/
+tls_test_LDADD = tls_test_c.o -lpthread
+tls_test_c.o: tls_test_c.c
+ $(COMPILE) -c $(TLS_TEST_C_CFLAGS) -o $@ $<
+
+tls_pic_test_SOURCES = tls_test_main.cc
+tls_pic_test_DEPENDENCIES = gcctestdir/ld tls_test_pic.o tls_test_file2_pic.o \
+ tls_test_c_pic.o
+tls_pic_test_LDFLAGS = -Bgcctestdir/
+tls_pic_test_LDADD = tls_test_pic.o tls_test_file2_pic.o tls_test_c_pic.o \
+ -lpthread
+
+tls_test_main_pie.o: tls_test_main.cc tls_test.h
+ $(CXXCOMPILE) -c -fpie -o $@ $<
+tls_test_pie.o: tls_test.cc tls_test.h
+ $(CXXCOMPILE) -c -fpie -o $@ $<
+tls_test_file2_pie.o: tls_test_file2.cc tls_test.h
+ $(CXXCOMPILE) -c -fpie -o $@ $<
+tls_test_c_pie.o: tls_test_c.c
+ $(COMPILE) -c -fpic $(TLS_TEST_C_CFLAGS) -o $@ $<
+tls_pie_test: tls_test_main_pie.o tls_test_pie.o tls_test_file2_pie.o \
+ tls_test_c_pie.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -pie tls_test_main_pie.o tls_test_pie.o tls_test_file2_pie.o tls_test_c_pie.o -lpthread
+
+tls_pie_pic_test: tls_test_main_pie.o tls_test_pic.o tls_test_file2_pic.o \
+ tls_test_c_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -pie tls_test_main_pie.o tls_test_pic.o tls_test_file2_pic.o tls_test_c_pic.o -lpthread
+
+tls_shared_test_SOURCES = tls_test_main.cc
+tls_shared_test_DEPENDENCIES = gcctestdir/ld tls_test_shared.so
+tls_shared_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+tls_shared_test_LDADD = tls_test_shared.so -lpthread
+
+tls_shared_ie_test_SOURCES = tls_test_main.cc
+tls_shared_ie_test_DEPENDENCIES = gcctestdir/ld tls_test_ie_shared.so
+tls_shared_ie_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+tls_shared_ie_test_LDADD = tls_test_ie_shared.so -lpthread
+
+tls_shared_gd_to_ie_test_SOURCES = tls_test_main.cc
+tls_shared_gd_to_ie_test_DEPENDENCIES = gcctestdir/ld tls_test_pic.o \
+ tls_test_c_pic.o tls_test_shared2.so
+tls_shared_gd_to_ie_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+tls_shared_gd_to_ie_test_LDADD = tls_test_pic.o tls_test_c_pic.o \
+ tls_test_shared2.so -lpthread
+
+if TLS_GNU2_DIALECT
+
+check_PROGRAMS += tls_shared_gnu2_gd_to_ie_test
+
+tls_test_gnu2.o: tls_test.cc
+ $(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
+tls_test_file2_gnu2.o: tls_test_file2.cc
+ $(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
+tls_test_c_gnu2.o: tls_test_c.c
+ $(COMPILE) -c -fpic -mtls-dialect=gnu2 $(TLS_TEST_C_CFLAGS) -o $@ $<
+tls_test_gnu2_shared2.so: tls_test_file2_gnu2.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared tls_test_file2_gnu2.o
+
+tls_shared_gnu2_gd_to_ie_test_SOURCES = tls_test_main.cc
+tls_shared_gnu2_gd_to_ie_test_DEPENDENCIES = gcctestdir/ld tls_test_gnu2.o \
+ tls_test_c_gnu2.o tls_test_gnu2_shared2.so
+tls_shared_gnu2_gd_to_ie_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+tls_shared_gnu2_gd_to_ie_test_LDADD = tls_test_gnu2.o tls_test_c_gnu2.o \
+ tls_test_gnu2_shared2.so -lpthread
+
+if TLS_DESCRIPTORS
+
+check_PROGRAMS += tls_shared_gnu2_test
+
+tls_test_gnu2_shared.so: tls_test_gnu2.o tls_test_file2_gnu2.o tls_test_c_gnu2.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared tls_test_gnu2.o tls_test_file2_gnu2.o tls_test_c_gnu2.o
+
+tls_shared_gnu2_test_SOURCES = tls_test_main.cc
+tls_shared_gnu2_test_DEPENDENCIES = gcctestdir/ld tls_test_gnu2_shared.so
+tls_shared_gnu2_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+tls_shared_gnu2_test_LDADD = tls_test_gnu2_shared.so -lpthread
+
+endif TLS_DESCRIPTORS
+
+endif TLS_GNU2_DIALECT
+
+if HAVE_STATIC
+if STATIC_TLS
+check_PROGRAMS += tls_static_test
+check_PROGRAMS += tls_static_pic_test
+
+tls_static_test_SOURCES = $(tls_test_SOURCES)
+tls_static_test_DEPENDENCIES = $(tls_test_DEPENDENCIES)
+tls_static_test_LDFLAGS = $(tls_test_LDFLAGS) -static
+tls_static_test_LDADD = $(tls_test_LDADD)
+
+tls_static_pic_test_SOURCES = $(tls_pic_test_SOURCES)
+tls_static_pic_test_DEPENDENCIES = $(tls_pic_test_DEPENDENCIES)
+tls_static_pic_test_LDFLAGS = $(tls_pic_test_LDFLAGS) -static
+tls_static_pic_test_LDADD = $(tls_pic_test_LDADD)
+endif
+endif
+
+if FN_PTRS_IN_SO_WITHOUT_PIC
+check_PROGRAMS += tls_shared_nonpic_test
+tls_test_shared_nonpic.so: tls_test.o tls_test_file2.o tls_test_c.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared tls_test.o tls_test_file2.o tls_test_c.o -Wl,-z,notext
+
+tls_shared_nonpic_test_SOURCES = tls_test_main.cc
+tls_shared_nonpic_test_DEPENDENCIES = gcctestdir/ld tls_test_shared_nonpic.so
+tls_shared_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+tls_shared_nonpic_test_LDADD = tls_test_shared_nonpic.so -lpthread
+endif FN_PTRS_IN_SO_WITHOUT_PIC
+
+endif TLS
+
+check_PROGRAMS += many_sections_test
+many_sections_test_SOURCES = many_sections_test.cc
+many_sections_test_DEPENDENCIES = gcctestdir/ld
+many_sections_test_LDFLAGS = -Bgcctestdir/ -rdynamic
+many_sections_test_LDADD =
+
+BUILT_SOURCES += many_sections_define.h
+MOSTLYCLEANFILES += many_sections_define.h
+many_sections_define.h:
+ (for i in `seq 1 70000`; do \
+ echo "int var_$$i __attribute__((section(\"section_$$i\"))) = $$i;"; \
+ done) > $@.tmp
+ mv -f $@.tmp $@
+
+BUILT_SOURCES += many_sections_check.h
+MOSTLYCLEANFILES += many_sections_check.h
+many_sections_check.h:
+ (for i in `seq 1 1000 70000`; do \
+ echo "assert(var_$$i == $$i);"; \
+ done) > $@.tmp
+ mv -f $@.tmp $@
+
+check_PROGRAMS += many_sections_r_test
+many_sections_r_test.o: many_sections_test.o gcctestdir/ld
+ gcctestdir/ld -r -o $@ many_sections_test.o
+many_sections_r_test: many_sections_r_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ many_sections_r_test.o $(LIBS)
+
+check_PROGRAMS += initpri1
+initpri1_SOURCES = initpri1.c
+initpri1_DEPENDENCIES = gcctestdir/ld
+initpri1_LDFLAGS = -Bgcctestdir/
+initpri1_LDADD =
+
+check_PROGRAMS += initpri2
+initpri2_SOURCES = initpri2.c
+initpri2_DEPENDENCIES = gcctestdir/ld
+initpri2_LDFLAGS = -Bgcctestdir/ -Wl,--ctors-in-init-array
+initpri2_LDADD =
+
+check_PROGRAMS += initpri3a
+initpri3a_SOURCES = initpri3.c
+initpri3a_DEPENDENCIES = gcctestdir/ld
+initpri3a_LDFLAGS = -Bgcctestdir/
+initpri3a_LDADD =
+
+# This test fails on targets not using .ctors and .dtors sections (e.g. ARM
+# EABI). Given that gcc is moving towards using .init_array in all cases,
+# this test is commented out. A better fix would be checking whether gcc
+# uses .ctors or .init_array sections in configure.
+
+# check_PROGRAMS += initpri3b
+# initpri3b_SOURCES = initpri3.c
+# initpri3b_DEPENDENCIES = gcctestdir/ld
+# initpri3b_LDFLAGS = -Bgcctestdir/ -Wl,--no-ctors-in-init-array
+# initpri3b_LDADD =
+
+# Test --detect-odr-violations
+check_SCRIPTS += debug_msg.sh
+
+# Create the data files that debug_msg.sh analyzes.
+check_DATA += debug_msg.err
+MOSTLYCLEANFILES += debug_msg.err
+debug_msg.o: debug_msg.cc
+ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/debug_msg.cc
+odr_violation1.o: odr_violation1.cc
+ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation1.cc
+# Compile with different optimization flags to check that rearranged
+# instructions don't cause a false positive.
+odr_violation2.o: odr_violation2.cc
+ $(CXXCOMPILE) -O2 -g -c -w -o $@ $(srcdir)/odr_violation2.cc
+debug_msg.err: debug_msg.o odr_violation1.o odr_violation2.o gcctestdir/ld
+ @echo $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o "2>$@"
+ @if $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o 2>$@; \
+ then \
+ echo 1>&2 "Link of debug_msg should have failed"; \
+ rm -f $@; \
+ exit 1; \
+ fi
+
+# Test error message when a vtable is undefined.
+check_SCRIPTS += missing_key_func.sh
+check_DATA += missing_key_func.err
+MOSTLYCLEANFILES += missing_key_func.err
+missing_key_func.o: missing_key_func.cc
+ $(CXXCOMPILE) -O0 -g -c -o $@ $(srcdir)/missing_key_func.cc
+missing_key_func.err: missing_key_func.o gcctestdir/ld
+ @echo $(CXXLINK) -Bgcctestdir/ -o missing_key_func missing_key_func.o "2>$@"
+ @if $(CXXLINK) -Bgcctestdir/ -o missing_key_func missing_key_func.o 2>$@; \
+ then \
+ echo 1>&2 "Link of missing_key_func should have failed"; \
+ rm -f $@; \
+ exit 1; \
+ fi
+
+if HAVE_ZLIB
+
+# Check that --detect-odr-violations works with compressed debug sections.
+check_DATA += debug_msg_cdebug.err
+MOSTLYCLEANFILES += debug_msg_cdebug.err
+debug_msg_cdebug.o: debug_msg.cc gcctestdir/as
+ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g -Wa,--compress-debug-sections -c -w -o $@ $(srcdir)/debug_msg.cc
+odr_violation1_cdebug.o: odr_violation1.cc gcctestdir/as
+ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g -Wa,--compress-debug-sections -c -w -o $@ $(srcdir)/odr_violation1.cc
+odr_violation2_cdebug.o: odr_violation2.cc gcctestdir/as
+ $(CXXCOMPILE) -Bgcctestdir/ -O2 -g -Wa,--compress-debug-sections -c -w -o $@ $(srcdir)/odr_violation2.cc
+debug_msg_cdebug.err: debug_msg_cdebug.o odr_violation1_cdebug.o odr_violation2_cdebug.o gcctestdir/ld
+ @echo $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg_cdebug debug_msg_cdebug.o odr_violation1_cdebug.o odr_violation2_cdebug.o "2>$@"
+ @if $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg_cdebug debug_msg_cdebug.o odr_violation1_cdebug.o odr_violation2_cdebug.o 2>$@; \
+ then \
+ echo 1>&2 "Link of debug_msg_cdebug should have failed"; \
+ rm -f $@; \
+ exit 1; \
+ fi
+
+endif HAVE_ZLIB
+
+# See if we can also detect problems when we're linking .so's, not .o's.
+check_DATA += debug_msg_so.err
+MOSTLYCLEANFILES += debug_msg_so.err
+debug_msg.so: debug_msg.cc gcctestdir/ld
+ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g -shared -fPIC -w -o $@ $(srcdir)/debug_msg.cc
+odr_violation1.so: odr_violation1.cc gcctestdir/ld
+ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g -shared -fPIC -w -o $@ $(srcdir)/odr_violation1.cc
+odr_violation2.so: odr_violation2.cc gcctestdir/ld
+ $(CXXCOMPILE) -Bgcctestdir/ -O2 -g -shared -fPIC -w -o $@ $(srcdir)/odr_violation2.cc
+debug_msg_so.err: debug_msg.so odr_violation1.so odr_violation2.so gcctestdir/ld
+ @echo $(CXXLINK_S) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg_so debug_msg.so odr_violation1.so odr_violation2.so "2>$@"
+ @if $(CXXLINK_S) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg_so debug_msg.so odr_violation1.so odr_violation2.so 2>$@; \
+ then \
+ echo 1>&2 "Link of debug_msg_so should have failed"; \
+ rm -f $@; \
+ exit 1; \
+ fi
+
+# We also want to make sure we do something reasonable when there's no
+# debug info available. For the best test, we use .so's.
+check_DATA += debug_msg_ndebug.err
+MOSTLYCLEANFILES += debug_msg_ndebug.err
+debug_msg_ndebug.so: debug_msg.cc gcctestdir/ld
+ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g0 -shared -fPIC -w -o $@ $(srcdir)/debug_msg.cc
+odr_violation1_ndebug.so: odr_violation1.cc gcctestdir/ld
+ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g0 -shared -fPIC -w -o $@ $(srcdir)/odr_violation1.cc
+odr_violation2_ndebug.so: odr_violation2.cc gcctestdir/ld
+ $(CXXCOMPILE) -Bgcctestdir/ -O2 -g0 -shared -fPIC -w -o $@ $(srcdir)/odr_violation2.cc
+debug_msg_ndebug.err: debug_msg_ndebug.so odr_violation1_ndebug.so odr_violation2_ndebug.so gcctestdir/ld
+ @echo $(CXXLINK_S) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg_ndebug debug_msg_ndebug.so odr_violation1_ndebug.so odr_violation2_ndebug.so -shared-libgcc -Bdynamic -lstdc++ "2>$@"
+ @if $(CXXLINK_S) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg_ndebug debug_msg_ndebug.so odr_violation1_ndebug.so odr_violation2_ndebug.so -shared-libgcc -Bdynamic -lstdc++ 2>$@; \
+ then \
+ echo 1>&2 "Link of debug_msg_ndebug should have failed"; \
+ rm -f $@; \
+ exit 1; \
+ fi
+
+
+# Similar to --detect-odr-violations: check for undefined symbols in .so's
+check_SCRIPTS += undef_symbol.sh
+check_DATA += undef_symbol.err
+MOSTLYCLEANFILES += undef_symbol.err
+undef_symbol.o: undef_symbol.cc
+ $(CXXCOMPILE) -O0 -g -c -fPIC $<
+undef_symbol.so: undef_symbol.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared undef_symbol.o
+undef_symbol.err: undef_symbol_main.o undef_symbol.so gcctestdir/ld
+ @echo $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so "2>$@"
+ @if $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so 2>$@; \
+ then \
+ echo 1>&2 "Link of undef_symbol_test should have failed"; \
+ rm -f $@; \
+ exit 1; \
+ fi
+
+
+# Test -o when emitting to a special file (such as something in /dev).
+check_PROGRAMS += flagstest_o_specialfile
+flagstest_o_specialfile: flagstest_debug.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -o /dev/stdout $< 2>&1 | cat > $@
+ chmod a+x $@
+ test -s $@
+
+if HAVE_ZLIB
+
+# Test --compress-debug-sections. FIXME: check we actually compress.
+check_PROGRAMS += flagstest_compress_debug_sections
+flagstest_compress_debug_sections: flagstest_debug.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -o $@ $< -Wl,--compress-debug-sections=zlib
+ test -s $@
+
+
+# The specialfile output has a tricky case when we also compress debug
+# sections, because it requires output-file resizing.
+check_PROGRAMS += flagstest_o_specialfile_and_compress_debug_sections
+flagstest_o_specialfile_and_compress_debug_sections: flagstest_debug.o \
+ gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -o /dev/stdout $< -Wl,--compress-debug-sections=zlib 2>&1 | cat > $@
+ chmod a+x $@
+ test -s $@
+
+endif HAVE_ZLIB
+
+# Test -TText and -Tdata.
+check_PROGRAMS += flagstest_o_ttext_1
+flagstest_o_ttext_1: flagstest_debug.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -o $@ $< -Wl,-Ttext,0x400000 -Wl,-Tdata,0x800000
+
+# This version won't be runnable, because there is no way to put the
+# PT_PHDR segment at file offset 0. We just make sure that we can
+# build it without error.
+check_DATA += flagstest_o_ttext_2
+MOSTLYCLEANFILES += flagstest_o_ttext_2
+flagstest_o_ttext_2: flagstest_debug.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -o $@ $< -Wl,-Ttext,0x400010 -Wl,-Tdata,0x800010
+
+# Test symbol versioning.
+check_PROGRAMS += ver_test
+ver_test_SOURCES = ver_test_main.cc
+ver_test_DEPENDENCIES = gcctestdir/ld ver_test_1.so ver_test_2.so ver_test_4.so
+ver_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+ver_test_LDADD = ver_test_1.so ver_test_2.so ver_test_4.so
+ver_test_1.so: ver_test_1.o ver_test_2.so ver_test_3.o ver_test_4.so gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared ver_test_1.o ver_test_2.so ver_test_3.o ver_test_4.so
+ver_test_2.so: ver_test_2.o $(srcdir)/ver_test_2.script ver_test_4.so gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_2.script -Wl,-R,. ver_test_2.o ver_test_4.so
+ver_test_4.so: ver_test_4.o $(srcdir)/ver_test_4.script gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_4.script ver_test_4.o
+ver_test_1.o: ver_test_1.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+ver_test_2.o: ver_test_2.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+ver_test_3.o: ver_test_3.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+ver_test_4.o: ver_test_4.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+
+check_SCRIPTS += ver_test_1.sh
+check_DATA += ver_test_1.syms
+ver_test_1.syms: ver_test_1.so
+ $(TEST_READELF) -s $< >$@ 2>/dev/null
+
+check_PROGRAMS += ver_test_2
+ver_test_2_SOURCES = ver_test_main_2.cc
+ver_test_2_DEPENDENCIES = gcctestdir/ld ver_test_4.so ver_test_2.so
+ver_test_2_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+ver_test_2_LDADD = ver_test_4.so ver_test_2.so
+
+check_SCRIPTS += ver_test_2.sh
+check_DATA += ver_test_2.syms
+ver_test_2.syms: ver_test_2
+ $(TEST_READELF) -s $< >$@ 2>/dev/null
+
+check_SCRIPTS += ver_test_4.sh
+check_DATA += ver_test_4.syms
+ver_test_4.syms: ver_test_4.so
+ $(TEST_READELF) -s $< >$@ 2>/dev/null
+
+ver_test_5.so: ver_test_5.o $(srcdir)/ver_test_5.script ver_test_4.so gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_5.script ver_test_5.o ver_test_4.so
+ver_test_5.o: ver_test_5.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+check_SCRIPTS += ver_test_5.sh
+check_DATA += ver_test_5.syms
+ver_test_5.syms: ver_test_5.so
+ $(TEST_READELF) -s $< >$@ 2>/dev/null
+
+check_PROGRAMS += ver_test_6
+ver_test_6_SOURCES = ver_test_6.c
+ver_test_6_DEPENDENCIES = gcctestdir/ld ver_test_2.so
+ver_test_6_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+ver_test_6_LDADD = ver_test_2.so
+
+ver_test_7.so: ver_test_4.o $(srcdir)/ver_test_4.script ver_test_7.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_4.script ver_test_4.o ver_test_7.o
+ver_test_7.o: ver_test_7.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+check_SCRIPTS += ver_test_7.sh
+check_DATA += ver_test_7.syms
+ver_test_7.syms: ver_test_7.so
+ $(TEST_READELF) -s $< >$@ 2>/dev/null
+
+check_PROGRAMS += ver_test_8
+ver_test_8_SOURCES = two_file_test_main.cc
+ver_test_8_DEPENDENCIES = gcctestdir/ld ver_test_8_1.so ver_test_8_2.so
+ver_test_8_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+ver_test_8_LDADD = ver_test_8_1.so ver_test_8_2.so
+ver_test_8_1.so: two_file_test_1_pic.o two_file_test_1b_pic.o ver_test_8_2.so gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_1b_pic.o ver_test_8_2.so
+ver_test_8_2.so: two_file_test_2_pic.o $(srcdir)/ver_test_8.script gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_8.script two_file_test_2_pic.o
+
+check_PROGRAMS += ver_test_9
+ver_test_9_SOURCES = ver_test_main.cc
+ver_test_9_DEPENDENCIES = gcctestdir/ld ver_test_9.so
+ver_test_9_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+ver_test_9_LDADD = ver_test_9.so
+ver_test_9.so: ver_test_9.o ver_test_4.so ver_test_5.so gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-R,. ver_test_9.o ver_test_5.so ver_test_4.so
+ver_test_9.o: ver_test_9.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+
+check_SCRIPTS += ver_test_10.sh
+check_DATA += ver_test_10.syms
+ver_test_10.syms: ver_test_10.so
+ $(TEST_READELF) -s $< >$@ 2>/dev/null
+ver_test_10.so: gcctestdir/ld ver_test_2.o ver_test_10.script
+ $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_10.script ver_test_2.o
+
+check_PROGRAMS += ver_test_11
+MOSTLYCLEANFILES += ver_test_11.a
+ver_test_11_SOURCES = ver_test_main_2.cc
+ver_test_11_DEPENDENCIES = gcctestdir/ld ver_test_11.a
+ver_test_11_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+ver_test_11_LDADD = ver_test_11.a
+ver_test_11.a: ver_test_1.o ver_test_2.o ver_test_4.o
+ $(TEST_AR) rc $@ $^
+
+check_PROGRAMS += ver_test_12
+ver_test_12_SOURCES = ver_test_main_2.cc
+ver_test_12_DEPENDENCIES = gcctestdir/ld ver_test_12.o
+ver_test_12_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+ver_test_12_LDADD = ver_test_12.o
+ver_test_12.o: gcctestdir/ld ver_test_1.o ver_test_2.o ver_test_4.o
+ gcctestdir/ld -r -o $@ ver_test_1.o ver_test_2.o ver_test_4.o
+
+check_PROGRAMS += protected_1
+protected_1_SOURCES = \
+ protected_main_1.cc protected_main_2.cc protected_main_3.cc
+protected_1_DEPENDENCIES = gcctestdir/ld protected_1.so
+protected_1_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+protected_1_LDADD = protected_1.so
+
+protected_1.so: gcctestdir/ld protected_1_pic.o protected_2_pic.o protected_3_pic.o
+ $(CXXLINK) -Bgcctestdir/ -shared protected_1_pic.o protected_2_pic.o protected_3_pic.o
+protected_1_pic.o: protected_1.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+protected_2_pic.o: protected_2.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+protected_3_pic.o: protected_3.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+
+check_PROGRAMS += protected_2
+protected_2_SOURCES = protected_main_1.cc protected_3.cc
+protected_2_DEPENDENCIES = gcctestdir/ld protected_1.so
+protected_2_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+protected_2_LDADD = protected_1.so
+
+check_DATA += protected_3.err
+MOSTLYCLEANFILES += protected_3.err
+protected_4_pic.o: protected_4.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+protected_3.err: protected_4_pic.o gcctestdir/ld
+ @echo $(CXXLINK) -Bgcctestdir/ -shared -o protected_4.so protected_4_pic.o "2>$@"
+ @if $(CXXLINK) -Bgcctestdir/ -shared -o protected_4.so protected_4_pic.o 2>$@; then \
+ echo 1>&2 "Link of protected_4.so should have failed"; \
+ rm -f $@; \
+ exit 1; \
+ fi
+
+check_PROGRAMS += relro_test
+check_SCRIPTS += relro_test.sh
+check_DATA += relro_test.stdout
+relro_test_SOURCES = relro_test_main.cc
+relro_test_DEPENDENCIES = gcctestdir/ld relro_test.so
+relro_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+relro_test_LDADD = relro_test.so
+relro_test.so: gcctestdir/ld relro_test_pic.o
+ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-z,relro relro_test_pic.o
+relro_test_pic.o: relro_test.cc
+ $(CXXCOMPILE) -c -fpic -o $@ $<
+relro_test.stdout: relro_test.so
+ $(TEST_READELF) -SlW relro_test.so > relro_test.stdout
+
+check_PROGRAMS += relro_now_test
+relro_now_test_SOURCES = relro_test_main.cc
+relro_now_test_DEPENDENCIES = gcctestdir/ld relro_now_test.so
+relro_now_test_LDFLAGS = -Bgcctestdir -Wl,-R,. -Wl,-z,relro -Wl,-z,now
+relro_now_test_LDADD = relro_now_test.so
+relro_now_test.so: gcctestdir/ld relro_test_pic.o
+ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-z,relro -Wl,-z,now relro_test_pic.o
+
+check_PROGRAMS += relro_strip_test
+relro_strip_test_SOURCES = relro_test_main.cc
+relro_strip_test_DEPENDENCIES = gcctestdir/ld relro_strip_test.so
+relro_strip_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+relro_strip_test_LDADD = relro_strip_test.so
+relro_strip_test.so: relro_test.so
+ $(TEST_STRIP) -o $@ $<
+
+check_PROGRAMS += relro_script_test
+relro_script_test_SOURCES = relro_test_main.cc
+relro_script_test_DEPENDENCIES = gcctestdir/ld relro_script_test.so
+relro_script_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+relro_script_test_LDADD = relro_script_test.so
+relro_script_test.so: gcctestdir/ld relro_script_test.t relro_test_pic.o
+ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-z,relro -Wl,-T,$(srcdir)/relro_script_test.t relro_test_pic.o
+
+check_PROGRAMS += script_test_1
+script_test_1_SOURCES = script_test_1.cc
+script_test_1_DEPENDENCIES = gcctestdir/ld script_test_1.t
+script_test_1_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -Wl,-T,$(srcdir)/script_test_1.t
+script_test_1_LDADD =
+
+check_PROGRAMS += script_test_2
+script_test_2_SOURCES = script_test_2.cc script_test_2a.cc script_test_2b.cc
+script_test_2_DEPENDENCIES = gcctestdir/ld script_test_2.t
+script_test_2_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -Wl,-T,$(srcdir)/script_test_2.t
+script_test_2_LDADD =
+
+check_PROGRAMS += justsyms
+justsyms_SOURCES = justsyms_1.cc
+justsyms_DEPENDENCIES = gcctestdir/ld justsyms_2r.o
+justsyms_LDFLAGS = -Bgcctestdir/ -Wl,-R,justsyms_2r.o
+justsyms_LDADD =
+justsyms_2.o: justsyms_2.cc
+ $(CXXCOMPILE) -c -o $@ $<
+justsyms_2r.o: justsyms_2.o gcctestdir/ld $(srcdir)/justsyms.t
+ gcctestdir/ld -o $@ -r -T $(srcdir)/justsyms.t justsyms_2.o
+
+check_PROGRAMS += justsyms_exec
+justsyms_exec_SOURCES = justsyms_exec.c
+justsyms_exec_DEPENDENCIES = gcctestdir/ld justsyms_lib
+justsyms_exec_LDFLAGS = -Bgcctestdir/ -Wl,-R,justsyms_lib
+justsyms_exec_LDADD =
+MOSTLYCLEANFILES += justsyms_lib
+justsyms_lib.o: justsyms_lib.c
+ $(COMPILE) -c -o $@ $<
+justsyms_lib: justsyms_lib.o gcctestdir/ld
+ gcctestdir/ld -o $@ -Ttext=0x1000200 -Tdata=0x2000000 -e exported_func justsyms_lib.o
+
+check_PROGRAMS += binary_test
+MOSTLYCLEANFILES += binary.txt
+binary_test_SOURCES = binary_test.cc
+binary_test_DEPENDENCIES = gcctestdir/ld binary.txt
+binary_test_LDFLAGS = -Bgcctestdir/ -Wl,--format,binary,binary.txt,--format,elf
+binary_test_LDADD =
+# Copy the file to the build directory to avoid worrying about the
+# full pathname in the generated symbols.
+binary.txt: $(srcdir)/binary.in
+ rm -f $@
+ $(LN_S) $< $@
+
+check_SCRIPTS += ver_matching_test.sh
+check_DATA += ver_matching_test.stdout
+MOSTLYCLEANFILES += ver_matching_test.stdout
+ver_matching_def.so: ver_matching_def_pic.o $(srcdir)/version_script.map gcctestdir/ld
+ $(CXXLINK) -O0 -Bgcctestdir/ -shared ver_matching_def_pic.o -Wl,--version-script=$(srcdir)/version_script.map
+ver_matching_def_pic.o: ver_matching_def.cc
+ $(CXXCOMPILE) -O0 -c -fpic -o $@ $<
+ver_matching_test.stdout: ver_matching_def.so
+ $(TEST_OBJDUMP) -T ver_matching_def.so | $(TEST_CXXFILT) > ver_matching_test.stdout
+
+check_PROGRAMS += script_test_3
+check_SCRIPTS += script_test_3.sh
+check_DATA += script_test_3.stdout
+MOSTLYCLEANFILES += script_test_3.stdout
+script_test_3: basic_test.o gcctestdir/ld script_test_3.t
+ $(CXXLINK) -Bgcctestdir/ basic_test.o -Wl,-T,$(srcdir)/script_test_3.t
+script_test_3.stdout: script_test_3
+ $(TEST_READELF) -SlW script_test_3 > script_test_3.stdout
+
+check_PROGRAMS += tls_phdrs_script_test
+tls_phdrs_script_test_SOURCES = $(tls_test_SOURCES)
+tls_phdrs_script_test_DEPENDENCIES = $(tls_test_DEPENDENCIES) $(srcdir)/script_test_3.t
+tls_phdrs_script_test_LDFLAGS = $(tls_test_LDFLAGS) -Wl,-T,$(srcdir)/script_test_3.t
+tls_phdrs_script_test_LDADD = $(tls_test_LDADD)
+
+check_SCRIPTS += script_test_4.sh
+check_DATA += script_test_4.stdout
+MOSTLYCLEANFILES += script_test_4
+script_test_4: basic_test.o gcctestdir/ld $(srcdir)/script_test_4.t
+ $(CXXLINK) -Bgcctestdir/ basic_test.o -Wl,-T,$(srcdir)/script_test_4.t
+script_test_4.stdout: script_test_4
+ $(TEST_READELF) -SlW script_test_4 > script_test_4.stdout
+
+check_PROGRAMS += tls_script_test
+tls_script_test_SOURCES = $(tls_test_SOURCES)
+tls_script_test_DEPENDENCIES = $(tls_test_DEPENDENCIES) $(srcdir)/script_test_4.t
+tls_script_test_LDFLAGS = $(tls_test_LDFLAGS) -Wl,-T,$(srcdir)/script_test_4.t
+tls_script_test_LDADD = $(tls_test_LDADD)
+
+check_SCRIPTS += script_test_5.sh
+check_DATA += script_test_5.stdout
+MOSTLYCLEANFILES += script_test_5
+script_test_5: script_test_5.o gcctestdir/ld $(srcdir)/script_test_5.t
+ $(CXXLINK) -Bgcctestdir/ script_test_5.o -Wl,-T,$(srcdir)/script_test_5.t
+script_test_5.stdout: script_test_5
+ $(TEST_READELF) -SW script_test_5 > script_test_5.stdout
+
+check_SCRIPTS += script_test_6.sh
+check_DATA += script_test_6.stdout
+MOSTLYCLEANFILES += script_test_6
+script_test_6: basic_test.o gcctestdir/ld $(srcdir)/script_test_6.t
+ $(CXXLINK) -Bgcctestdir/ basic_test.o -Wl,-T,$(srcdir)/script_test_6.t \
+ -Wl,-Ttext=0x10001000 -Wl,-Tdata=0x10200000 -Wl,-Tbss=0x10400000
+script_test_6.stdout: script_test_6
+ $(TEST_READELF) -SlW script_test_6 > script_test_6.stdout
+
+check_SCRIPTS += script_test_7.sh
+check_DATA += script_test_7.stdout
+MOSTLYCLEANFILES += script_test_7
+script_test_7: basic_test.o gcctestdir/ld $(srcdir)/script_test_7.t
+ $(CXXLINK) -Bgcctestdir/ basic_test.o -Wl,-T,$(srcdir)/script_test_7.t
+script_test_7.stdout: script_test_7
+ $(TEST_READELF) -SlW script_test_7 > script_test_7.stdout
+
+check_SCRIPTS += script_test_8.sh
+check_DATA += script_test_8.stdout
+MOSTLYCLEANFILES += script_test_8
+script_test_8: basic_test.o gcctestdir/ld $(srcdir)/script_test_7.t
+ $(CXXLINK) -Bgcctestdir/ basic_test.o -Wl,-T,$(srcdir)/script_test_7.t \
+ -Wl,-Ttext=0x20001000 -Wl,-Tdata=0x20200000 -Wl,-Tbss=0x20400000
+script_test_8.stdout: script_test_8
+ $(TEST_READELF) -SlW script_test_8 > script_test_8.stdout
+
+check_SCRIPTS += script_test_9.sh
+check_DATA += script_test_9.stdout
+MOSTLYCLEANFILES += script_test_9
+script_test_9.o: script_test_9.cc
+ $(CXXCOMPILE) -O0 -c -o $@ $<
+script_test_9: gcctestdir/ld $(srcdir)/script_test_9.t script_test_9.o
+ $(CXXLINK) -Bgcctestdir/ script_test_9.o -Wl,-T,$(srcdir)/script_test_9.t
+script_test_9.stdout: script_test_9
+ $(TEST_READELF) -lW script_test_9 > script_test_9.stdout
+
+# Test scripts with a relocatable link.
+# The -g option is necessary to trigger a bug where a section
+# declared in a script file is assigned a non-zero starting address.
+check_PROGRAMS += script_test_11
+script_test_11: gcctestdir/ld script_test_11_r.o
+ $(LINK) -Bgcctestdir/ script_test_11_r.o
+script_test_11_r.o: gcctestdir/ld $(srcdir)/script_test_11.t script_test_11.o
+ gcctestdir/ld -r -o $@ -T $(srcdir)/script_test_11.t script_test_11.o
+script_test_11.o: script_test_11.c
+ $(COMPILE) -c -g -o $@ $<
+
+# Test --dynamic-list, --dynamic-list-data, --dynamic-list-cpp-new,
+# and --dynamic-list-cpp-typeinfo
+
+check_SCRIPTS += dynamic_list.sh
+check_DATA += dynamic_list.stdout
+MOSTLYCLEANFILES += dynamic_list dynamic_list.stdout
+dynamic_list: basic_test.o gcctestdir/ld $(srcdir)/dynamic_list.t
+ $(CXXLINK) -Bgcctestdir/ basic_test.o \
+ -Wl,--dynamic-list $(srcdir)/dynamic_list.t \
+ -Wl,--dynamic-list-data \
+ -Wl,--dynamic-list-cpp-new \
+ -Wl,--dynamic-list-cpp-typeinfo
+dynamic_list.stdout: dynamic_list
+ $(TEST_READELF) -W --dyn-syms dynamic_list > dynamic_list.stdout
+
+check_PROGRAMS += thin_archive_test_1
+MOSTLYCLEANFILES += libthin1.a libthin3.a libthinall.a \
+ alt/thin_archive_test_2.o alt/thin_archive_test_4.o \
+ alt/libthin2.a alt/libthin4.a
+thin_archive_test_1_SOURCES = thin_archive_main.cc
+thin_archive_test_1_DEPENDENCIES = gcctestdir/ld libthin1.a alt/libthin2.a
+thin_archive_test_1_LDFLAGS = -Bgcctestdir/ -Lalt
+thin_archive_test_1_LDADD = libthin1.a -lthin2
+
+check_PROGRAMS += thin_archive_test_2
+thin_archive_test_2_SOURCES = thin_archive_main.cc
+thin_archive_test_2_DEPENDENCIES = gcctestdir/ld libthinall.a
+thin_archive_test_2_LDFLAGS = -Bgcctestdir/ -L.
+thin_archive_test_2_LDADD = -lthinall
+
+libthin1.a: thin_archive_test_1.o alt/thin_archive_test_2.o
+ rm -f $@
+ $(TEST_AR) crT $@ $^
+alt/libthin2.a: thin_archive_test_3.o alt/thin_archive_test_4.o
+ rm -f $@
+ $(TEST_AR) crT $@ $^
+libthin3.a: thin_archive_test_1.o alt/thin_archive_test_4.o
+ rm -f $@
+ $(TEST_AR) crT $@ $^
+alt/libthin4.a: alt/thin_archive_test_2.o thin_archive_test_3.o
+ rm -f $@
+ $(TEST_AR) crT $@ $^
+libthinall.a: libthin3.a alt/libthin4.a
+ rm -f $@
+ $(TEST_AR) crT $@ $^
+alt/thin_archive_test_2.o: thin_archive_test_2.cc
+ test -d alt || mkdir -p alt
+ $(CXXCOMPILE) -c -o $@ $<
+alt/thin_archive_test_4.o: thin_archive_test_4.cc
+ test -d alt || mkdir -p alt
+ $(CXXCOMPILE) -c -o $@ $<
+
+if PLUGINS
+
+check_PROGRAMS += plugin_test_1
+check_SCRIPTS += plugin_test_1.sh
+check_DATA += plugin_test_1.err
+MOSTLYCLEANFILES += plugin_test_1.err
+plugin_test_1: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms empty.syms gcctestdir/ld plugin_test.so
+ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv" two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms empty.syms 2>plugin_test_1.err
+plugin_test_1.err: plugin_test_1
+ @touch plugin_test_1.err
+
+check_PROGRAMS += plugin_test_2
+check_SCRIPTS += plugin_test_2.sh
+check_DATA += plugin_test_2.err
+MOSTLYCLEANFILES += plugin_test_2.err
+plugin_test_2: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_shared_2.so gcctestdir/ld plugin_test.so
+ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,-R,.,--plugin,"./plugin_test.so" two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_shared_2.so 2>plugin_test_2.err
+plugin_test_2.err: plugin_test_2
+ @touch plugin_test_2.err
+
+check_PROGRAMS += plugin_test_3
+check_SCRIPTS += plugin_test_3.sh
+check_DATA += plugin_test_3.err
+MOSTLYCLEANFILES += plugin_test_3.err
+plugin_test_3: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms empty.syms gcctestdir/ld plugin_test.so
+ $(CXXLINK) -Bgcctestdir/ -Wl,--export-dynamic -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv" two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms empty.syms 2>plugin_test_3.err
+plugin_test_3.err: plugin_test_3
+ @touch plugin_test_3.err
+
+check_PROGRAMS += plugin_test_4
+check_SCRIPTS += plugin_test_4.sh
+check_DATA += plugin_test_4.err
+MOSTLYCLEANFILES += plugin_test_4.a plugin_test_4.err
+plugin_test_4: two_file_test_main.o plugin_test_4.a gcctestdir/ld plugin_test.so
+ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv" two_file_test_main.o -Wl,--whole-archive,plugin_test_4.a,--no-whole-archive 2>plugin_test_4.err
+plugin_test_4.err: plugin_test_4
+ @touch plugin_test_4.err
+
+plugin_test_4.a: two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms
+ $(TEST_AR) cr $@ $^
+
+check_PROGRAMS += plugin_test_5
+plugin_test_5: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms unused.syms gcctestdir/ld plugin_test.so
+ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv",--gc-sections two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms unused.syms
+
+check_PROGRAMS += plugin_test_6
+check_SCRIPTS += plugin_test_6.sh
+check_DATA += plugin_test_6.err
+MOSTLYCLEANFILES += plugin_test_6.err
+plugin_test_6: plugin_common_test_1.syms plugin_common_test_2.syms gcctestdir/ld plugin_test.so
+ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so" plugin_common_test_1.syms plugin_common_test_2.syms 2>plugin_test_6.err
+plugin_test_6.err: plugin_test_6
+ @touch plugin_test_6.err
+
+check_PROGRAMS += plugin_test_7
+check_SCRIPTS += plugin_test_7.sh
+check_DATA += plugin_test_7.err plugin_test_7.syms
+MOSTLYCLEANFILES += plugin_test_7.err
+plugin_test_7: plugin_test_7_1.o plugin_test_7_1.syms plugin_test_7_2.o gcctestdir/ld plugin_test.so
+ $(LINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--gc-sections,--print-gc-sections plugin_test_7_1.syms plugin_test_7_2.o 2>plugin_test_7.err
+plugin_test_7.syms: plugin_test_7
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+plugin_test_7_1.o: plugin_test_7_1.c
+ $(COMPILE) -DLTO -O0 -c -ffunction-sections -fdata-sections -o $@ $<
+plugin_test_7_1_orig.o: plugin_test_7_1.c
+ $(COMPILE) -O0 -c -ffunction-sections -fdata-sections -o $@ $<
+plugin_test_7_1.syms: plugin_test_7_1_orig.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+plugin_test_7_2.o: plugin_test_7_2.c
+ $(COMPILE) -O0 -c -ffunction-sections -fdata-sections -o $@ $<
+plugin_test_7.err: plugin_test_7
+
+# Test plugins with -r.
+check_PROGRAMS += plugin_test_8
+plugin_test_8.o: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.o ../ld-new plugin_test.so
+ ../ld-new -r -o $@ --no-demangle --plugin "./plugin_test.so" two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.o
+plugin_test_8: plugin_test_8.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle plugin_test_8.o
+
+# Test that symbols known in the IR file but not in the replacement file
+# produce an unresolved symbol error.
+check_DATA += plugin_test_9.err
+MOSTLYCLEANFILES += plugin_test_9.err
+plugin_test_9.err: two_file_test_main.o two_file_test_1c.syms two_file_test_2.syms gcctestdir/ld plugin_test.so
+ @echo $(CXXLINK) -Bgcctestdir/ -o plugin_test_9 -Wl,--no-demangle,--plugin,"./plugin_test.so" two_file_test_main.o two_file_test_1c.syms two_file_test_2.syms "2>$@"
+ @if $(CXXLINK) -Bgcctestdir/ -o plugin_test_9 -Wl,--no-demangle,--plugin,"./plugin_test.so" two_file_test_main.o two_file_test_1c.syms two_file_test_2.syms 2>$@; then \
+ echo 1>&2 "Link of plugin_test_9 should have failed"; \
+ rm -f $@; \
+ exit 1; \
+ fi
+# Make a .syms file that claims to define the symbol _Z4t16av.
+two_file_test_1c.syms: two_file_test_1.syms two_file_test_1c.o
+ cp two_file_test_1.syms $@.tmp
+ grep "_Z4t16av" two_file_test_1b.syms >> $@.tmp
+ mv -f $@.tmp $@
+# Make a copy of two_file_test_1.o, which does not define the symbol _Z4t16av.
+MOSTLYCLEANFILES += two_file_test_1c.o
+two_file_test_1c.o: two_file_test_1.o
+ cp two_file_test_1.o $@
+
+plugin_test.so: plugin_test.o
+ $(LINK) -Bgcctestdir/ -shared plugin_test.o
+plugin_test.o: plugin_test.c
+ $(COMPILE) -O0 -c -fpic -o $@ $<
+
+two_file_test_main.syms: two_file_test_main.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+two_file_test_1.syms: two_file_test_1.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+two_file_test_1b.syms: two_file_test_1b.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+two_file_test_2.syms: two_file_test_2.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+plugin_common_test_1.syms: plugin_common_test_1.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+plugin_common_test_2.syms: plugin_common_test_2.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+
+empty.syms:
+ @echo "" >$@
+ @echo "Symbol table" >>$@
+
+if TLS
+
+check_PROGRAMS += plugin_test_tls
+check_SCRIPTS += plugin_test_tls.sh
+check_DATA += plugin_test_tls.err
+MOSTLYCLEANFILES += plugin_test_tls.err
+plugin_test_tls: two_file_test_tls.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2_tls.syms gcctestdir/ld plugin_test.so
+ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv" two_file_test_tls.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2_tls.syms 2>plugin_test_tls.err
+plugin_test_tls.err: plugin_test_tls
+ @touch plugin_test_tls.err
+
+two_file_test_2_tls.syms: two_file_test_2_tls.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+
+endif TLS
+
+MOSTLYCLEANFILES += unused.c
+unused.syms: unused.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+ @echo " 1: 00000000 4 FUNC GLOBAL DEFAULT 1 UNUSED" >>$@
+unused.o: unused.c
+ $(COMPILE) -c -o $@ $<
+unused.c:
+ @cp /dev/null $@
+
+check_SCRIPTS += plugin_final_layout.sh
+check_DATA += plugin_final_layout.stdout plugin_final_layout_readelf.stdout
+MOSTLYCLEANFILES += plugin_final_layout
+plugin_final_layout.o: plugin_final_layout.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -fdata-sections -g -o $@ $<
+plugin_final_layout: plugin_final_layout.o plugin_section_order.so gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--plugin,"./plugin_section_order.so" plugin_final_layout.o
+plugin_final_layout.stdout: plugin_final_layout
+ $(TEST_NM) -n --synthetic plugin_final_layout > plugin_final_layout.stdout
+plugin_final_layout_readelf.stdout: plugin_final_layout
+ $(TEST_READELF) -Wl plugin_final_layout > plugin_final_layout_readelf.stdout
+
+plugin_section_order.so: plugin_section_order.o
+ $(LINK) -Bgcctestdir/ -shared plugin_section_order.o
+plugin_section_order.o: plugin_section_order.c
+ $(COMPILE) -O0 -c -fpic -o $@ $<
+
+endif PLUGINS
+
+check_PROGRAMS += exclude_libs_test
+check_SCRIPTS += exclude_libs_test.sh
+check_DATA += exclude_libs_test.syms
+MOSTLYCLEANFILES += exclude_libs_test.syms libexclude_libs_test_1.a \
+ libexclude_libs_test_2.a alt/libexclude_libs_test_3.a
+exclude_libs_test_SOURCES = exclude_libs_test.c
+exclude_libs_test_DEPENDENCIES = gcctestdir/ld libexclude_libs_test_1.a \
+ libexclude_libs_test_2.a alt/libexclude_libs_test_3.a
+exclude_libs_test_LDFLAGS = -Bgcctestdir/ -L. -Lalt \
+ -Wl,--exclude-libs,dummy:libexclude_libs_test_1 \
+ -Wl,--exclude-libs,libexclude_libs_test_3
+exclude_libs_test_LDADD = -lexclude_libs_test_1 -lexclude_libs_test_2 \
+ alt/libexclude_libs_test_3.a
+exclude_libs_test.syms: exclude_libs_test
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+libexclude_libs_test_1.a: exclude_libs_test_1.o
+ $(TEST_AR) rc $@ $^
+libexclude_libs_test_2.a: exclude_libs_test_2.o
+ $(TEST_AR) rc $@ $^
+alt/libexclude_libs_test_3.a: exclude_libs_test_3.o
+ test -d alt || mkdir -p alt
+ $(TEST_AR) rc $@ $^
+
+check_PROGRAMS += local_labels_test
+local_labels_test.o: ver_test_6.c
+ $(COMPILE) -g -c -Wa,-L -o $@ $<
+local_labels_test: local_labels_test.o
+ $(LINK) -Bgcctestdir/ local_labels_test.o
+
+check_PROGRAMS += discard_locals_test
+check_SCRIPTS += discard_locals_test.sh
+check_DATA += discard_locals_test.syms \
+ discard_locals_relocatable_test1.syms \
+ discard_locals_relocatable_test2.syms
+MOSTLYCLEANFILES += discard_locals_test.syms \
+ discard_locals_relocatable_test1.syms \
+ discard_locals_relocatable_test2.syms \
+ discard_locals_relocatable_test1.out \
+ discard_locals_relocatable_test2.out
+discard_locals_test_SOURCES = discard_locals_test.c
+discard_locals_test_LDFLAGS = -Bgcctestdir/ -Wl,--discard-locals
+discard_locals_test.syms: discard_locals_test
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+# '-Wa,-L' is required to preserve the local label used for testing.
+discard_locals_test.o: discard_locals_test.c
+ $(COMPILE) -c -Wa,-L -o $@ $<
+
+discard_locals_relocatable_test1.syms: discard_locals_relocatable_test1.out
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+discard_locals_relocatable_test.o: discard_locals_relocatable_test.c
+ $(COMPILE) -c -Wa,-L -fPIC -o $@ $<
+discard_locals_relocatable_test1.out: discard_locals_relocatable_test.o ../ld-new
+ ../ld-new --discard-locals -relocatable -o $@ $<
+
+discard_locals_relocatable_test2.syms: discard_locals_relocatable_test2.out
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+discard_locals_relocatable_test2.out: discard_locals_relocatable_test.o ../ld-new
+ ../ld-new --discard-all -relocatable -o $@ $<
+
+if MCMODEL_MEDIUM
+check_PROGRAMS += large
+large_SOURCES = large.c
+large_CFLAGS = -mcmodel=medium
+large_DEPENDENCIES = gcctestdir/ld
+large_LDFLAGS = -Bgcctestdir/
+large_LDADD =
+endif MCMODEL_MEDIUM
+
+# Test that hidden and internal symbols in the main program cannot be
+# referenced by a shared library.
+check_SCRIPTS += hidden_test.sh
+check_DATA += hidden_test.err
+MOSTLYCLEANFILES += hidden_test hidden_test.err
+libhidden.so: hidden_test_1.c gcctestdir/ld
+ $(COMPILE) -Bgcctestdir/ -g -shared -fPIC -w -o $@ $(srcdir)/hidden_test_1.c
+hidden_test: hidden_test_main.o libhidden.so gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -Wl,-R,. hidden_test_main.o libhidden.so 2>hidden_test.err
+hidden_test.err: hidden_test
+ @touch hidden_test.err
+
+# Test -retain-symbols-file.
+check_SCRIPTS += retain_symbols_file_test.sh
+check_DATA += retain_symbols_file_test.stdout
+MOSTLYCLEANFILES += retain_symbols_file_test retain_symbols_file_test.in \
+ retain_symbols_file_test.stdout
+retain_symbols_file_test.so: basic_pic_test.o gcctestdir/ld
+ echo 'main' > retain_symbols_file_test.in
+ echo 't1' >> retain_symbols_file_test.in
+ echo '_ZN4t16bC1Ev' >> retain_symbols_file_test.in
+ echo '_ZNK4t20a3getEv' >> retain_symbols_file_test.in
+ echo '_Z3t18v' >> retain_symbols_file_test.in
+ echo '__tcf_0' >> retain_symbols_file_test.in
+ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-retain-symbols-file,retain_symbols_file_test.in basic_pic_test.o
+retain_symbols_file_test.stdout: retain_symbols_file_test.so
+ $(TEST_NM) -C retain_symbols_file_test.so > $@
+
+
+# Test that if the output file already exists and is empty,
+# it will get execute permission.
+check_PROGRAMS += permission_test
+permission_test: basic_test.o gcctestdir/ld
+ umask 022; \
+ rm -f $@; \
+ touch $@; \
+ chmod 600 $@; \
+ $(CXXLINK) -Bgcctestdir/ basic_test.o
+
+# Check -l:foo.a
+check_PROGRAMS += searched_file_test
+MOSTLYCLEANFILES += searched_file_test searched_file_test_lib.o \
+ alt/searched_file_test_lib.a
+searched_file_test_SOURCES = searched_file_test.cc
+searched_file_test_DEPENDENCIES = alt/searched_file_test_lib.a
+searched_file_test_LDFLAGS = -Bgcctestdir/ -Lalt
+searched_file_test_LDADD = -l:searched_file_test_lib.a
+searched_file_test_lib.o: searched_file_test_lib.cc
+ $(CXXCOMPILE) -c -o $@ $<
+alt/searched_file_test_lib.a: searched_file_test_lib.o
+ test -d alt || mkdir -p alt
+ $(TEST_AR) rc $@ $^
+
+# Test that no .gnu.version sections are created when
+# symbol versioning is not used.
+check_SCRIPTS += no_version_test.sh
+check_DATA += no_version_test.stdout
+MOSTLYCLEANFILES += libno_version_test.so no_version_test.stdout
+# We invoke the linker directly since gcc may include additional objects that
+# uses symbol versioning.
+libno_version_test.so: no_version_test.o gcctestdir/ld
+ gcctestdir/ld -shared -o $@ no_version_test.o
+no_version_test.o: no_version_test.c
+ $(COMPILE) -o $@ -c -fPIC $<
+no_version_test.stdout: libno_version_test.so
+ $(TEST_OBJDUMP) -h $< > $@
+
+# Test STT_GNU_IFUNC symbols.
+if IFUNC
+
+ifuncmod1.o: ifuncmod1.c
+ $(COMPILE) -c -fPIC -o $@ $<
+ifuncmod1.so: ifuncmod1.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -shared ifuncmod1.o
+
+ifuncdep1.o: ifuncmod1.c
+ $(COMPILE) -c -o $@ $<
+
+ifuncmain1pic.o: ifuncmain1.c
+ $(COMPILE) -c -fPIC -o $@ $<
+ifuncmain1pie.o: ifuncmain1.c
+ $(COMPILE) -c -fPIE -o $@ $<
+
+if HAVE_STATIC
+if IFUNC_STATIC
+check_PROGRAMS += ifuncmain1static
+ifuncmain1static_SOURCES = ifuncmain1.c
+ifuncmain1static_DEPENDENCIES = gcctestdir/ld ifuncdep1.o
+ifuncmain1static_LDFLAGS = -Bgcctestdir/ -static
+ifuncmain1static_LDADD = ifuncdep1.o
+
+check_PROGRAMS += ifuncmain1picstatic
+ifuncmain1picstatic: ifuncmain1pic.o ifuncmod1.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -static ifuncmain1pic.o ifuncmod1.o
+endif
+endif
+
+check_PROGRAMS += ifuncmain1
+ifuncmain1_SOURCES = ifuncmain1.c
+ifuncmain1_DEPENDENCIES = gcctestdir/ld ifuncmod1.so
+ifuncmain1_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+ifuncmain1_LDADD = ifuncmod1.so
+
+check_PROGRAMS += ifuncmain1pic
+ifuncmain1pic: ifuncmain1pic.o ifuncmod1.so gcctestdir/ld
+ $(LINK) -Bgcctestdir/ ifuncmain1pic.o ifuncmod1.so -Wl,-R,.
+
+check_PROGRAMS += ifuncmain1vis
+ifuncmain1vis_SOURCES = ifuncmain1vis.c
+ifuncmain1vis_DEPENDENCIES = gcctestdir/ld ifuncmod1.so
+ifuncmain1vis_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+ifuncmain1vis_LDADD = ifuncmod1.so
+
+check_PROGRAMS += ifuncmain1vispic
+ifuncmain1vispic.o: ifuncmain1vis.c
+ $(COMPILE) -c -fPIC -o $@ $<
+ifuncmain1vispic: ifuncmain1vispic.o ifuncmod1.so gcctestdir/ld
+ $(LINK) -Bgcctestdir/ ifuncmain1pic.o ifuncmod1.so -Wl,-R,.
+
+check_PROGRAMS += ifuncmain1staticpic
+ifuncmain1staticpic: ifuncmain1pic.o ifuncmod1.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ ifuncmain1pic.o ifuncmod1.o
+
+check_PROGRAMS += ifuncmain1pie
+ifuncmain1pie: ifuncmain1pie.o ifuncmod1.so gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -pie ifuncmain1pie.o ifuncmod1.so -Wl,-R,.
+
+check_PROGRAMS += ifuncmain1vispie
+ifuncmain1vispie.o: ifuncmain1vis.c
+ $(COMPILE) -c -fPIE -o $@ $<
+ifuncmain1vispie: ifuncmain1vispie.o ifuncmod1.so gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -pie ifuncmain1vispie.o ifuncmod1.so -Wl,-R,.
+
+check_PROGRAMS += ifuncmain1staticpie
+ifuncmain1staticpie: ifuncmain1pie.o ifuncmod1.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -pie ifuncmain1pie.o ifuncmod1.o
+
+ifuncmain2pic.o: ifuncmain2.c
+ $(COMPILE) -c -fPIC -o $@ $<
+
+ifuncdep2pic.o: ifuncdep2.c
+ $(COMPILE) -c -fPIC -o $@ $<
+
+if HAVE_STATIC
+if IFUNC_STATIC
+check_PROGRAMS += ifuncmain2static
+ifuncmain2static_SOURCES = ifuncmain2.c ifuncdep2.c
+ifuncmain2static_DEPENDENCIES = gcctestdir/ld
+ifuncmain2static_LDFLAGS = -Bgcctestdir/ -static
+ifuncmain2static_LDADD =
+
+check_PROGRAMS += ifuncmain2picstatic
+ifuncmain2picstatic: ifuncmain2pic.o ifuncdep2pic.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -static ifuncmain2pic.o ifuncdep2pic.o
+endif
+endif
+
+check_PROGRAMS += ifuncmain2
+ifuncmain2_SOURCES = ifuncmain2.c ifuncdep2.c
+ifuncmain2_DEPENDENCIES = gcctestdir/ld
+ifuncmain2_LDFLAGS = -Bgcctestdir/
+ifuncmain2_LDADD =
+
+check_PROGRAMS += ifuncmain2pic
+ifuncmain2pic: ifuncmain2pic.o ifuncdep2pic.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ ifuncmain2pic.o ifuncdep2pic.o
+
+ifuncmod3.o: ifuncmod3.c
+ $(COMPILE) -c -fPIC -o $@ $<
+ifuncmod3.so: ifuncmod3.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -shared ifuncmod3.o
+
+check_PROGRAMS += ifuncmain3
+ifuncmain3_SOURCES = ifuncmain3.c
+ifuncmain3_DEPENDENCIES = gcctestdir/ld ifuncmod3.so
+ifuncmain3_LDFLAGS = -Bgcctestdir/ -Wl,--export-dynamic -Wl,-R,.
+ifuncmain3_LDADD = -ldl
+
+ifuncmain4pic.o: ifuncmain4.c
+ $(COMPILE) -c -fPIC -o $@ $<
+
+if HAVE_STATIC
+if IFUNC_STATIC
+check_PROGRAMS += ifuncmain4static
+ifuncmain4static_SOURCES = ifuncmain4.c
+ifuncmain4static_DEPENDENCIES = gcctestdir/ld
+ifuncmain4static_LDFLAGS = -Bgcctestdir/ -static
+ifuncmain4static_LDADD =
+
+check_PROGRAMS += ifuncmain4picstatic
+ifuncmain4picstatic: ifuncmain4pic.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -static ifuncmain4pic.o
+endif
+endif
+
+check_PROGRAMS += ifuncmain4
+ifuncmain4_SOURCES = ifuncmain4.c
+ifuncmain4_DEPENDENCIES = gcctestdir/ld
+ifuncmain4_LDFLAGS = -Bgcctestdir/
+ifuncmain4_LDADD =
+
+ifuncmain5pic.o: ifuncmain5.c
+ $(COMPILE) -c -fPIC -o $@ $<
+
+ifuncmain5pie.o: ifuncmain5.c
+ $(COMPILE) -c -fPIE -o $@ $<
+
+ifuncmod5.o: ifuncmod5.c
+ $(COMPILE) -c -fPIC -o $@ $<
+ifuncmod5.so: ifuncmod5.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -shared ifuncmod5.o
+
+ifuncdep5.o: ifuncmod5.c
+ $(COMPILE) -c -o $@ $<
+
+if HAVE_STATIC
+if IFUNC_STATIC
+check_PROGRAMS += ifuncmain5static
+ifuncmain5static_SOURCES = ifuncmain5.c
+ifuncmain5static_DEPENDENCIES = gcctestdir/ld ifuncdep5.o
+ifuncmain5static_LDFLAGS = -Bgcctestdir/ -static
+ifuncmain5static_LDADD = ifuncdep5.o
+
+check_PROGRAMS += ifuncmain5picstatic
+ifuncmain5picstatic: ifuncmain5pic.o ifuncmod5.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -static ifuncmain5pic.o ifuncmod5.o
+endif
+endif
+
+check_PROGRAMS += ifuncmain5
+ifuncmain5_SOURCES = ifuncmain5.c
+ifuncmain5_DEPENDENCIES = gcctestdir/ld ifuncmod5.so
+ifuncmain5_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+ifuncmain5_LDADD = ifuncmod5.so
+
+check_PROGRAMS += ifuncmain5pic
+ifuncmain5pic: ifuncmain5pic.o ifuncmod5.so gcctestdir/ld
+ $(LINK) -Bgcctestdir/ ifuncmain5pic.o ifuncmod5.so -Wl,-R,.
+
+check_PROGRAMS += ifuncmain5staticpic
+ifuncmain5staticpic: ifuncmain5pic.o ifuncmod5.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ ifuncmain5pic.o ifuncmod5.o
+
+check_PROGRAMS += ifuncmain5pie
+ifuncmain5pie: ifuncmain5pie.o ifuncmod5.so gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -pie ifuncmain5pie.o ifuncmod5.so -Wl,-R,.
+
+ifuncmain6pie.o: ifuncmain6pie.c
+ $(COMPILE) -c -fPIE -o $@ $<
+
+ifuncmod6.o: ifuncmod6.c
+ $(COMPILE) -c -fPIC -o $@ $<
+ifuncmod6.so: ifuncmod6.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -shared ifuncmod6.o
+
+check_PROGRAMS += ifuncmain6pie
+ifuncmain6pie: ifuncmain6pie.o ifuncmod6.so gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -pie ifuncmain6pie.o ifuncmod6.so -Wl,-R,.
+
+ifuncmain7pic.o: ifuncmain7.c
+ $(COMPILE) -c -fPIC -o $@ $<
+
+ifuncmain7pie.o: ifuncmain7.c
+ $(COMPILE) -c -fPIE -o $@ $<
+
+if HAVE_STATIC
+if IFUNC_STATIC
+check_PROGRAMS += ifuncmain7static
+ifuncmain7static_SOURCES = ifuncmain7.c
+ifuncmain7static_DEPENDENCIES = gcctestdir/ld
+ifuncmain7static_LDFLAGS = -Bgcctestdir/ -static
+ifuncmain7static_LDADD =
+
+check_PROGRAMS += ifuncmain7picstatic
+ifuncmain7picstatic: ifuncmain7pic.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -static ifuncmain7pic.o
+endif
+endif
+
+check_PROGRAMS += ifuncmain7
+ifuncmain7_SOURCES = ifuncmain7.c
+ifuncmain7_DEPENDENCIES = gcctestdir/ld
+ifuncmain7_LDFLAGS = -Bgcctestdir/
+ifuncmain7_LDADD =
+
+check_PROGRAMS += ifuncmain7pic
+ifuncmain7pic: ifuncmain7pic.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ ifuncmain7pic.o
+
+check_PROGRAMS += ifuncmain7pie
+ifuncmain7pie: ifuncmain7pie.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -pie ifuncmain7pie.o
+
+check_PROGRAMS += ifuncvar
+ifuncvar1_pic.o: ifuncvar1.c
+ $(COMPILE) -c -fPIC -o $@ $<
+ifuncvar2_pic.o: ifuncvar2.c
+ $(COMPILE) -c -fPIC -o $@ $<
+ifuncvar.so: ifuncvar1_pic.o ifuncvar2_pic.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -shared ifuncvar1_pic.o ifuncvar2_pic.o
+ifuncvar_SOURCES = ifuncvar3.c
+ifuncvar_DEPENDENCIES = gcctestdir/ld ifuncvar.so
+ifuncvar_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+ifuncvar_LDADD = ifuncvar.so
+
+endif IFUNC
+
+# Test that strong reference to a weak symbol in a DSO remains strong.
+check_SCRIPTS += strong_ref_weak_def.sh
+check_DATA += strong_ref_weak_def.stdout
+MOSTLYCLEANFILES += strong_ref_weak_def_1.so strong_ref_weak_def_2.so \
+ strong_ref_weak_def.stdout
+strong_ref_weak_def_2.o: strong_ref_weak_def_2.c
+ $(COMPILE) -o $@ -c -fPIC $<
+strong_ref_weak_def_2.so: strong_ref_weak_def_2.o gcctestdir/ld
+ gcctestdir/ld -shared -o $@ strong_ref_weak_def_2.o
+strong_ref_weak_def_1.o: strong_ref_weak_def_1.c
+ $(COMPILE) -o $@ -c -fPIC $<
+strong_ref_weak_def_1.so: strong_ref_weak_def_1.o strong_ref_weak_def_2.so \
+ gcctestdir/ld
+ gcctestdir/ld -shared -o $@ strong_ref_weak_def_1.o \
+ strong_ref_weak_def_2.so
+strong_ref_weak_def.stdout: strong_ref_weak_def_1.so
+ $(TEST_READELF) -sWD $< > $@
+
+# Test that a strong weak reference remains strong if there is another
+# weak reference in a DSO.
+check_SCRIPTS += dyn_weak_ref.sh
+check_DATA += dyn_weak_ref.stdout
+MOSTLYCLEANFILES += dyn_weak_ref_1.so dyn_weak_ref_2.so \
+ dyn_weak_ref.stdout
+dyn_weak_ref_2.o: dyn_weak_ref_2.c
+ $(COMPILE) -o $@ -c -fPIC $<
+dyn_weak_ref_2.so: dyn_weak_ref_2.o gcctestdir/ld
+ gcctestdir/ld -shared -o $@ dyn_weak_ref_2.o
+dyn_weak_ref_1.o: dyn_weak_ref_1.c
+ $(COMPILE) -o $@ -c -fPIC $<
+# We intentionally put dyn_weak_ref_2.so in front of dyn_weak_ref_1.o
+# so that the weak ref there goes to gold's symbol table first.
+dyn_weak_ref_1.so: dyn_weak_ref_1.o dyn_weak_ref_2.so gcctestdir/ld
+ gcctestdir/ld -shared -o $@ dyn_weak_ref_2.so dyn_weak_ref_1.o
+dyn_weak_ref.stdout: dyn_weak_ref_1.so
+ $(TEST_READELF) -sWD $< > $@
+
+
+# Test that --start-lib and --end-lib function correctly.
+check_PROGRAMS += start_lib_test
+MOSTLYCLEANFILES += libstart_lib_test.a
+start_lib_test: start_lib_test_main.o libstart_lib_test.a start_lib_test_2.o start_lib_test_3.o \
+ gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -o $@ start_lib_test_main.o -L. -lstart_lib_test \
+ -Wl,--start-lib start_lib_test_2.o start_lib_test_3.o -Wl,--end-lib
+libstart_lib_test.a: start_lib_test_1.o
+ $(TEST_AR) rc $@ $^
+
+# Test that MEMORY region support works.
+check_SCRIPTS += memory_test.sh
+check_DATA += memory_test.stdout
+MOSTLYCLEANFILES += memory_test.stdout memory_test memory_test.o
+memory_test.o: memory_test.s
+ $(COMPILE) -o $@ -c $<
+memory_test: memory_test.o gcctestdir/ld $(srcdir)/memory_test.t
+ $(LINK) -Bgcctestdir/ -nostartfiles -nostdlib -z max-page-size=0x1000 -z common-page-size=0x1000 -Wl,-T,$(srcdir)/memory_test.t -o $@ memory_test.o
+memory_test.stdout: memory_test
+ $(TEST_READELF) -lWS $< > $@
+
+if HAVE_PUBNAMES
+
+# Test that --gdb-index functions correctly without gcc-generated pubnames.
+check_SCRIPTS += gdb_index_test_1.sh
+check_DATA += gdb_index_test_1.stdout
+MOSTLYCLEANFILES += gdb_index_test_1.stdout gdb_index_test_1
+gdb_index_test.o: gdb_index_test.cc
+ $(CXXCOMPILE) -O0 -g -gno-pubnames -c -o $@ $<
+gdb_index_test_1: gdb_index_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--gdb-index $<
+gdb_index_test_1.stdout: gdb_index_test_1
+ $(TEST_READELF) --debug-dump=gdb_index $< > $@
+
+if HAVE_ZLIB
+
+# Test that --gdb-index functions correctly with compressed debug sections.
+check_SCRIPTS += gdb_index_test_2.sh
+check_DATA += gdb_index_test_2.stdout
+MOSTLYCLEANFILES += gdb_index_test_2.stdout gdb_index_test_2
+gdb_index_test_cdebug.o: gdb_index_test.cc
+ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g -Wa,--compress-debug-sections -c -o $@ $<
+gdb_index_test_2: gdb_index_test_cdebug.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--gdb-index $<
+gdb_index_test_2.stdout: gdb_index_test_2
+ $(TEST_READELF) --debug-dump=gdb_index $< > $@
+
+endif HAVE_ZLIB
+
+# Another simple C test (DW_AT_high_pc encoding) for --gdb-index.
+check_SCRIPTS += gdb_index_test_3.sh
+check_DATA += gdb_index_test_3.stdout
+MOSTLYCLEANFILES += gdb_index_test_3.stdout gdb_index_test_3
+gdb_index_test_3.o: gdb_index_test_3.c
+ $(COMPILE) -O0 -g -c -o $@ $<
+gdb_index_test_3: gdb_index_test_3.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -Wl,--gdb-index,--fatal-warnings $<
+gdb_index_test_3.stdout: gdb_index_test_3
+ $(TEST_READELF) --debug-dump=gdb_index $< > $@
+
+# Test that --gdb-index functions correctly with gcc-generated pubnames.
+check_SCRIPTS += gdb_index_test_4.sh
+check_DATA += gdb_index_test_4.stdout
+MOSTLYCLEANFILES += gdb_index_test_4.stdout gdb_index_test_4
+gdb_index_test_pub.o: gdb_index_test.cc
+ $(CXXCOMPILE) -O0 -g -gpubnames -c -o $@ $<
+gdb_index_test_4: gdb_index_test_pub.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--gdb-index $<
+gdb_index_test_4.stdout: gdb_index_test_4
+ $(TEST_READELF) --debug-dump=gdb_index $< > $@
+
+endif HAVE_PUBNAMES
+
+# End-to-end incremental linking tests.
+# Incremental linking is currently supported only on the x86_64 target.
+
+if DEFAULT_TARGET_X86_64
+
+two_file_test_1_v1_ndebug.o: two_file_test_1_v1.cc
+ $(CXXCOMPILE) -O0 -g0 -c -o $@ $<
+two_file_test_1_ndebug.o: two_file_test_1.cc
+ $(CXXCOMPILE) -O0 -g0 -c -o $@ $<
+two_file_test_1b_ndebug.o: two_file_test_1b.cc
+ $(CXXCOMPILE) -O0 -g0 -c -o $@ $<
+two_file_test_2_ndebug.o: two_file_test_2.cc
+ $(CXXCOMPILE) -O0 -g0 -c -o $@ $<
+two_file_test_main_ndebug.o: two_file_test_main.cc
+ $(CXXCOMPILE) -O0 -g0 -c -o $@ $<
+
+check_PROGRAMS += incremental_test_2
+MOSTLYCLEANFILES += two_file_test_tmp_2.o
+incremental_test_2: two_file_test_1_v1_ndebug.o two_file_test_1_ndebug.o two_file_test_1b_ndebug.o \
+ two_file_test_2_ndebug.o two_file_test_main_ndebug.o gcctestdir/ld
+ cp -f two_file_test_1_v1_ndebug.o two_file_test_tmp_2.o
+ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_tmp_2.o two_file_test_1b_ndebug.o two_file_test_2_ndebug.o two_file_test_main_ndebug.o
+ @sleep 1
+ cp -f two_file_test_1_ndebug.o two_file_test_tmp_2.o
+ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_tmp_2.o two_file_test_1b_ndebug.o two_file_test_2_ndebug.o two_file_test_main_ndebug.o
+
+check_PROGRAMS += incremental_test_3
+MOSTLYCLEANFILES += two_file_test_tmp_3.o
+incremental_test_3: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
+ two_file_test_2.o two_file_test_main.o gcctestdir/ld
+ cp -f two_file_test_1b_v1.o two_file_test_tmp_3.o
+ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
+ @sleep 1
+ cp -f two_file_test_1b.o two_file_test_tmp_3.o
+ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
+
+check_PROGRAMS += incremental_test_4
+MOSTLYCLEANFILES += incremental_test_4.base two_file_test_tmp_4.o
+incremental_test_4: two_file_test_1.o two_file_test_1b.o two_file_test_2_v1.o \
+ two_file_test_2.o two_file_test_main.o gcctestdir/ld
+ cp -f two_file_test_2_v1.o two_file_test_tmp_4.o
+ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
+ mv -f incremental_test_4 incremental_test_4.base
+ @sleep 1
+ cp -f two_file_test_2.o two_file_test_tmp_4.o
+ $(CXXLINK) -Wl,--incremental-update,--incremental-base=incremental_test_4.base -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
+
+check_PROGRAMS += incremental_test_5
+MOSTLYCLEANFILES += two_file_test_5.a
+incremental_test_5: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
+ two_file_test_2.o two_file_test_main.o gcctestdir/ld
+ cp -f two_file_test_1b_v1.o two_file_test_tmp_5.o
+ $(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
+ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
+ @sleep 1
+ cp -f two_file_test_1b.o two_file_test_tmp_5.o
+ $(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
+ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
+
+# Test the --incremental-unchanged flag with an archive library.
+# The second link should not update the library.
+check_PROGRAMS += incremental_test_6
+MOSTLYCLEANFILES += two_file_test_6.a
+incremental_test_6: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
+ two_file_test_2.o two_file_test_main.o gcctestdir/ld
+ cp -f two_file_test_1b.o two_file_test_tmp_6.o
+ $(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
+ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
+ @sleep 1
+ cp -f two_file_test_1b_v1.o two_file_test_tmp_6.o
+ $(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
+ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_main.o -Wl,--incremental-unchanged two_file_test_6.a -Wl,--incremental-unknown
+
+check_PROGRAMS += incremental_copy_test
+incremental_copy_test: copy_test_v1.o copy_test.o copy_test_1.so copy_test_2.so
+ cp -f copy_test_v1.o copy_test_tmp.o
+ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ -Wl,-R,. -Wl,--no-as-needed copy_test_tmp.o copy_test_1.so copy_test_2.so
+ @sleep 1
+ cp -f copy_test.o copy_test_tmp.o
+ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ -Wl,-R,. -Wl,--no-as-needed copy_test_tmp.o copy_test_1.so copy_test_2.so
+
+check_PROGRAMS += incremental_common_test_1
+incremental_common_test_1: common_test_1_v1.o common_test_1_v2.o gcctestdir/ld
+ cp -f common_test_1_v1.o common_test_1_tmp.o
+ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ common_test_1_tmp.o
+ @sleep 1
+ cp -f common_test_1_v2.o common_test_1_tmp.o
+ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ common_test_1_tmp.o
+
+check_PROGRAMS += incremental_comdat_test_1
+incremental_comdat_test_1: incr_comdat_test_1.o incr_comdat_test_2_v1.o incr_comdat_test_2_v2.o incr_comdat_test_2_v3.o gcctestdir/ld
+ cp -f incr_comdat_test_2_v1.o incr_comdat_test_1_tmp.o
+ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ incr_comdat_test_1.o incr_comdat_test_1_tmp.o
+ @sleep 1
+ cp -f incr_comdat_test_2_v2.o incr_comdat_test_1_tmp.o
+ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ incr_comdat_test_1.o incr_comdat_test_1_tmp.o
+ @sleep 1
+ cp -f incr_comdat_test_2_v3.o incr_comdat_test_1_tmp.o
+ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ incr_comdat_test_1.o incr_comdat_test_1_tmp.o
+
+endif DEFAULT_TARGET_X86_64
+
+endif GCC
+endif NATIVE_LINKER
+
+# These tests work with native and cross linkers.
+
+if NATIVE_OR_CROSS_LINKER
+
+# Test script section order.
+check_SCRIPTS += script_test_10.sh
+check_DATA += script_test_10.stdout
+MOSTLYCLEANFILES += script_test_10
+script_test_10.o: script_test_10.s
+ $(TEST_AS) -o $@ $<
+script_test_10: $(srcdir)/script_test_10.t script_test_10.o gcctestdir/ld
+ gcctestdir/ld -o $@ script_test_10.o -T $(srcdir)/script_test_10.t
+script_test_10.stdout: script_test_10
+ $(TEST_READELF) -SW script_test_10 > $@
+
+# These tests work with cross linkers only.
+
+if DEFAULT_TARGET_I386
+
+check_SCRIPTS += split_i386.sh
+check_DATA += split_i386_1.stdout split_i386_2.stdout \
+ split_i386_3.stdout split_i386_4.stdout split_i386_r.stdout
+SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+split_i386_1.o: split_i386_1.s
+ $(TEST_AS) -o $@ $<
+split_i386_2.o: split_i386_2.s
+ $(TEST_AS) -o $@ $<
+split_i386_3.o: split_i386_3.s
+ $(TEST_AS) -o $@ $<
+split_i386_4.o: split_i386_4.s
+ $(TEST_AS) -o $@ $<
+split_i386_n.o: split_i386_n.s
+ $(TEST_AS) -o $@ $<
+split_i386_1: split_i386_1.o split_i386_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_1.o split_i386_n.o
+split_i386_1.stdout: split_i386_1
+ $(TEST_OBJDUMP) -d $< > $@
+split_i386_2: split_i386_2.o split_i386_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_2.o split_i386_n.o
+split_i386_2.stdout: split_i386_2
+ $(TEST_OBJDUMP) -d $< > $@
+split_i386_3.stdout: split_i386_3.o split_i386_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o split_i386_3 split_i386_3.o split_i386_n.o > $@ 2>&1 || exit 0
+split_i386_4: split_i386_4.o split_i386_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_4.o split_i386_n.o
+split_i386_4.stdout: split_i386_4
+ $(TEST_OBJDUMP) -d $< > $@
+split_i386_r.stdout: split_i386_1.o split_i386_n.o ../ld-new
+ ../ld-new -r split_i386_1.o split_i386_n.o -o split_i386_r > $@ 2>&1 || exit 0
+MOSTLYCLEANFILES += split_i386_1 split_i386_2 split_i386_3 \
+ split_i386_4 split_i386_r
+
+endif DEFAULT_TARGET_I386
+
+if DEFAULT_TARGET_X86_64
+
+check_SCRIPTS += split_x86_64.sh
+check_DATA += split_x86_64_1.stdout split_x86_64_2.stdout \
+ split_x86_64_3.stdout split_x86_64_4.stdout split_x86_64_r.stdout
+SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+split_x86_64_1.o: split_x86_64_1.s
+ $(TEST_AS) -o $@ $<
+split_x86_64_2.o: split_x86_64_2.s
+ $(TEST_AS) -o $@ $<
+split_x86_64_3.o: split_x86_64_3.s
+ $(TEST_AS) -o $@ $<
+split_x86_64_4.o: split_x86_64_4.s
+ $(TEST_AS) -o $@ $<
+split_x86_64_n.o: split_x86_64_n.s
+ $(TEST_AS) -o $@ $<
+split_x86_64_1: split_x86_64_1.o split_x86_64_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_1.o split_x86_64_n.o
+split_x86_64_1.stdout: split_x86_64_1
+ $(TEST_OBJDUMP) -d $< > $@
+split_x86_64_2: split_x86_64_2.o split_x86_64_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_2.o split_x86_64_n.o
+split_x86_64_2.stdout: split_x86_64_2
+ $(TEST_OBJDUMP) -d $< > $@
+split_x86_64_3.stdout: split_x86_64_3.o split_x86_64_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o split_x86_64_3 split_x86_64_3.o split_x86_64_n.o > $@ 2>&1 || exit 0
+split_x86_64_4: split_x86_64_4.o split_x86_64_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_4.o split_x86_64_n.o
+split_x86_64_4.stdout: split_x86_64_4
+ $(TEST_OBJDUMP) -d $< > $@
+split_x86_64_r.stdout: split_x86_64_1.o split_x86_64_n.o ../ld-new
+ ../ld-new -r split_x86_64_1.o split_x86_64_n.o -o split_x86_64_r > $@ 2>&1 || exit 0
+MOSTLYCLEANFILES += split_x86_64_1 split_x86_64_2 split_x86_64_3 \
+ split_x86_64_4 split_x86_64_r
+
+endif DEFAULT_TARGET_X86_64
+
+if DEFAULT_TARGET_ARM
+
+check_SCRIPTS += arm_abs_global.sh
+check_DATA += arm_abs_global.stdout
+arm_abs_lib.o: arm_abs_lib.s
+ $(TEST_AS) -march=armv7-a -o $@ $<
+libarm_abs.so: arm_abs_lib.o ../ld-new
+ ../ld-new -shared -o $@ arm_abs_lib.o
+arm_abs_global.o: arm_abs_global.s
+ $(TEST_AS) -march=armv7-a -o $@ $<
+arm_abs_global: arm_abs_global.o libarm_abs.so ../ld-new
+ ../ld-new -o $@ arm_abs_global.o -L. -larm_abs
+arm_abs_global.stdout: arm_abs_global
+ $(TEST_READELF) -r $< > $@
+
+MOSTLYCLEANFILES += arm_abs_global
+
+check_SCRIPTS += arm_branch_in_range.sh arm_branch_out_of_range.sh
+check_DATA += 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 thumb2_bl_out_of_range.stdout \
+ thumb_blx_in_range.stdout thumb_blx_out_of_range.stdout \
+ thumb2_blx_in_range.stdout thumb2_blx_out_of_range.stdout \
+ thumb_bl_out_of_range_local.stdout arm_thm_jump11.stdout \
+ arm_thm_jump8.stdout
+
+arm_bl_in_range.stdout: arm_bl_in_range
+ $(TEST_OBJDUMP) -D $< > $@
+
+arm_bl_in_range: arm_bl_in_range.o ../ld-new
+ ../ld-new -T $(srcdir)/arm_branch_range.t -o $@ $<
+
+arm_bl_in_range.o: arm_bl_in_range.s
+ $(TEST_AS) -o $@ $<
+
+arm_bl_out_of_range.stdout: arm_bl_out_of_range
+ $(TEST_OBJDUMP) -S $< > $@
+
+arm_bl_out_of_range: arm_bl_out_of_range.o ../ld-new
+ ../ld-new -T $(srcdir)/arm_branch_range.t -o $@ $<
+
+arm_bl_out_of_range.o: arm_bl_out_of_range.s
+ $(TEST_AS) -o $@ $<
+
+thumb_bl_in_range.stdout: thumb_bl_in_range
+ $(TEST_OBJDUMP) -D $< > $@
+
+thumb_bl_in_range: thumb_bl_in_range.o ../ld-new
+ ../ld-new --no-fix-arm1176 -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+thumb_bl_in_range.o: thumb_bl_in_range.s
+ $(TEST_AS) -o $@ -march=armv5te $<
+
+thumb_bl_out_of_range.stdout: thumb_bl_out_of_range
+ $(TEST_OBJDUMP) -D $< > $@
+
+thumb_bl_out_of_range: thumb_bl_out_of_range.o ../ld-new
+ ../ld-new --no-fix-arm1176 -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+thumb_bl_out_of_range.o: thumb_bl_out_of_range.s
+ $(TEST_AS) -o $@ -march=armv5te $<
+
+thumb2_bl_in_range.stdout: thumb2_bl_in_range
+ $(TEST_OBJDUMP) -D $< > $@
+
+thumb2_bl_in_range: thumb2_bl_in_range.o ../ld-new
+ ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
+
+thumb2_bl_in_range.o: thumb_bl_in_range.s
+ $(TEST_AS) -o $@ -march=armv7-a $<
+
+thumb2_bl_out_of_range.stdout: thumb2_bl_out_of_range
+ $(TEST_OBJDUMP) -D $< > $@
+
+thumb2_bl_out_of_range: thumb2_bl_out_of_range.o ../ld-new
+ ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
+
+thumb2_bl_out_of_range.o: thumb_bl_out_of_range.s
+ $(TEST_AS) -o $@ -march=armv7-a $<
+
+thumb_blx_in_range.stdout: thumb_blx_in_range
+ $(TEST_OBJDUMP) -D $< > $@
+
+thumb_blx_in_range: thumb_blx_in_range.o ../ld-new
+ ../ld-new --no-fix-arm1176 -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+thumb_blx_in_range.o: thumb_blx_in_range.s
+ $(TEST_AS) -o $@ -march=armv5te $<
+
+thumb_blx_out_of_range.stdout: thumb_blx_out_of_range
+ $(TEST_OBJDUMP) -D $< > $@
+
+thumb_blx_out_of_range: thumb_blx_out_of_range.o ../ld-new
+ ../ld-new --no-fix-arm1176 -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+thumb_blx_out_of_range.o: thumb_blx_out_of_range.s
+ $(TEST_AS) -o $@ -march=armv5te $<
+
+thumb2_blx_in_range.stdout: thumb2_blx_in_range
+ $(TEST_OBJDUMP) -D $< > $@
+
+thumb2_blx_in_range: thumb2_blx_in_range.o ../ld-new
+ ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
+
+thumb2_blx_in_range.o: thumb_blx_in_range.s
+ $(TEST_AS) -o $@ -march=armv7-a $<
+
+thumb2_blx_out_of_range.stdout: thumb2_blx_out_of_range
+ $(TEST_OBJDUMP) -D $< > $@
+
+thumb2_blx_out_of_range: thumb2_blx_out_of_range.o ../ld-new
+ ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
+
+thumb2_blx_out_of_range.o: thumb_blx_out_of_range.s
+ $(TEST_AS) -o $@ -march=armv7-a $<
+
+thumb_bl_out_of_range_local.stdout: thumb_bl_out_of_range_local
+ $(TEST_OBJDUMP) -D $< > $@
+
+thumb_bl_out_of_range_local: thumb_bl_out_of_range_local.o ../ld-new
+ ../ld-new --no-fix-arm1176 -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+thumb_bl_out_of_range_local.o: thumb_bl_out_of_range_local.s
+ $(TEST_AS) -o $@ -march=armv5te $<
+
+arm_thm_jump11.stdout: arm_thm_jump11
+ $(TEST_OBJDUMP) -D $< > $@
+
+arm_thm_jump11: arm_thm_jump11.o ../ld-new
+ ../ld-new -T $(srcdir)/arm_thm_jump11.t -o $@ $<
+
+arm_thm_jump11.o: arm_thm_jump11.s
+ $(TEST_AS) -o $@ $<
+
+arm_thm_jump8.stdout: arm_thm_jump8
+ $(TEST_OBJDUMP) -D $< > $@
+
+arm_thm_jump8: arm_thm_jump8.o ../ld-new
+ ../ld-new -T $(srcdir)/arm_thm_jump8.t -o $@ $<
+
+arm_thm_jump8.o: arm_thm_jump8.s
+ $(TEST_AS) -o $@ $<
+
+MOSTLYCLEANFILES += arm_bl_in_range arm_bl_out_of_range thumb_bl_in_range \
+ thumb_bl_out_of_range thumb2_bl_in_range thumb2_bl_out_of_range \
+ thumb_blx_in_range thumb_blx_out_of_range thumb2_blx_in_range \
+ thumb2_blx_out_of_range thumb_bl_out_of_range_local arm_thm_jump11 \
+ arm_thm_jump8
+
+check_SCRIPTS += arm_fix_v4bx.sh
+check_DATA += arm_fix_v4bx.stdout arm_fix_v4bx_interworking.stdout \
+ arm_no_fix_v4bx.stdout
+
+arm_fix_v4bx.stdout: arm_fix_v4bx
+ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_fix_v4bx: arm_fix_v4bx.o ../ld-new
+ ../ld-new --no-fix-arm1176 --fix-v4bx -o $@ $<
+
+arm_fix_v4bx.o: arm_fix_v4bx.s
+ $(TEST_AS) -o $@ $<
+
+arm_fix_v4bx_interworking.stdout: arm_fix_v4bx_interworking
+ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_fix_v4bx_interworking: arm_fix_v4bx.o ../ld-new
+ ../ld-new --no-fix-arm1176 --fix-v4bx-interworking -o $@ $<
+
+arm_no_fix_v4bx.stdout: arm_no_fix_v4bx
+ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_no_fix_v4bx: arm_fix_v4bx.o ../ld-new
+ ../ld-new --no-fix-arm1176 -o $@ $<
+
+MOSTLYCLEANFILES += arm_fix_v4bx arm_fix_v4bx_interworking arm_no_fix_v4bx
+
+check_SCRIPTS += arm_attr_merge.sh
+check_DATA += arm_attr_merge_6.stdout arm_attr_merge_6r.stdout \
+ arm_attr_merge_7.stdout
+
+arm_attr_merge_6.stdout: arm_attr_merge_6
+ $(TEST_READELF) -A $< > $@
+
+arm_attr_merge_6: arm_attr_merge_6a.o arm_attr_merge_6b.o
+ ../ld-new -o $@ arm_attr_merge_6a.o arm_attr_merge_6b.o
+
+arm_attr_merge_6a.o: arm_attr_merge_6a.s
+ $(TEST_AS) -o $@ $<
+
+arm_attr_merge_6b.o: arm_attr_merge_6b.s
+ $(TEST_AS) -o $@ $<
+
+arm_attr_merge_6r.stdout: arm_attr_merge_6r
+ $(TEST_READELF) -A $< > $@
+
+arm_attr_merge_6r: arm_attr_merge_6b.o arm_attr_merge_6a.o
+ ../ld-new -o $@ arm_attr_merge_6b.o arm_attr_merge_6a.o
+
+arm_attr_merge_7.stdout: arm_attr_merge_7
+ $(TEST_READELF) -A $< > $@
+
+arm_attr_merge_7: arm_attr_merge_7a.o arm_attr_merge_7b.o
+ ../ld-new -o $@ arm_attr_merge_7a.o arm_attr_merge_7b.o
+
+arm_attr_merge_7a.o: arm_attr_merge_7a.s
+ $(TEST_AS) -o $@ $<
+
+arm_attr_merge_7b.o: arm_attr_merge_7b.s
+ $(TEST_AS) -o $@ $<
+
+MOSTLYCLEANFILES += arm_attr_merge_6 arm_attr_merge_6r arm_attr_merge_7
+
+# ARM1176 workaround test.
+check_SCRIPTS += arm_fix_1176.sh
+check_DATA += arm_fix_1176_default_v6z.stdout arm_fix_1176_on_v6z.stdout \
+ arm_fix_1176_off_v6z.stdout arm_fix_1176_default_v5te.stdout \
+ arm_fix_1176_default_v7a.stdout arm_fix_1176_default_1156t2f_s.stdout
+
+arm_fix_1176_default_v6z.stdout: arm_fix_1176_default_v6z
+ $(TEST_OBJDUMP) -D -j.foo $< > $@
+
+arm_fix_1176_default_v6z: arm_fix_1176_default_v6z.o ../ld-new
+ ../ld-new --section-start=.foo=0x2001014 -o $@ $<
+
+arm_fix_1176_default_v6z.o: arm_fix_1176.s
+ $(TEST_AS) -march=armv6z -o $@ $<
+
+arm_fix_1176_on_v6z.stdout: arm_fix_1176_on_v6z
+ $(TEST_OBJDUMP) -D -j.foo $< > $@
+
+arm_fix_1176_on_v6z: arm_fix_1176_on_v6z.o ../ld-new
+ ../ld-new --section-start=.foo=0x2001014 --fix-arm1176 -o $@ $<
+
+arm_fix_1176_on_v6z.o: arm_fix_1176.s
+ $(TEST_AS) -march=armv6z -o $@ $<
+
+arm_fix_1176_off_v6z.stdout: arm_fix_1176_off_v6z
+ $(TEST_OBJDUMP) -D -j.foo $< > $@
+
+arm_fix_1176_off_v6z: arm_fix_1176_off_v6z.o ../ld-new
+ ../ld-new --section-start=.foo=0x2001014 --no-fix-arm1176 -o $@ $<
+
+arm_fix_1176_off_v6z.o: arm_fix_1176.s
+ $(TEST_AS) -march=armv6z -o $@ $<
+
+arm_fix_1176_default_v5te.stdout: arm_fix_1176_default_v5te
+ $(TEST_OBJDUMP) -D -j.foo $< > $@
+
+arm_fix_1176_default_v5te: arm_fix_1176_default_v5te.o ../ld-new
+ ../ld-new --section-start=.foo=0x2001014 -o $@ $<
+
+arm_fix_1176_default_v5te.o: arm_fix_1176.s
+ $(TEST_AS) -march=armv5te -o $@ $<
+
+arm_fix_1176_default_v7a.stdout: arm_fix_1176_default_v7a
+ $(TEST_OBJDUMP) -D -j.foo $< > $@
+
+arm_fix_1176_default_v7a: arm_fix_1176_default_v7a.o ../ld-new
+ ../ld-new --section-start=.foo=0x2001014 -o $@ $<
+
+arm_fix_1176_default_v7a.o: arm_fix_1176.s
+ $(TEST_AS) -march=armv7-a -o $@ $<
+
+arm_fix_1176_default_1156t2f_s.stdout: arm_fix_1176_default_1156t2f_s
+ $(TEST_OBJDUMP) -D -j.foo $< > $@
+
+arm_fix_1176_default_1156t2f_s: arm_fix_1176_default_1156t2f_s.o ../ld-new
+ ../ld-new --section-start=.foo=0x2001014 -o $@ $<
+
+arm_fix_1176_default_1156t2f_s.o: arm_fix_1176.s
+ $(TEST_AS) -mcpu=arm1156t2f-s -o $@ $<
+
+MOSTLYCLEANFILES += arm_fix_1176_default_v6z arm_fix_1176_on_v6z arm_fix_1176_off_v6z \
+ arm_fix_1176_default_v5te arm_fix_1176_default_v7a arm_fix_1176_default_1156t2f_s
+
+# Cortex-A8 workaround test.
+
+check_SCRIPTS += arm_cortex_a8.sh
+check_DATA += arm_cortex_a8_b_cond.stdout arm_cortex_a8_b.stdout \
+ arm_cortex_a8_bl.stdout arm_cortex_a8_blx.stdout \
+ arm_cortex_a8_local.stdout arm_cortex_a8_local_reloc.stdout
+
+arm_cortex_a8_b_cond.stdout: arm_cortex_a8_b_cond
+ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_cortex_a8_b_cond: arm_cortex_a8_b_cond.o ../ld-new
+ ../ld-new -o $@ $<
+
+arm_cortex_a8_b_cond.o: arm_cortex_a8_b_cond.s
+ $(TEST_AS) -o $@ $<
+
+arm_cortex_a8_b.stdout: arm_cortex_a8_b
+ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_cortex_a8_b: arm_cortex_a8_b.o ../ld-new
+ ../ld-new --fix-cortex-a8 -o $@ $<
+
+arm_cortex_a8_b.o: arm_cortex_a8_b.s
+ $(TEST_AS) -o $@ $<
+
+arm_cortex_a8_bl.stdout: arm_cortex_a8_bl
+ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_cortex_a8_bl: arm_cortex_a8_bl.o ../ld-new
+ ../ld-new -o $@ $<
+
+arm_cortex_a8_bl.o: arm_cortex_a8_bl.s
+ $(TEST_AS) -o $@ $<
+
+arm_cortex_a8_blx.stdout: arm_cortex_a8_blx
+ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_cortex_a8_blx: arm_cortex_a8_blx.o ../ld-new
+ ../ld-new -o $@ $<
+
+arm_cortex_a8_blx.o: arm_cortex_a8_blx.s
+ $(TEST_AS) -o $@ $<
+
+arm_cortex_a8_local.stdout: arm_cortex_a8_local
+ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_cortex_a8_local: arm_cortex_a8_local.o ../ld-new
+ ../ld-new -o $@ $<
+
+arm_cortex_a8_local.o: arm_cortex_a8_local.s
+ $(TEST_AS) -o $@ $<
+
+arm_cortex_a8_local_reloc.stdout: arm_cortex_a8_local_reloc
+ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_cortex_a8_local_reloc: arm_cortex_a8_local_reloc.o ../ld-new
+ ../ld-new -o $@ $<
+
+arm_cortex_a8_local_reloc.o: arm_cortex_a8_local_reloc.s
+ $(TEST_AS) -o $@ $<
+
+MOSTLYCLEANFILES += arm_cortex_a8_b_cond arm_cortex_a8_b arm_cortex_a8_bl \
+ arm_cortex_a8_blx arm_cortex_a8_local arm_cortex_a8_local_reloc
+
+check_SCRIPTS += arm_exidx_test.sh
+check_DATA += arm_exidx_test.stdout
+
+arm_exidx_test.stdout: arm_exidx_test.so
+ $(TEST_READELF) -Sr $< > $@
+
+arm_exidx_test.so: arm_exidx_test.o ../ld-new
+ ../ld-new -shared -o $@ $<
+
+arm_exidx_test.o: arm_exidx_test.s
+ $(TEST_AS) -o $@ $<
+
+check_SCRIPTS += pr12826.sh
+check_DATA += pr12826.stdout
+
+pr12826.stdout: pr12826.so
+ $(TEST_READELF) -A $< > $@
+
+pr12826.so: pr12826_1.o pr12826_2.o ../ld-new
+ ../ld-new -shared -o $@ $<
+
+pr12826_1.o: pr12826_1.s
+ $(TEST_AS) -o $@ $<
+
+pr12826_2.o: pr12826_2.s
+ $(TEST_AS) -o $@ $<
+
+check_SCRIPTS += arm_unaligned_reloc.sh
+check_DATA += arm_unaligned_reloc.stdout arm_unaligned_reloc_r.stdout
+
+arm_unaligned_reloc.stdout: arm_unaligned_reloc
+ $(TEST_OBJDUMP) -D $< > $@
+
+arm_unaligned_reloc_r.stdout: arm_unaligned_reloc_r
+ $(TEST_OBJDUMP) -Dr $< > $@
+
+arm_unaligned_reloc: arm_unaligned_reloc.o ../ld-new
+ ../ld-new -o $@ $<
+
+arm_unaligned_reloc_r: arm_unaligned_reloc.o ../ld-new
+ ../ld-new -r -o $@ $<
+
+arm_unaligned_reloc.o: arm_unaligned_reloc.s
+ $(TEST_AS) -o $@ $<
+
+MOSTLYCLEANFILES += arm_unaligned_reloc arm_unaligned_reloc_r
+
+# Check ARM to ARM farcall veneers
+
+check_SCRIPTS += arm_farcall_arm_arm.sh
+check_DATA += arm_farcall_arm_arm.stdout
+
+arm_farcall_arm_arm.stdout: arm_farcall_arm_arm
+ $(TEST_OBJDUMP) -d $< > $@
+
+arm_farcall_arm_arm: arm_farcall_arm_arm.o ../ld-new
+ ../ld-new --no-fix-arm1176 --section-start .text=0x1000 --section-start .foo=0x2001020 -o $@ $<
+
+arm_farcall_arm_arm.o: arm_farcall_arm_arm.s
+ $(TEST_AS) -o $@ $<
+
+MOSTLYCLEANFILES += arm_farcall_arm_arm
+
+# Check ARM to Thumb farcall veneers
+
+check_SCRIPTS += arm_farcall_arm_thumb.sh
+check_DATA += arm_farcall_arm_thumb.stdout arm_farcall_arm_thumb_5t.stdout
+
+arm_farcall_arm_thumb.stdout: arm_farcall_arm_thumb
+ $(TEST_OBJDUMP) -D $< > $@
+
+arm_farcall_arm_thumb: arm_farcall_arm_thumb.o ../ld-new
+ ../ld-new --section-start .text=0x1000 --section-start .foo=0x2001014 -o $@ $<
+
+arm_farcall_arm_thumb.o: arm_farcall_arm_thumb.s
+ $(TEST_AS) -o $@ $<
+
+arm_farcall_arm_thumb_5t.stdout: arm_farcall_arm_thumb_5t
+ $(TEST_OBJDUMP) -D $< > $@
+
+arm_farcall_arm_thumb_5t: arm_farcall_arm_thumb_5t.o ../ld-new
+ ../ld-new --no-fix-arm1176 --section-start .text=0x1000 --section-start .foo=0x2001014 -o $@ $<
+
+arm_farcall_arm_thumb_5t.o: arm_farcall_arm_thumb.s
+ $(TEST_AS) -march=armv5t -o $@ $<
+
+MOSTLYCLEANFILES += arm_farcall_arm_thumb arm_farcall_arm_thumb_5t
+
+# Check Thumb to Thumb farcall veneers
+
+check_SCRIPTS += arm_farcall_thumb_thumb.sh
+check_DATA += arm_farcall_thumb_thumb.stdout \
+ arm_farcall_thumb_thumb_5t.stdout \
+ arm_farcall_thumb_thumb_7m.stdout \
+ arm_farcall_thumb_thumb_6m.stdout
+
+arm_farcall_thumb_thumb.stdout: arm_farcall_thumb_thumb
+ $(TEST_OBJDUMP) -D $< > $@
+
+arm_farcall_thumb_thumb: arm_farcall_thumb_thumb.o ../ld-new
+ ../ld-new --section-start .text=0x1000 --section-start .foo=0x2001014 -o $@ $<
+
+arm_farcall_thumb_thumb.o: arm_farcall_thumb_thumb.s
+ $(TEST_AS) -march=armv4t -o $@ $<
+
+arm_farcall_thumb_thumb_5t.stdout: arm_farcall_thumb_thumb_5t
+ $(TEST_OBJDUMP) -D $< > $@
+
+arm_farcall_thumb_thumb_5t: arm_farcall_thumb_thumb_5t.o ../ld-new
+ ../ld-new --no-fix-arm1176 --section-start .text=0x1000 --section-start .foo=0x2001014 -o $@ $<
+
+arm_farcall_thumb_thumb_5t.o: arm_farcall_thumb_thumb.s
+ $(TEST_AS) -march=armv5t -o $@ $<
+
+arm_farcall_thumb_thumb_7m.stdout: arm_farcall_thumb_thumb_7m
+ $(TEST_OBJDUMP) -D $< > $@
+
+arm_farcall_thumb_thumb_7m: arm_farcall_thumb_thumb_7m.o ../ld-new
+ ../ld-new --section-start .text=0x1000 --section-start .foo=0x2001014 -o $@ $<
+
+arm_farcall_thumb_thumb_7m.o: arm_farcall_thumb_thumb.s
+ $(TEST_AS) -march=armv7-m -o $@ $<
+
+arm_farcall_thumb_thumb_6m.stdout: arm_farcall_thumb_thumb_6m
+ $(TEST_OBJDUMP) -D $< > $@
+
+arm_farcall_thumb_thumb_6m: arm_farcall_thumb_thumb_6m.o ../ld-new
+ ../ld-new --section-start .text=0x1000 --section-start .foo=0x2001014 -o $@ $<
+
+arm_farcall_thumb_thumb_6m.o: arm_farcall_thumb_thumb.s
+ $(TEST_AS) -march=armv6-m -o $@ $<
+
+MOSTLYCLEANFILES += arm_farcall_thumb_thumb arm_farcall_thumb_thumb_5t \
+ arm_farcall_thumb_thumb_7m arm_farcall_thumb_thumb_6m
+
+# Check Thumb to ARM farcall veneers
+
+check_SCRIPTS += arm_farcall_thumb_arm.sh
+check_DATA += arm_farcall_thumb_arm.stdout \
+ arm_farcall_thumb_arm_5t.stdout
+
+arm_farcall_thumb_arm.stdout: arm_farcall_thumb_arm
+ $(TEST_OBJDUMP) -D $< > $@
+
+arm_farcall_thumb_arm: arm_farcall_thumb_arm.o ../ld-new
+ ../ld-new --section-start .text=0x1c01010 --section-start .foo=0x2001014 -o $@ $<
+
+arm_farcall_thumb_arm.o: arm_farcall_thumb_arm.s
+ $(TEST_AS) -o $@ $<
+
+arm_farcall_thumb_arm_5t.stdout: arm_farcall_thumb_arm_5t
+ $(TEST_OBJDUMP) -D $< > $@
+
+arm_farcall_thumb_arm_5t: arm_farcall_thumb_arm_5t.o ../ld-new
+ ../ld-new --no-fix-arm1176 --section-start .text=0x1c01010 --section-start .foo=0x2001014 -o $@ $<
+
+arm_farcall_thumb_arm_5t.o: arm_farcall_thumb_arm.s
+ $(TEST_AS) -march=armv5t -o $@ $<
+
+MOSTLYCLEANFILES += arm_farcall_thumb_arm arm_farcall_thumb_arm_5t
+
+endif DEFAULT_TARGET_ARM
+
+endif NATIVE_OR_CROSS_LINKER
+
+# Tests for the dwp tool.
+# We don't want to rely yet on GCC support for -gsplit-dwarf,
+# so we use (for now) test cases in x86 assembly language,
+# compiled from the dwp_test_*.cc sources.
+
+if DEFAULT_TARGET_X86_64
+
+dwp_test_main.o: dwp_test_main.s
+ $(TEST_AS) -o $@ $<
+dwp_test_1.o: dwp_test_1.s
+ $(TEST_AS) -o $@ $<
+dwp_test_1b.o: dwp_test_1b.s
+ $(TEST_AS) -o $@ $<
+dwp_test_2.o: dwp_test_2.s
+ $(TEST_AS) -o $@ $<
+
+dwp_test_main.dwo: dwp_test_main.o
+ $(TEST_OBJCOPY) --extract-dwo $< $@
+dwp_test_1.dwo: dwp_test_1.o
+ $(TEST_OBJCOPY) --extract-dwo $< $@
+dwp_test_1b.dwo: dwp_test_1b.o
+ $(TEST_OBJCOPY) --extract-dwo $< $@
+dwp_test_2.dwo: dwp_test_2.o
+ $(TEST_OBJCOPY) --extract-dwo $< $@
+
+MOSTLYCLEANFILES += *.dwo *.dwp
+check_SCRIPTS += dwp_test_1.sh
+check_DATA += dwp_test_1.stdout
+dwp_test_1.stdout: dwp_test_1.dwp
+ $(TEST_READELF) -wi $< > $@
+dwp_test_1.dwp: ../dwp dwp_test_main.dwo dwp_test_1.dwo dwp_test_1b.dwo dwp_test_2.dwo
+ ../dwp -o $@ dwp_test_main.dwo dwp_test_1.dwo dwp_test_1b.dwo dwp_test_2.dwo
+
+check_SCRIPTS += dwp_test_2.sh
+check_DATA += dwp_test_2.stdout
+dwp_test_2.stdout: dwp_test_2.dwp
+ $(TEST_READELF) -wi $< > $@
+dwp_test_2.dwp: ../dwp dwp_test_2a.dwp dwp_test_2b.dwp
+ ../dwp -o $@ dwp_test_2a.dwp dwp_test_2b.dwp
+dwp_test_2a.dwp: ../dwp dwp_test_main.dwo dwp_test_1.dwo
+ ../dwp -o $@ dwp_test_main.dwo dwp_test_1.dwo
+dwp_test_2b.dwp: ../dwp dwp_test_1b.dwo dwp_test_2.dwo
+ ../dwp -o $@ dwp_test_1b.dwo dwp_test_2.dwo
+
+endif DEFAULT_TARGET_X86_64
diff --git a/binutils-2.25/gold/testsuite/Makefile.in b/binutils-2.25/gold/testsuite/Makefile.in
new file mode 100644
index 00000000..07bb534a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/Makefile.in
@@ -0,0 +1,5892 @@
+# 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@
+
+# Process this file with automake to generate Makefile.in
+
+# As far as I can tell automake testing support assumes that the build
+# system and the host system are the same. So these tests will not
+# work when building with a cross-compiler.
+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@
+check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+ $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
+ $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \
+ $(am__EXEEXT_10) $(am__EXEEXT_11) $(am__EXEEXT_12) \
+ $(am__EXEEXT_13) $(am__EXEEXT_14) $(am__EXEEXT_15) \
+ $(am__EXEEXT_16) $(am__EXEEXT_17) $(am__EXEEXT_18) \
+ $(am__EXEEXT_19) $(am__EXEEXT_20) $(am__EXEEXT_21) \
+ $(am__EXEEXT_22) $(am__EXEEXT_23) $(am__EXEEXT_24) \
+ $(am__EXEEXT_25) $(am__EXEEXT_26) $(am__EXEEXT_27) \
+ $(am__EXEEXT_28) $(am__EXEEXT_29) $(am__EXEEXT_30) \
+ $(am__EXEEXT_31) $(am__EXEEXT_32) $(am__EXEEXT_33) \
+ $(am__EXEEXT_34) $(am__EXEEXT_35) $(am__EXEEXT_36) \
+ $(am__EXEEXT_37) $(am__EXEEXT_38) $(am__EXEEXT_39)
+@NATIVE_OR_CROSS_LINKER_TRUE@am__append_1 = object_unittest \
+@NATIVE_OR_CROSS_LINKER_TRUE@ binary_unittest leb128_unittest
+
+# This test fails on targets not using .ctors and .dtors sections (e.g. ARM
+# EABI). Given that gcc is moving towards using .init_array in all cases,
+# this test is commented out. A better fix would be checking whether gcc
+# uses .ctors or .init_array sections in configure.
+
+# check_PROGRAMS += initpri3b
+# initpri3b_SOURCES = initpri3.c
+# initpri3b_DEPENDENCIES = gcctestdir/ld
+# initpri3b_LDFLAGS = -Bgcctestdir/ -Wl,--no-ctors-in-init-array
+# initpri3b_LDADD =
+
+# Test --detect-odr-violations
+
+# Test error message when a vtable is undefined.
+
+# Similar to --detect-odr-violations: check for undefined symbols in .so's
+
+# Test --dynamic-list, --dynamic-list-data, --dynamic-list-cpp-new,
+# and --dynamic-list-cpp-typeinfo
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_2 = incremental_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_comdat_test.sh gc_tls_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_orphan_section_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ pr14265.sh icf_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_so_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ final_layout.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ text_section_grouping.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ section_sorting_name.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_preemptible_functions_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_string_merge_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_sht_rel_addend_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ merge_string_literals.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.sh weak_plt.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg.sh missing_key_func.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.sh ver_test_1.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_2.sh ver_test_4.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_5.sh ver_test_7.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_10.sh relro_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_5.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_6.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_7.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_8.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_9.sh dynamic_list.sh
+
+# Create the data files that debug_msg.sh analyzes.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_3 = incremental_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_comdat_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_tls_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_orphan_section_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ pr14265.stdout icf_test.map \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test_1.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test_2.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test.map \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_so_test_1.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_so_test_2.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_so_test.map \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ final_layout.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ text_section_grouping.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ text_section_no_grouping.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ section_sorting_name.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_preemptible_functions_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_string_merge_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_sht_rel_addend_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ merge_string_literals.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.dbg \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_plt_shared.so debug_msg.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ missing_key_func.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_4 = incremental_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test.cmdline \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_comdat_test gc_tls_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_orphan_section_test pr14265 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_test icf_test.map \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test icf_safe_test.map \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_so_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_so_test.map \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ final_layout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ final_layout_sequence.txt \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ final_layout_script.lds \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ text_section_grouping \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ text_section_no_grouping \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ section_sorting_name \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_virtual_function_folding_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_virtual_function_folding_test.map \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_preemptible_functions_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_string_merge_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_sht_rel_addend_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ merge_string_literals \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.dbg \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/weak_undef_lib.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_5 = icf_virtual_function_folding_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ large_symbol_alignment \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_test basic_pic_test
+@GCC_FALSE@large_symbol_alignment_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@large_symbol_alignment_DEPENDENCIES =
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@am__append_6 = basic_static_test \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_pic_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_7 = basic_pie_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_test
+@GCC_FALSE@constructor_test_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@constructor_test_DEPENDENCIES =
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@am__append_8 = constructor_static_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_9 = two_file_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_pic_test
+@GCC_FALSE@two_file_test_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@two_file_test_DEPENDENCIES =
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@am__append_10 = two_file_static_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_11 = two_file_shared_1_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_1_pic_2_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_pic_1_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_12_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_pie_test
+
+# The nonpic tests will fail on platforms which can not put non-PIC
+# code into shared libraries, so we just don't run them in that case.
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_12 = two_file_shared_1_nonpic_test \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_nonpic_test \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_nonpic_test \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_12_nonpic_test \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_nonpic_test \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_mixed_shared_test \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_mixed_2_shared_test \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_mixed_pie_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_13 = two_file_strip_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_strip_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ common_test_1 common_test_2 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_shared_1_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_shared_2_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_same_shared_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_separate_shared_12_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_separate_shared_21_test
+@GCC_FALSE@common_test_1_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@common_test_1_DEPENDENCIES =
+@GCC_FALSE@exception_test_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@exception_test_DEPENDENCIES =
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@am__append_14 = exception_static_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_15 = weak_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_undef_test
+@GCC_FALSE@weak_test_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@weak_test_DEPENDENCIES =
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_16 = weak_undef_nonpic_test
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_17 = alt/weak_undef_lib_nonpic.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_18 = weak_alias_test weak_plt \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ copy_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_19 = tls_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_pic_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_pie_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_pie_pic_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_shared_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_shared_ie_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_shared_gd_to_ie_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__append_20 = tls_shared_gnu2_gd_to_ie_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__append_21 = tls_shared_gnu2_test
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am__append_22 = tls_static_test \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@ tls_static_pic_test
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_23 = tls_shared_nonpic_test
+
+# Test -o when emitting to a special file (such as something in /dev).
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_24 = many_sections_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_r_test initpri1 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ initpri2 initpri3a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile
+@GCC_FALSE@many_sections_test_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@many_sections_test_DEPENDENCIES =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_25 = many_sections_define.h \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_check.h
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_26 = many_sections_define.h \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_check.h \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ missing_key_func.err
+@GCC_FALSE@initpri1_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@initpri1_DEPENDENCIES =
+@GCC_FALSE@initpri2_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@initpri2_DEPENDENCIES =
+@GCC_FALSE@initpri3a_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@initpri3a_DEPENDENCIES =
+
+# Check that --detect-odr-violations works with compressed debug sections.
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_27 = debug_msg_cdebug.err
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_28 = debug_msg_cdebug.err
+
+# See if we can also detect problems when we're linking .so's, not .o's.
+
+# We also want to make sure we do something reasonable when there's no
+# debug info available. For the best test, we use .so's.
+
+# This version won't be runnable, because there is no way to put the
+# PT_PHDR segment at file offset 0. We just make sure that we can
+# build it without error.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_29 = debug_msg_so.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_ndebug.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_ttext_2 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_1.syms ver_test_2.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_4.syms ver_test_5.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_7.syms ver_test_10.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ protected_3.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_5.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_6.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_7.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_8.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_9.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_30 = debug_msg_so.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_ndebug.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_ttext_2 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_11.a protected_3.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ justsyms_lib binary.txt \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4 script_test_5 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_6 script_test_7 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_8 script_test_9 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list dynamic_list.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ libthin1.a libthin3.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ libthinall.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/thin_archive_test_2.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/thin_archive_test_4.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/libthin2.a alt/libthin4.a
+
+# Test --compress-debug-sections. FIXME: check we actually compress.
+
+# The specialfile output has a tricky case when we also compress debug
+# sections, because it requires output-file resizing.
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_31 = flagstest_compress_debug_sections \
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile_and_compress_debug_sections
+
+# Test -TText and -Tdata.
+
+# Test symbol versioning.
+
+# Test scripts with a relocatable link.
+# The -g option is necessary to trigger a bug where a section
+# declared in a script file is assigned a non-zero starting address.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_32 = flagstest_o_ttext_1 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test ver_test_2 ver_test_6 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_8 ver_test_9 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_11 ver_test_12 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ protected_1 protected_2 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_test relro_now_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_strip_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_script_test script_test_1 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_2 justsyms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ justsyms_exec binary_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ tls_phdrs_script_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ tls_script_test script_test_11 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ thin_archive_test_1 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ thin_archive_test_2
+@GCC_FALSE@script_test_1_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@script_test_1_DEPENDENCIES =
+@GCC_FALSE@script_test_2_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@script_test_2_DEPENDENCIES =
+@GCC_FALSE@justsyms_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@justsyms_DEPENDENCIES =
+@GCC_FALSE@justsyms_exec_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@justsyms_exec_DEPENDENCIES =
+@GCC_FALSE@binary_test_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@binary_test_DEPENDENCIES =
+@GCC_FALSE@thin_archive_test_2_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@thin_archive_test_2_DEPENDENCIES =
+
+# Test plugins with -r.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_33 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_3 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_4 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_5 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_6 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_7 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_8
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_34 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_3.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_4.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_6.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_7.sh
+
+# Test that symbols known in the IR file but not in the replacement file
+# produce an unresolved symbol error.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_35 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_3.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_4.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_6.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_7.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_7.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_9.err
+# Make a copy of two_file_test_1.o, which does not define the symbol _Z4t16av.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_36 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_3.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_4.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_4.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_6.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_7.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_9.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ two_file_test_1c.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@@TLS_TRUE@am__append_37 = plugin_test_tls
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@@TLS_TRUE@am__append_38 = plugin_test_tls.sh
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@@TLS_TRUE@am__append_39 = plugin_test_tls.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@@TLS_TRUE@am__append_40 = plugin_test_tls.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_41 = unused.c \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_final_layout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_42 = plugin_final_layout.sh
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_43 = plugin_final_layout.stdout plugin_final_layout_readelf.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_44 = exclude_libs_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ local_labels_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test
+
+# Test that hidden and internal symbols in the main program cannot be
+# referenced by a shared library.
+
+# Test -retain-symbols-file.
+
+# Test that no .gnu.version sections are created when
+# symbol versioning is not used.
+
+# Test that strong reference to a weak symbol in a DSO remains strong.
+
+# Test that a strong weak reference remains strong if there is another
+# weak reference in a DSO.
+
+# Test that MEMORY region support works.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_45 = exclude_libs_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ no_version_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ strong_ref_weak_def.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref.sh memory_test.sh
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_46 = exclude_libs_test.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_relocatable_test1.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_relocatable_test2.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ no_version_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ strong_ref_weak_def.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ memory_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_47 = exclude_libs_test.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ libexclude_libs_test_1.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ libexclude_libs_test_2.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/libexclude_libs_test_3.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_relocatable_test1.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_relocatable_test2.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_relocatable_test1.out \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_relocatable_test2.out \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test hidden_test.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.in \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test_lib.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/searched_file_test_lib.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ libno_version_test.so \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ no_version_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ strong_ref_weak_def_1.so \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ strong_ref_weak_def_2.so \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ strong_ref_weak_def.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref_1.so \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref_2.so \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ libstart_lib_test.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ memory_test.stdout memory_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ memory_test.o
+@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am__append_48 = large
+@GCC_FALSE@large_DEPENDENCIES =
+@MCMODEL_MEDIUM_FALSE@large_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@large_DEPENDENCIES =
+
+# Test that if the output file already exists and is empty,
+# it will get execute permission.
+
+# Check -l:foo.a
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_49 = permission_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test
+@GCC_FALSE@searched_file_test_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@searched_file_test_DEPENDENCIES =
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__append_50 = ifuncmain1static \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1picstatic
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__append_51 = ifuncmain1 \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1pic \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1vis \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1vispic \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1staticpic \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1pie \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1vispie \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1staticpie
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__append_52 = ifuncmain2static \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain2picstatic
+@GCC_FALSE@ifuncmain2static_DEPENDENCIES =
+@HAVE_STATIC_FALSE@ifuncmain2static_DEPENDENCIES =
+@IFUNC_FALSE@ifuncmain2static_DEPENDENCIES =
+@IFUNC_STATIC_FALSE@ifuncmain2static_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@ifuncmain2static_DEPENDENCIES =
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__append_53 = ifuncmain2 \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain2pic \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain3
+@GCC_FALSE@ifuncmain2_DEPENDENCIES =
+@IFUNC_FALSE@ifuncmain2_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@ifuncmain2_DEPENDENCIES =
+@GCC_FALSE@ifuncmain3_DEPENDENCIES =
+@IFUNC_FALSE@ifuncmain3_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@ifuncmain3_DEPENDENCIES =
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__append_54 = ifuncmain4static \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain4picstatic
+@GCC_FALSE@ifuncmain4static_DEPENDENCIES =
+@HAVE_STATIC_FALSE@ifuncmain4static_DEPENDENCIES =
+@IFUNC_FALSE@ifuncmain4static_DEPENDENCIES =
+@IFUNC_STATIC_FALSE@ifuncmain4static_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@ifuncmain4static_DEPENDENCIES =
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__append_55 = ifuncmain4
+@GCC_FALSE@ifuncmain4_DEPENDENCIES =
+@IFUNC_FALSE@ifuncmain4_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@ifuncmain4_DEPENDENCIES =
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__append_56 = ifuncmain5static \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain5picstatic
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__append_57 = ifuncmain5 \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain5pic \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain5staticpic \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain5pie \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain6pie
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__append_58 = ifuncmain7static \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7picstatic
+@GCC_FALSE@ifuncmain7static_DEPENDENCIES =
+@HAVE_STATIC_FALSE@ifuncmain7static_DEPENDENCIES =
+@IFUNC_FALSE@ifuncmain7static_DEPENDENCIES =
+@IFUNC_STATIC_FALSE@ifuncmain7static_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@ifuncmain7static_DEPENDENCIES =
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__append_59 = ifuncmain7 \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7pic \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7pie \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncvar
+@GCC_FALSE@ifuncmain7_DEPENDENCIES =
+@IFUNC_FALSE@ifuncmain7_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@ifuncmain7_DEPENDENCIES =
+
+# Test that --start-lib and --end-lib function correctly.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_60 = start_lib_test
+
+# Test that --gdb-index functions correctly without gcc-generated pubnames.
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@am__append_61 = gdb_index_test_1.sh
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@am__append_62 = gdb_index_test_1.stdout
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@am__append_63 = gdb_index_test_1.stdout gdb_index_test_1
+
+# Test that --gdb-index functions correctly with compressed debug sections.
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_64 = gdb_index_test_2.sh
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_65 = gdb_index_test_2.stdout
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_66 = gdb_index_test_2.stdout gdb_index_test_2
+
+# Another simple C test (DW_AT_high_pc encoding) for --gdb-index.
+
+# Test that --gdb-index functions correctly with gcc-generated pubnames.
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@am__append_67 = gdb_index_test_3.sh \
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ gdb_index_test_4.sh
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@am__append_68 = gdb_index_test_3.stdout \
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ gdb_index_test_4.stdout
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@am__append_69 = gdb_index_test_3.stdout \
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ gdb_index_test_3 \
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ gdb_index_test_4.stdout \
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ gdb_index_test_4
+
+# Test the --incremental-unchanged flag with an archive library.
+# The second link should not update the library.
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_70 = incremental_test_2 \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_3 \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_4 \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_5 \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_6 \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_copy_test \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_common_test_1 \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_comdat_test_1
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_71 = two_file_test_tmp_2.o \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_tmp_3.o \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_4.base \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_tmp_4.o \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_5.a \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_6.a
+
+# These tests work with native and cross linkers.
+
+# Test script section order.
+@NATIVE_OR_CROSS_LINKER_TRUE@am__append_72 = script_test_10.sh
+@NATIVE_OR_CROSS_LINKER_TRUE@am__append_73 = script_test_10.stdout
+@NATIVE_OR_CROSS_LINKER_TRUE@am__append_74 = script_test_10
+
+# These tests work with cross linkers only.
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_75 = split_i386.sh
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_76 = split_i386_1.stdout split_i386_2.stdout \
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ split_i386_3.stdout split_i386_4.stdout split_i386_r.stdout
+
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_77 = split_i386_1 split_i386_2 split_i386_3 \
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ split_i386_4 split_i386_r
+
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_78 = split_x86_64.sh
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_79 = split_x86_64_1.stdout split_x86_64_2.stdout \
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ split_x86_64_3.stdout split_x86_64_4.stdout split_x86_64_r.stdout
+
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_80 = split_x86_64_1 split_x86_64_2 split_x86_64_3 \
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ split_x86_64_4 split_x86_64_r
+
+
+# ARM1176 workaround test.
+
+# Cortex-A8 workaround test.
+
+# Check ARM to ARM farcall veneers
+
+# Check ARM to Thumb farcall veneers
+
+# Check Thumb to Thumb farcall veneers
+
+# Check Thumb to ARM farcall veneers
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_81 = arm_abs_global.sh \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_branch_in_range.sh \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_branch_out_of_range.sh \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_v4bx.sh \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_attr_merge.sh \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_1176.sh \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_cortex_a8.sh \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_exidx_test.sh \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ pr12826.sh \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_unaligned_reloc.sh \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_arm_arm.sh \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_arm_thumb.sh \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb.sh \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_arm.sh
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_82 = arm_abs_global.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_bl_in_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_bl_out_of_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_bl_in_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_bl_out_of_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb2_bl_in_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb2_bl_out_of_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_blx_in_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_blx_out_of_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb2_blx_in_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb2_blx_out_of_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_bl_out_of_range_local.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_thm_jump11.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_thm_jump8.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_v4bx.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_v4bx_interworking.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_no_fix_v4bx.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_attr_merge_6.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_attr_merge_6r.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_attr_merge_7.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_1176_default_v6z.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_1176_on_v6z.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_1176_off_v6z.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_1176_default_v5te.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_1176_default_v7a.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_1176_default_1156t2f_s.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_cortex_a8_b_cond.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_cortex_a8_b.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_cortex_a8_bl.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_cortex_a8_blx.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_cortex_a8_local.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_cortex_a8_local_reloc.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_exidx_test.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ pr12826.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_unaligned_reloc.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_unaligned_reloc_r.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_arm_arm.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_arm_thumb.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_arm_thumb_5t.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb_5t.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb_7m.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb_6m.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_arm.stdout \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_arm_5t.stdout
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_83 = arm_abs_global \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_bl_in_range \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_bl_out_of_range \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_bl_in_range \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_bl_out_of_range \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb2_bl_in_range \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb2_bl_out_of_range \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_blx_in_range \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_blx_out_of_range \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb2_blx_in_range \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb2_blx_out_of_range \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_bl_out_of_range_local \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_thm_jump11 \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_thm_jump8 \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_v4bx \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_v4bx_interworking \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_no_fix_v4bx \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_attr_merge_6 \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_attr_merge_6r \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_attr_merge_7 \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_1176_default_v6z \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_1176_on_v6z \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_1176_off_v6z \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_1176_default_v5te \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_1176_default_v7a \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_1176_default_1156t2f_s \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_cortex_a8_b_cond \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_cortex_a8_b \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_cortex_a8_bl \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_cortex_a8_blx \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_cortex_a8_local \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_cortex_a8_local_reloc \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_unaligned_reloc \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_unaligned_reloc_r \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_arm_arm \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_arm_thumb \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_arm_thumb_5t \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb_5t \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb_7m \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb_6m \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_arm \
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_arm_5t
+@DEFAULT_TARGET_X86_64_TRUE@am__append_84 = *.dwo *.dwp
+@DEFAULT_TARGET_X86_64_TRUE@am__append_85 = dwp_test_1.sh \
+@DEFAULT_TARGET_X86_64_TRUE@ dwp_test_2.sh
+@DEFAULT_TARGET_X86_64_TRUE@am__append_86 = dwp_test_1.stdout \
+@DEFAULT_TARGET_X86_64_TRUE@ dwp_test_2.stdout
+subdir = testsuite
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+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)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AR = ar
+ARFLAGS = cru
+libgoldtest_a_AR = $(AR) $(ARFLAGS)
+libgoldtest_a_LIBADD =
+am_libgoldtest_a_OBJECTS = test.$(OBJEXT) testmain.$(OBJEXT) \
+ testfile.$(OBJEXT)
+libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS)
+@NATIVE_OR_CROSS_LINKER_TRUE@am__EXEEXT_1 = object_unittest$(EXEEXT) \
+@NATIVE_OR_CROSS_LINKER_TRUE@ binary_unittest$(EXEEXT) \
+@NATIVE_OR_CROSS_LINKER_TRUE@ leb128_unittest$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_2 = icf_virtual_function_folding_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ large_symbol_alignment$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_pic_test$(EXEEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_3 = basic_static_test$(EXEEXT) \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_pic_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_4 = basic_pie_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_test$(EXEEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_5 = constructor_static_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_6 = two_file_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_pic_test$(EXEEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_7 = two_file_static_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_8 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_1_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_1_pic_2_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_pic_1_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_12_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_pie_test$(EXEEXT)
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_9 = two_file_shared_1_nonpic_test$(EXEEXT) \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_nonpic_test$(EXEEXT) \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_nonpic_test$(EXEEXT) \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_12_nonpic_test$(EXEEXT) \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_nonpic_test$(EXEEXT) \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_mixed_shared_test$(EXEEXT) \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_mixed_2_shared_test$(EXEEXT) \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_mixed_pie_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_10 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_strip_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_strip_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ common_test_1$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ common_test_2$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_shared_1_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_shared_2_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_same_shared_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_separate_shared_12_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_separate_shared_21_test$(EXEEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_11 = exception_static_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_12 = weak_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_undef_test$(EXEEXT)
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_13 = weak_undef_nonpic_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_14 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_alias_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_plt$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ copy_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__EXEEXT_15 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_pic_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_pie_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_pie_pic_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_shared_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_shared_ie_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_shared_gd_to_ie_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__EXEEXT_16 = tls_shared_gnu2_gd_to_ie_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__EXEEXT_17 = tls_shared_gnu2_test$(EXEEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am__EXEEXT_18 = tls_static_test$(EXEEXT) \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@ tls_static_pic_test$(EXEEXT)
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__EXEEXT_19 = tls_shared_nonpic_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_20 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_r_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ initpri1$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ initpri2$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ initpri3a$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile$(EXEEXT)
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_21 = flagstest_compress_debug_sections$(EXEEXT) \
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_22 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_ttext_1$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_2$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_6$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_8$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_9$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_11$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_12$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ protected_1$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ protected_2$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_now_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_strip_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_script_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_1$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_2$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ justsyms$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ justsyms_exec$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ binary_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ tls_phdrs_script_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ tls_script_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_11$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ thin_archive_test_1$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ thin_archive_test_2$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__EXEEXT_23 = plugin_test_1$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_3$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_4$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_5$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_6$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_7$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_8$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@@TLS_TRUE@am__EXEEXT_24 = plugin_test_tls$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_25 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exclude_libs_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ local_labels_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test$(EXEEXT)
+@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_26 = large$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_27 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ permission_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test$(EXEEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_28 = ifuncmain1static$(EXEEXT) \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1picstatic$(EXEEXT)
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_29 = \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1pic$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1vis$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1vispic$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1staticpic$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1pie$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1vispie$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain1staticpie$(EXEEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_30 = ifuncmain2static$(EXEEXT) \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain2picstatic$(EXEEXT)
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_31 = \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain2$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain2pic$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain3$(EXEEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_32 = ifuncmain4static$(EXEEXT) \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain4picstatic$(EXEEXT)
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_33 = \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain4$(EXEEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_34 = ifuncmain5static$(EXEEXT) \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain5picstatic$(EXEEXT)
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_35 = \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain5$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain5pic$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain5staticpic$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain5pie$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain6pie$(EXEEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_36 = ifuncmain7static$(EXEEXT) \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7picstatic$(EXEEXT)
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_37 = \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7pic$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7pie$(EXEEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncvar$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_38 = start_lib_test$(EXEEXT)
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_39 = incremental_test_2$(EXEEXT) \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_3$(EXEEXT) \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_4$(EXEEXT) \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_5$(EXEEXT) \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_6$(EXEEXT) \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_copy_test$(EXEEXT) \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_common_test_1$(EXEEXT) \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_comdat_test_1$(EXEEXT)
+basic_pic_test_SOURCES = basic_pic_test.c
+basic_pic_test_OBJECTS = basic_pic_test.$(OBJEXT)
+basic_pic_test_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+basic_pic_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+basic_pie_test_SOURCES = basic_pie_test.c
+basic_pie_test_OBJECTS = basic_pie_test.$(OBJEXT)
+basic_pie_test_LDADD = $(LDADD)
+basic_pie_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+basic_static_pic_test_SOURCES = basic_static_pic_test.c
+basic_static_pic_test_OBJECTS = basic_static_pic_test.$(OBJEXT)
+basic_static_pic_test_LDADD = $(LDADD)
+basic_static_pic_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+basic_static_test_SOURCES = basic_static_test.c
+basic_static_test_OBJECTS = basic_static_test.$(OBJEXT)
+basic_static_test_LDADD = $(LDADD)
+basic_static_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+basic_test_SOURCES = basic_test.c
+basic_test_OBJECTS = basic_test.$(OBJEXT)
+basic_test_LDADD = $(LDADD)
+basic_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_binary_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ binary_test.$(OBJEXT)
+binary_test_OBJECTS = $(am_binary_test_OBJECTS)
+binary_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(binary_test_LDFLAGS) $(LDFLAGS) -o $@
+@NATIVE_OR_CROSS_LINKER_TRUE@am_binary_unittest_OBJECTS = \
+@NATIVE_OR_CROSS_LINKER_TRUE@ binary_unittest.$(OBJEXT)
+binary_unittest_OBJECTS = $(am_binary_unittest_OBJECTS)
+binary_unittest_LDADD = $(LDADD)
+binary_unittest_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_common_test_1_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ common_test_1.$(OBJEXT)
+common_test_1_OBJECTS = $(am_common_test_1_OBJECTS)
+common_test_1_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(common_test_1_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_common_test_2_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ common_test_1.$(OBJEXT)
+common_test_2_OBJECTS = $(am_common_test_2_OBJECTS)
+common_test_2_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(common_test_2_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__objects_1 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_test.$(OBJEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@am_constructor_static_test_OBJECTS = $(am__objects_1)
+constructor_static_test_OBJECTS = \
+ $(am_constructor_static_test_OBJECTS)
+constructor_static_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(constructor_static_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_constructor_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_test.$(OBJEXT)
+constructor_test_OBJECTS = $(am_constructor_test_OBJECTS)
+constructor_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(constructor_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_copy_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ copy_test.$(OBJEXT)
+copy_test_OBJECTS = $(am_copy_test_OBJECTS)
+copy_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(copy_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_discard_locals_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.$(OBJEXT)
+discard_locals_test_OBJECTS = $(am_discard_locals_test_OBJECTS)
+discard_locals_test_LDADD = $(LDADD)
+discard_locals_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+discard_locals_test_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(discard_locals_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_exception_same_shared_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_main.$(OBJEXT)
+exception_same_shared_test_OBJECTS = \
+ $(am_exception_same_shared_test_OBJECTS)
+exception_same_shared_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(exception_same_shared_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_exception_separate_shared_12_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_main.$(OBJEXT)
+exception_separate_shared_12_test_OBJECTS = \
+ $(am_exception_separate_shared_12_test_OBJECTS)
+exception_separate_shared_12_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(exception_separate_shared_12_test_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_exception_separate_shared_21_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_main.$(OBJEXT)
+exception_separate_shared_21_test_OBJECTS = \
+ $(am_exception_separate_shared_21_test_OBJECTS)
+exception_separate_shared_21_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(exception_separate_shared_21_test_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_exception_shared_1_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_2.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_main.$(OBJEXT)
+exception_shared_1_test_OBJECTS = \
+ $(am_exception_shared_1_test_OBJECTS)
+exception_shared_1_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(exception_shared_1_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_exception_shared_2_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_1.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_main.$(OBJEXT)
+exception_shared_2_test_OBJECTS = \
+ $(am_exception_shared_2_test_OBJECTS)
+exception_shared_2_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(exception_shared_2_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__objects_2 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_main.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_1.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_2.$(OBJEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@am_exception_static_test_OBJECTS = $(am__objects_2)
+exception_static_test_OBJECTS = $(am_exception_static_test_OBJECTS)
+exception_static_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(exception_static_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_exception_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_main.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_1.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_2.$(OBJEXT)
+exception_test_OBJECTS = $(am_exception_test_OBJECTS)
+exception_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(exception_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_exclude_libs_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exclude_libs_test.$(OBJEXT)
+exclude_libs_test_OBJECTS = $(am_exclude_libs_test_OBJECTS)
+exclude_libs_test_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(exclude_libs_test_LDFLAGS) $(LDFLAGS) -o $@
+flagstest_compress_debug_sections_SOURCES = \
+ flagstest_compress_debug_sections.c
+flagstest_compress_debug_sections_OBJECTS = \
+ flagstest_compress_debug_sections.$(OBJEXT)
+flagstest_compress_debug_sections_LDADD = $(LDADD)
+flagstest_compress_debug_sections_DEPENDENCIES = libgoldtest.a \
+ ../libgold.a ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+flagstest_o_specialfile_SOURCES = flagstest_o_specialfile.c
+flagstest_o_specialfile_OBJECTS = flagstest_o_specialfile.$(OBJEXT)
+flagstest_o_specialfile_LDADD = $(LDADD)
+flagstest_o_specialfile_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+flagstest_o_specialfile_and_compress_debug_sections_SOURCES = \
+ flagstest_o_specialfile_and_compress_debug_sections.c
+flagstest_o_specialfile_and_compress_debug_sections_OBJECTS = \
+ flagstest_o_specialfile_and_compress_debug_sections.$(OBJEXT)
+flagstest_o_specialfile_and_compress_debug_sections_LDADD = $(LDADD)
+flagstest_o_specialfile_and_compress_debug_sections_DEPENDENCIES = \
+ libgoldtest.a ../libgold.a ../../libiberty/libiberty.a \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+flagstest_o_ttext_1_SOURCES = flagstest_o_ttext_1.c
+flagstest_o_ttext_1_OBJECTS = flagstest_o_ttext_1.$(OBJEXT)
+flagstest_o_ttext_1_LDADD = $(LDADD)
+flagstest_o_ttext_1_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+icf_virtual_function_folding_test_SOURCES = \
+ icf_virtual_function_folding_test.c
+icf_virtual_function_folding_test_OBJECTS = \
+ icf_virtual_function_folding_test.$(OBJEXT)
+icf_virtual_function_folding_test_LDADD = $(LDADD)
+icf_virtual_function_folding_test_DEPENDENCIES = libgoldtest.a \
+ ../libgold.a ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncmain1_OBJECTS = ifuncmain1.$(OBJEXT)
+ifuncmain1_OBJECTS = $(am_ifuncmain1_OBJECTS)
+ifuncmain1_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ifuncmain1_LDFLAGS) \
+ $(LDFLAGS) -o $@
+ifuncmain1pic_SOURCES = ifuncmain1pic.c
+ifuncmain1pic_OBJECTS = ifuncmain1pic.$(OBJEXT)
+ifuncmain1pic_LDADD = $(LDADD)
+ifuncmain1pic_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ifuncmain1picstatic_SOURCES = ifuncmain1picstatic.c
+ifuncmain1picstatic_OBJECTS = ifuncmain1picstatic.$(OBJEXT)
+ifuncmain1picstatic_LDADD = $(LDADD)
+ifuncmain1picstatic_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ifuncmain1pie_SOURCES = ifuncmain1pie.c
+ifuncmain1pie_OBJECTS = ifuncmain1pie.$(OBJEXT)
+ifuncmain1pie_LDADD = $(LDADD)
+ifuncmain1pie_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncmain1static_OBJECTS = ifuncmain1.$(OBJEXT)
+ifuncmain1static_OBJECTS = $(am_ifuncmain1static_OBJECTS)
+ifuncmain1static_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(ifuncmain1static_LDFLAGS) $(LDFLAGS) -o $@
+ifuncmain1staticpic_SOURCES = ifuncmain1staticpic.c
+ifuncmain1staticpic_OBJECTS = ifuncmain1staticpic.$(OBJEXT)
+ifuncmain1staticpic_LDADD = $(LDADD)
+ifuncmain1staticpic_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ifuncmain1staticpie_SOURCES = ifuncmain1staticpie.c
+ifuncmain1staticpie_OBJECTS = ifuncmain1staticpie.$(OBJEXT)
+ifuncmain1staticpie_LDADD = $(LDADD)
+ifuncmain1staticpie_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncmain1vis_OBJECTS = ifuncmain1vis.$(OBJEXT)
+ifuncmain1vis_OBJECTS = $(am_ifuncmain1vis_OBJECTS)
+ifuncmain1vis_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(ifuncmain1vis_LDFLAGS) $(LDFLAGS) -o $@
+ifuncmain1vispic_SOURCES = ifuncmain1vispic.c
+ifuncmain1vispic_OBJECTS = ifuncmain1vispic.$(OBJEXT)
+ifuncmain1vispic_LDADD = $(LDADD)
+ifuncmain1vispic_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ifuncmain1vispie_SOURCES = ifuncmain1vispie.c
+ifuncmain1vispie_OBJECTS = ifuncmain1vispie.$(OBJEXT)
+ifuncmain1vispie_LDADD = $(LDADD)
+ifuncmain1vispie_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncmain2_OBJECTS = ifuncmain2.$(OBJEXT) \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncdep2.$(OBJEXT)
+ifuncmain2_OBJECTS = $(am_ifuncmain2_OBJECTS)
+ifuncmain2_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ifuncmain2_LDFLAGS) \
+ $(LDFLAGS) -o $@
+ifuncmain2pic_SOURCES = ifuncmain2pic.c
+ifuncmain2pic_OBJECTS = ifuncmain2pic.$(OBJEXT)
+ifuncmain2pic_LDADD = $(LDADD)
+ifuncmain2pic_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ifuncmain2picstatic_SOURCES = ifuncmain2picstatic.c
+ifuncmain2picstatic_OBJECTS = ifuncmain2picstatic.$(OBJEXT)
+ifuncmain2picstatic_LDADD = $(LDADD)
+ifuncmain2picstatic_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncmain2static_OBJECTS = ifuncmain2.$(OBJEXT) \
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncdep2.$(OBJEXT)
+ifuncmain2static_OBJECTS = $(am_ifuncmain2static_OBJECTS)
+ifuncmain2static_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(ifuncmain2static_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncmain3_OBJECTS = ifuncmain3.$(OBJEXT)
+ifuncmain3_OBJECTS = $(am_ifuncmain3_OBJECTS)
+ifuncmain3_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ifuncmain3_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncmain4_OBJECTS = ifuncmain4.$(OBJEXT)
+ifuncmain4_OBJECTS = $(am_ifuncmain4_OBJECTS)
+ifuncmain4_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ifuncmain4_LDFLAGS) \
+ $(LDFLAGS) -o $@
+ifuncmain4picstatic_SOURCES = ifuncmain4picstatic.c
+ifuncmain4picstatic_OBJECTS = ifuncmain4picstatic.$(OBJEXT)
+ifuncmain4picstatic_LDADD = $(LDADD)
+ifuncmain4picstatic_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncmain4static_OBJECTS = ifuncmain4.$(OBJEXT)
+ifuncmain4static_OBJECTS = $(am_ifuncmain4static_OBJECTS)
+ifuncmain4static_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(ifuncmain4static_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncmain5_OBJECTS = ifuncmain5.$(OBJEXT)
+ifuncmain5_OBJECTS = $(am_ifuncmain5_OBJECTS)
+ifuncmain5_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ifuncmain5_LDFLAGS) \
+ $(LDFLAGS) -o $@
+ifuncmain5pic_SOURCES = ifuncmain5pic.c
+ifuncmain5pic_OBJECTS = ifuncmain5pic.$(OBJEXT)
+ifuncmain5pic_LDADD = $(LDADD)
+ifuncmain5pic_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ifuncmain5picstatic_SOURCES = ifuncmain5picstatic.c
+ifuncmain5picstatic_OBJECTS = ifuncmain5picstatic.$(OBJEXT)
+ifuncmain5picstatic_LDADD = $(LDADD)
+ifuncmain5picstatic_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ifuncmain5pie_SOURCES = ifuncmain5pie.c
+ifuncmain5pie_OBJECTS = ifuncmain5pie.$(OBJEXT)
+ifuncmain5pie_LDADD = $(LDADD)
+ifuncmain5pie_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncmain5static_OBJECTS = ifuncmain5.$(OBJEXT)
+ifuncmain5static_OBJECTS = $(am_ifuncmain5static_OBJECTS)
+ifuncmain5static_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(ifuncmain5static_LDFLAGS) $(LDFLAGS) -o $@
+ifuncmain5staticpic_SOURCES = ifuncmain5staticpic.c
+ifuncmain5staticpic_OBJECTS = ifuncmain5staticpic.$(OBJEXT)
+ifuncmain5staticpic_LDADD = $(LDADD)
+ifuncmain5staticpic_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ifuncmain6pie_SOURCES = ifuncmain6pie.c
+ifuncmain6pie_OBJECTS = ifuncmain6pie.$(OBJEXT)
+ifuncmain6pie_LDADD = $(LDADD)
+ifuncmain6pie_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncmain7_OBJECTS = ifuncmain7.$(OBJEXT)
+ifuncmain7_OBJECTS = $(am_ifuncmain7_OBJECTS)
+ifuncmain7_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ifuncmain7_LDFLAGS) \
+ $(LDFLAGS) -o $@
+ifuncmain7pic_SOURCES = ifuncmain7pic.c
+ifuncmain7pic_OBJECTS = ifuncmain7pic.$(OBJEXT)
+ifuncmain7pic_LDADD = $(LDADD)
+ifuncmain7pic_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ifuncmain7picstatic_SOURCES = ifuncmain7picstatic.c
+ifuncmain7picstatic_OBJECTS = ifuncmain7picstatic.$(OBJEXT)
+ifuncmain7picstatic_LDADD = $(LDADD)
+ifuncmain7picstatic_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ifuncmain7pie_SOURCES = ifuncmain7pie.c
+ifuncmain7pie_OBJECTS = ifuncmain7pie.$(OBJEXT)
+ifuncmain7pie_LDADD = $(LDADD)
+ifuncmain7pie_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncmain7static_OBJECTS = ifuncmain7.$(OBJEXT)
+ifuncmain7static_OBJECTS = $(am_ifuncmain7static_OBJECTS)
+ifuncmain7static_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(ifuncmain7static_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncvar_OBJECTS = \
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncvar3.$(OBJEXT)
+ifuncvar_OBJECTS = $(am_ifuncvar_OBJECTS)
+ifuncvar_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ifuncvar_LDFLAGS) \
+ $(LDFLAGS) -o $@
+incremental_comdat_test_1_SOURCES = incremental_comdat_test_1.c
+incremental_comdat_test_1_OBJECTS = \
+ incremental_comdat_test_1.$(OBJEXT)
+incremental_comdat_test_1_LDADD = $(LDADD)
+incremental_comdat_test_1_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+incremental_common_test_1_SOURCES = incremental_common_test_1.c
+incremental_common_test_1_OBJECTS = \
+ incremental_common_test_1.$(OBJEXT)
+incremental_common_test_1_LDADD = $(LDADD)
+incremental_common_test_1_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+incremental_copy_test_SOURCES = incremental_copy_test.c
+incremental_copy_test_OBJECTS = incremental_copy_test.$(OBJEXT)
+incremental_copy_test_LDADD = $(LDADD)
+incremental_copy_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+incremental_test_2_SOURCES = incremental_test_2.c
+incremental_test_2_OBJECTS = incremental_test_2.$(OBJEXT)
+incremental_test_2_LDADD = $(LDADD)
+incremental_test_2_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+incremental_test_3_SOURCES = incremental_test_3.c
+incremental_test_3_OBJECTS = incremental_test_3.$(OBJEXT)
+incremental_test_3_LDADD = $(LDADD)
+incremental_test_3_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+incremental_test_4_SOURCES = incremental_test_4.c
+incremental_test_4_OBJECTS = incremental_test_4.$(OBJEXT)
+incremental_test_4_LDADD = $(LDADD)
+incremental_test_4_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+incremental_test_5_SOURCES = incremental_test_5.c
+incremental_test_5_OBJECTS = incremental_test_5.$(OBJEXT)
+incremental_test_5_LDADD = $(LDADD)
+incremental_test_5_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+incremental_test_6_SOURCES = incremental_test_6.c
+incremental_test_6_OBJECTS = incremental_test_6.$(OBJEXT)
+incremental_test_6_LDADD = $(LDADD)
+incremental_test_6_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_initpri1_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ initpri1.$(OBJEXT)
+initpri1_OBJECTS = $(am_initpri1_OBJECTS)
+initpri1_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(initpri1_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_initpri2_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ initpri2.$(OBJEXT)
+initpri2_OBJECTS = $(am_initpri2_OBJECTS)
+initpri2_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(initpri2_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_initpri3a_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ initpri3.$(OBJEXT)
+initpri3a_OBJECTS = $(am_initpri3a_OBJECTS)
+initpri3a_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(initpri3a_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_justsyms_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ justsyms_1.$(OBJEXT)
+justsyms_OBJECTS = $(am_justsyms_OBJECTS)
+justsyms_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(justsyms_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_justsyms_exec_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ justsyms_exec.$(OBJEXT)
+justsyms_exec_OBJECTS = $(am_justsyms_exec_OBJECTS)
+justsyms_exec_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(justsyms_exec_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am_large_OBJECTS = large-large.$(OBJEXT)
+large_OBJECTS = $(am_large_OBJECTS)
+large_LINK = $(CCLD) $(large_CFLAGS) $(CFLAGS) $(large_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_large_symbol_alignment_OBJECTS = large_symbol_alignment.$(OBJEXT)
+large_symbol_alignment_OBJECTS = $(am_large_symbol_alignment_OBJECTS)
+large_symbol_alignment_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(large_symbol_alignment_LDFLAGS) $(LDFLAGS) -o $@
+@NATIVE_OR_CROSS_LINKER_TRUE@am_leb128_unittest_OBJECTS = \
+@NATIVE_OR_CROSS_LINKER_TRUE@ leb128_unittest.$(OBJEXT)
+leb128_unittest_OBJECTS = $(am_leb128_unittest_OBJECTS)
+leb128_unittest_LDADD = $(LDADD)
+leb128_unittest_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+local_labels_test_SOURCES = local_labels_test.c
+local_labels_test_OBJECTS = local_labels_test.$(OBJEXT)
+local_labels_test_LDADD = $(LDADD)
+local_labels_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+many_sections_r_test_SOURCES = many_sections_r_test.c
+many_sections_r_test_OBJECTS = many_sections_r_test.$(OBJEXT)
+many_sections_r_test_LDADD = $(LDADD)
+many_sections_r_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_many_sections_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_test.$(OBJEXT)
+many_sections_test_OBJECTS = $(am_many_sections_test_OBJECTS)
+many_sections_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(many_sections_test_LDFLAGS) $(LDFLAGS) -o $@
+@NATIVE_OR_CROSS_LINKER_TRUE@am_object_unittest_OBJECTS = \
+@NATIVE_OR_CROSS_LINKER_TRUE@ object_unittest.$(OBJEXT)
+object_unittest_OBJECTS = $(am_object_unittest_OBJECTS)
+object_unittest_LDADD = $(LDADD)
+object_unittest_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+permission_test_SOURCES = permission_test.c
+permission_test_OBJECTS = permission_test.$(OBJEXT)
+permission_test_LDADD = $(LDADD)
+permission_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+plugin_test_1_SOURCES = plugin_test_1.c
+plugin_test_1_OBJECTS = plugin_test_1.$(OBJEXT)
+plugin_test_1_LDADD = $(LDADD)
+plugin_test_1_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+plugin_test_2_SOURCES = plugin_test_2.c
+plugin_test_2_OBJECTS = plugin_test_2.$(OBJEXT)
+plugin_test_2_LDADD = $(LDADD)
+plugin_test_2_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+plugin_test_3_SOURCES = plugin_test_3.c
+plugin_test_3_OBJECTS = plugin_test_3.$(OBJEXT)
+plugin_test_3_LDADD = $(LDADD)
+plugin_test_3_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+plugin_test_4_SOURCES = plugin_test_4.c
+plugin_test_4_OBJECTS = plugin_test_4.$(OBJEXT)
+plugin_test_4_LDADD = $(LDADD)
+plugin_test_4_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+plugin_test_5_SOURCES = plugin_test_5.c
+plugin_test_5_OBJECTS = plugin_test_5.$(OBJEXT)
+plugin_test_5_LDADD = $(LDADD)
+plugin_test_5_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+plugin_test_6_SOURCES = plugin_test_6.c
+plugin_test_6_OBJECTS = plugin_test_6.$(OBJEXT)
+plugin_test_6_LDADD = $(LDADD)
+plugin_test_6_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+plugin_test_7_SOURCES = plugin_test_7.c
+plugin_test_7_OBJECTS = plugin_test_7.$(OBJEXT)
+plugin_test_7_LDADD = $(LDADD)
+plugin_test_7_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+plugin_test_8_SOURCES = plugin_test_8.c
+plugin_test_8_OBJECTS = plugin_test_8.$(OBJEXT)
+plugin_test_8_LDADD = $(LDADD)
+plugin_test_8_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+plugin_test_tls_SOURCES = plugin_test_tls.c
+plugin_test_tls_OBJECTS = plugin_test_tls.$(OBJEXT)
+plugin_test_tls_LDADD = $(LDADD)
+plugin_test_tls_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_protected_1_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ protected_main_1.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ protected_main_2.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ protected_main_3.$(OBJEXT)
+protected_1_OBJECTS = $(am_protected_1_OBJECTS)
+protected_1_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(protected_1_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_protected_2_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ protected_main_1.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ protected_3.$(OBJEXT)
+protected_2_OBJECTS = $(am_protected_2_OBJECTS)
+protected_2_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(protected_2_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_relro_now_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_test_main.$(OBJEXT)
+relro_now_test_OBJECTS = $(am_relro_now_test_OBJECTS)
+relro_now_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(relro_now_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_relro_script_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_test_main.$(OBJEXT)
+relro_script_test_OBJECTS = $(am_relro_script_test_OBJECTS)
+relro_script_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(relro_script_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_relro_strip_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_test_main.$(OBJEXT)
+relro_strip_test_OBJECTS = $(am_relro_strip_test_OBJECTS)
+relro_strip_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(relro_strip_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_relro_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_test_main.$(OBJEXT)
+relro_test_OBJECTS = $(am_relro_test_OBJECTS)
+relro_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(relro_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_script_test_1_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_1.$(OBJEXT)
+script_test_1_OBJECTS = $(am_script_test_1_OBJECTS)
+script_test_1_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(script_test_1_LDFLAGS) $(LDFLAGS) -o $@
+script_test_11_SOURCES = script_test_11.c
+script_test_11_OBJECTS = script_test_11.$(OBJEXT)
+script_test_11_LDADD = $(LDADD)
+script_test_11_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_script_test_2_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_2.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_2a.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_2b.$(OBJEXT)
+script_test_2_OBJECTS = $(am_script_test_2_OBJECTS)
+script_test_2_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(script_test_2_LDFLAGS) $(LDFLAGS) -o $@
+script_test_3_SOURCES = script_test_3.c
+script_test_3_OBJECTS = script_test_3.$(OBJEXT)
+script_test_3_LDADD = $(LDADD)
+script_test_3_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_searched_file_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test.$(OBJEXT)
+searched_file_test_OBJECTS = $(am_searched_file_test_OBJECTS)
+searched_file_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(searched_file_test_LDFLAGS) $(LDFLAGS) -o $@
+start_lib_test_SOURCES = start_lib_test.c
+start_lib_test_OBJECTS = start_lib_test.$(OBJEXT)
+start_lib_test_LDADD = $(LDADD)
+start_lib_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_thin_archive_test_1_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ thin_archive_main.$(OBJEXT)
+thin_archive_test_1_OBJECTS = $(am_thin_archive_test_1_OBJECTS)
+thin_archive_test_1_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(thin_archive_test_1_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_thin_archive_test_2_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ thin_archive_main.$(OBJEXT)
+thin_archive_test_2_OBJECTS = $(am_thin_archive_test_2_OBJECTS)
+thin_archive_test_2_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(thin_archive_test_2_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__objects_3 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_file2.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_main.$(OBJEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_tls_phdrs_script_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(am__objects_3)
+tls_phdrs_script_test_OBJECTS = $(am_tls_phdrs_script_test_OBJECTS)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__DEPENDENCIES_2 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_c.o
+tls_phdrs_script_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(tls_phdrs_script_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_pic_test_OBJECTS = tls_test_main.$(OBJEXT)
+tls_pic_test_OBJECTS = $(am_tls_pic_test_OBJECTS)
+tls_pic_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(tls_pic_test_LDFLAGS) $(LDFLAGS) -o $@
+tls_pie_pic_test_SOURCES = tls_pie_pic_test.c
+tls_pie_pic_test_OBJECTS = tls_pie_pic_test.$(OBJEXT)
+tls_pie_pic_test_LDADD = $(LDADD)
+tls_pie_pic_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+tls_pie_test_SOURCES = tls_pie_test.c
+tls_pie_test_OBJECTS = tls_pie_test.$(OBJEXT)
+tls_pie_test_LDADD = $(LDADD)
+tls_pie_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_tls_script_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(am__objects_3)
+tls_script_test_OBJECTS = $(am_tls_script_test_OBJECTS)
+tls_script_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(tls_script_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_shared_gd_to_ie_test_OBJECTS = tls_test_main.$(OBJEXT)
+tls_shared_gd_to_ie_test_OBJECTS = \
+ $(am_tls_shared_gd_to_ie_test_OBJECTS)
+tls_shared_gd_to_ie_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(tls_shared_gd_to_ie_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am_tls_shared_gnu2_gd_to_ie_test_OBJECTS = tls_test_main.$(OBJEXT)
+tls_shared_gnu2_gd_to_ie_test_OBJECTS = \
+ $(am_tls_shared_gnu2_gd_to_ie_test_OBJECTS)
+tls_shared_gnu2_gd_to_ie_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(tls_shared_gnu2_gd_to_ie_test_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am_tls_shared_gnu2_test_OBJECTS = tls_test_main.$(OBJEXT)
+tls_shared_gnu2_test_OBJECTS = $(am_tls_shared_gnu2_test_OBJECTS)
+tls_shared_gnu2_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(tls_shared_gnu2_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_shared_ie_test_OBJECTS = tls_test_main.$(OBJEXT)
+tls_shared_ie_test_OBJECTS = $(am_tls_shared_ie_test_OBJECTS)
+tls_shared_ie_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(tls_shared_ie_test_LDFLAGS) $(LDFLAGS) -o $@
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_shared_nonpic_test_OBJECTS = tls_test_main.$(OBJEXT)
+tls_shared_nonpic_test_OBJECTS = $(am_tls_shared_nonpic_test_OBJECTS)
+tls_shared_nonpic_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(tls_shared_nonpic_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_shared_test_OBJECTS = tls_test_main.$(OBJEXT)
+tls_shared_test_OBJECTS = $(am_tls_shared_test_OBJECTS)
+tls_shared_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(tls_shared_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__objects_4 = tls_test_main.$(OBJEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am_tls_static_pic_test_OBJECTS = $(am__objects_4)
+tls_static_pic_test_OBJECTS = $(am_tls_static_pic_test_OBJECTS)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__DEPENDENCIES_3 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_pic.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_file2_pic.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_c_pic.o
+tls_static_pic_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(tls_static_pic_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am_tls_static_test_OBJECTS = $(am__objects_3)
+tls_static_test_OBJECTS = $(am_tls_static_test_OBJECTS)
+tls_static_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(tls_static_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_file2.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_main.$(OBJEXT)
+tls_test_OBJECTS = $(am_tls_test_OBJECTS)
+tls_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(tls_test_LDFLAGS) $(LDFLAGS) -o $@
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_mixed_2_shared_test_OBJECTS = two_file_test_main.$(OBJEXT)
+two_file_mixed_2_shared_test_OBJECTS = \
+ $(am_two_file_mixed_2_shared_test_OBJECTS)
+two_file_mixed_2_shared_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(two_file_mixed_2_shared_test_LDFLAGS) $(LDFLAGS) \
+ -o $@
+two_file_mixed_pie_test_SOURCES = two_file_mixed_pie_test.c
+two_file_mixed_pie_test_OBJECTS = two_file_mixed_pie_test.$(OBJEXT)
+two_file_mixed_pie_test_LDADD = $(LDADD)
+two_file_mixed_pie_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_mixed_shared_test_OBJECTS = two_file_test_main.$(OBJEXT)
+two_file_mixed_shared_test_OBJECTS = \
+ $(am_two_file_mixed_shared_test_OBJECTS)
+two_file_mixed_shared_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(two_file_mixed_shared_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_pic_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+two_file_pic_test_OBJECTS = $(am_two_file_pic_test_OBJECTS)
+two_file_pic_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(two_file_pic_test_LDFLAGS) $(LDFLAGS) -o $@
+two_file_pie_test_SOURCES = two_file_pie_test.c
+two_file_pie_test_OBJECTS = two_file_pie_test.$(OBJEXT)
+two_file_pie_test_LDADD = $(LDADD)
+two_file_pie_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_relocatable_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+two_file_relocatable_test_OBJECTS = \
+ $(am_two_file_relocatable_test_OBJECTS)
+two_file_relocatable_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(two_file_relocatable_test_LDFLAGS) $(LDFLAGS) -o $@
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_same_shared_nonpic_test_OBJECTS = two_file_test_main.$(OBJEXT)
+two_file_same_shared_nonpic_test_OBJECTS = \
+ $(am_two_file_same_shared_nonpic_test_OBJECTS)
+two_file_same_shared_nonpic_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(two_file_same_shared_nonpic_test_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_same_shared_strip_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+two_file_same_shared_strip_test_OBJECTS = \
+ $(am_two_file_same_shared_strip_test_OBJECTS)
+two_file_same_shared_strip_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(two_file_same_shared_strip_test_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_same_shared_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+two_file_same_shared_test_OBJECTS = \
+ $(am_two_file_same_shared_test_OBJECTS)
+two_file_same_shared_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(two_file_same_shared_test_LDFLAGS) $(LDFLAGS) -o $@
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_separate_shared_12_nonpic_test_OBJECTS = two_file_test_main.$(OBJEXT)
+two_file_separate_shared_12_nonpic_test_OBJECTS = \
+ $(am_two_file_separate_shared_12_nonpic_test_OBJECTS)
+two_file_separate_shared_12_nonpic_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(two_file_separate_shared_12_nonpic_test_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_separate_shared_12_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+two_file_separate_shared_12_test_OBJECTS = \
+ $(am_two_file_separate_shared_12_test_OBJECTS)
+two_file_separate_shared_12_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(two_file_separate_shared_12_test_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_separate_shared_21_nonpic_test_OBJECTS = two_file_test_main.$(OBJEXT)
+two_file_separate_shared_21_nonpic_test_OBJECTS = \
+ $(am_two_file_separate_shared_21_nonpic_test_OBJECTS)
+two_file_separate_shared_21_nonpic_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(two_file_separate_shared_21_nonpic_test_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_separate_shared_21_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+two_file_separate_shared_21_test_OBJECTS = \
+ $(am_two_file_separate_shared_21_test_OBJECTS)
+two_file_separate_shared_21_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(two_file_separate_shared_21_test_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_shared_1_nonpic_test_OBJECTS = two_file_test_2.$(OBJEXT) \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+two_file_shared_1_nonpic_test_OBJECTS = \
+ $(am_two_file_shared_1_nonpic_test_OBJECTS)
+two_file_shared_1_nonpic_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(two_file_shared_1_nonpic_test_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_shared_1_pic_2_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+two_file_shared_1_pic_2_test_OBJECTS = \
+ $(am_two_file_shared_1_pic_2_test_OBJECTS)
+two_file_shared_1_pic_2_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(two_file_shared_1_pic_2_test_LDFLAGS) $(LDFLAGS) \
+ -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_shared_1_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+two_file_shared_1_test_OBJECTS = $(am_two_file_shared_1_test_OBJECTS)
+two_file_shared_1_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(two_file_shared_1_test_LDFLAGS) $(LDFLAGS) -o $@
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_shared_2_nonpic_test_OBJECTS = two_file_test_1.$(OBJEXT) \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_1b.$(OBJEXT) \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+two_file_shared_2_nonpic_test_OBJECTS = \
+ $(am_two_file_shared_2_nonpic_test_OBJECTS)
+two_file_shared_2_nonpic_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(two_file_shared_2_nonpic_test_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_shared_2_pic_1_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+two_file_shared_2_pic_1_test_OBJECTS = \
+ $(am_two_file_shared_2_pic_1_test_OBJECTS)
+two_file_shared_2_pic_1_test_LINK = $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(two_file_shared_2_pic_1_test_LDFLAGS) $(LDFLAGS) \
+ -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_shared_2_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_1.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_1b.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+two_file_shared_2_test_OBJECTS = $(am_two_file_shared_2_test_OBJECTS)
+two_file_shared_2_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(two_file_shared_2_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__objects_5 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_1.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_1b.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_static_test_OBJECTS = $(am__objects_5)
+two_file_static_test_OBJECTS = $(am_two_file_static_test_OBJECTS)
+two_file_static_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(two_file_static_test_LDFLAGS) $(LDFLAGS) -o $@
+two_file_strip_test_SOURCES = two_file_strip_test.c
+two_file_strip_test_OBJECTS = two_file_strip_test.$(OBJEXT)
+two_file_strip_test_LDADD = $(LDADD)
+two_file_strip_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_1.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_1b.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2.$(OBJEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+two_file_test_OBJECTS = $(am_two_file_test_OBJECTS)
+two_file_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(two_file_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ver_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_main.$(OBJEXT)
+ver_test_OBJECTS = $(am_ver_test_OBJECTS)
+ver_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(ver_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ver_test_11_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_main_2.$(OBJEXT)
+ver_test_11_OBJECTS = $(am_ver_test_11_OBJECTS)
+ver_test_11_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(ver_test_11_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ver_test_12_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_main_2.$(OBJEXT)
+ver_test_12_OBJECTS = $(am_ver_test_12_OBJECTS)
+ver_test_12_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(ver_test_12_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ver_test_2_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_main_2.$(OBJEXT)
+ver_test_2_OBJECTS = $(am_ver_test_2_OBJECTS)
+ver_test_2_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(ver_test_2_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ver_test_6_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_6.$(OBJEXT)
+ver_test_6_OBJECTS = $(am_ver_test_6_OBJECTS)
+ver_test_6_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ver_test_6_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ver_test_8_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
+ver_test_8_OBJECTS = $(am_ver_test_8_OBJECTS)
+ver_test_8_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(ver_test_8_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ver_test_9_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_main.$(OBJEXT)
+ver_test_9_OBJECTS = $(am_ver_test_9_OBJECTS)
+ver_test_9_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(ver_test_9_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_weak_alias_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_alias_test_main.$(OBJEXT)
+weak_alias_test_OBJECTS = $(am_weak_alias_test_OBJECTS)
+weak_alias_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(weak_alias_test_LDFLAGS) $(LDFLAGS) -o $@
+weak_plt_SOURCES = weak_plt.c
+weak_plt_OBJECTS = weak_plt.$(OBJEXT)
+weak_plt_LDADD = $(LDADD)
+weak_plt_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_weak_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_test.$(OBJEXT)
+weak_test_OBJECTS = $(am_weak_test_OBJECTS)
+weak_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(weak_test_LDFLAGS) $(LDFLAGS) -o $@
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am_weak_undef_nonpic_test_OBJECTS = weak_undef_test.$(OBJEXT)
+weak_undef_nonpic_test_OBJECTS = $(am_weak_undef_nonpic_test_OBJECTS)
+weak_undef_nonpic_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(weak_undef_nonpic_test_LDFLAGS) $(LDFLAGS) -o $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_weak_undef_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_undef_test.$(OBJEXT)
+weak_undef_test_OBJECTS = $(am_weak_undef_test_OBJECTS)
+weak_undef_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(weak_undef_test_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CCLD = $(CC)
+CXXLD = $(CXX)
+SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c basic_pie_test.c \
+ basic_static_pic_test.c basic_static_test.c basic_test.c \
+ $(binary_test_SOURCES) $(binary_unittest_SOURCES) \
+ $(common_test_1_SOURCES) $(common_test_2_SOURCES) \
+ $(constructor_static_test_SOURCES) $(constructor_test_SOURCES) \
+ $(copy_test_SOURCES) $(discard_locals_test_SOURCES) \
+ $(exception_same_shared_test_SOURCES) \
+ $(exception_separate_shared_12_test_SOURCES) \
+ $(exception_separate_shared_21_test_SOURCES) \
+ $(exception_shared_1_test_SOURCES) \
+ $(exception_shared_2_test_SOURCES) \
+ $(exception_static_test_SOURCES) $(exception_test_SOURCES) \
+ $(exclude_libs_test_SOURCES) \
+ flagstest_compress_debug_sections.c flagstest_o_specialfile.c \
+ flagstest_o_specialfile_and_compress_debug_sections.c \
+ flagstest_o_ttext_1.c icf_virtual_function_folding_test.c \
+ $(ifuncmain1_SOURCES) ifuncmain1pic.c ifuncmain1picstatic.c \
+ ifuncmain1pie.c $(ifuncmain1static_SOURCES) \
+ ifuncmain1staticpic.c ifuncmain1staticpie.c \
+ $(ifuncmain1vis_SOURCES) ifuncmain1vispic.c ifuncmain1vispie.c \
+ $(ifuncmain2_SOURCES) ifuncmain2pic.c ifuncmain2picstatic.c \
+ $(ifuncmain2static_SOURCES) $(ifuncmain3_SOURCES) \
+ $(ifuncmain4_SOURCES) ifuncmain4picstatic.c \
+ $(ifuncmain4static_SOURCES) $(ifuncmain5_SOURCES) \
+ ifuncmain5pic.c ifuncmain5picstatic.c ifuncmain5pie.c \
+ $(ifuncmain5static_SOURCES) ifuncmain5staticpic.c \
+ ifuncmain6pie.c $(ifuncmain7_SOURCES) ifuncmain7pic.c \
+ ifuncmain7picstatic.c ifuncmain7pie.c \
+ $(ifuncmain7static_SOURCES) $(ifuncvar_SOURCES) \
+ incremental_comdat_test_1.c incremental_common_test_1.c \
+ incremental_copy_test.c incremental_test_2.c \
+ incremental_test_3.c incremental_test_4.c incremental_test_5.c \
+ incremental_test_6.c $(initpri1_SOURCES) $(initpri2_SOURCES) \
+ $(initpri3a_SOURCES) $(justsyms_SOURCES) \
+ $(justsyms_exec_SOURCES) $(large_SOURCES) \
+ $(large_symbol_alignment_SOURCES) $(leb128_unittest_SOURCES) \
+ local_labels_test.c many_sections_r_test.c \
+ $(many_sections_test_SOURCES) $(object_unittest_SOURCES) \
+ permission_test.c plugin_test_1.c plugin_test_2.c \
+ plugin_test_3.c plugin_test_4.c plugin_test_5.c \
+ plugin_test_6.c plugin_test_7.c plugin_test_8.c \
+ plugin_test_tls.c $(protected_1_SOURCES) \
+ $(protected_2_SOURCES) $(relro_now_test_SOURCES) \
+ $(relro_script_test_SOURCES) $(relro_strip_test_SOURCES) \
+ $(relro_test_SOURCES) $(script_test_1_SOURCES) \
+ script_test_11.c $(script_test_2_SOURCES) script_test_3.c \
+ $(searched_file_test_SOURCES) start_lib_test.c \
+ $(thin_archive_test_1_SOURCES) $(thin_archive_test_2_SOURCES) \
+ $(tls_phdrs_script_test_SOURCES) $(tls_pic_test_SOURCES) \
+ tls_pie_pic_test.c tls_pie_test.c $(tls_script_test_SOURCES) \
+ $(tls_shared_gd_to_ie_test_SOURCES) \
+ $(tls_shared_gnu2_gd_to_ie_test_SOURCES) \
+ $(tls_shared_gnu2_test_SOURCES) $(tls_shared_ie_test_SOURCES) \
+ $(tls_shared_nonpic_test_SOURCES) $(tls_shared_test_SOURCES) \
+ $(tls_static_pic_test_SOURCES) $(tls_static_test_SOURCES) \
+ $(tls_test_SOURCES) $(two_file_mixed_2_shared_test_SOURCES) \
+ two_file_mixed_pie_test.c \
+ $(two_file_mixed_shared_test_SOURCES) \
+ $(two_file_pic_test_SOURCES) two_file_pie_test.c \
+ $(two_file_relocatable_test_SOURCES) \
+ $(two_file_same_shared_nonpic_test_SOURCES) \
+ $(two_file_same_shared_strip_test_SOURCES) \
+ $(two_file_same_shared_test_SOURCES) \
+ $(two_file_separate_shared_12_nonpic_test_SOURCES) \
+ $(two_file_separate_shared_12_test_SOURCES) \
+ $(two_file_separate_shared_21_nonpic_test_SOURCES) \
+ $(two_file_separate_shared_21_test_SOURCES) \
+ $(two_file_shared_1_nonpic_test_SOURCES) \
+ $(two_file_shared_1_pic_2_test_SOURCES) \
+ $(two_file_shared_1_test_SOURCES) \
+ $(two_file_shared_2_nonpic_test_SOURCES) \
+ $(two_file_shared_2_pic_1_test_SOURCES) \
+ $(two_file_shared_2_test_SOURCES) \
+ $(two_file_static_test_SOURCES) two_file_strip_test.c \
+ $(two_file_test_SOURCES) $(ver_test_SOURCES) \
+ $(ver_test_11_SOURCES) $(ver_test_12_SOURCES) \
+ $(ver_test_2_SOURCES) $(ver_test_6_SOURCES) \
+ $(ver_test_8_SOURCES) $(ver_test_9_SOURCES) \
+ $(weak_alias_test_SOURCES) weak_plt.c $(weak_test_SOURCES) \
+ $(weak_undef_nonpic_test_SOURCES) $(weak_undef_test_SOURCES)
+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)
+AM_RECURSIVE_TARGETS = check check-html recheck recheck-html
+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)
+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@
+
+# Ignore warning about AM_PROG_CC_C_O due to large_CFLAGS
+AUTOMAKE_OPTIONS = foreign -Wno-portability
+
+# The two_file_test tests -fmerge-constants, so we simply always turn
+# it on. For compilers that do not support the command-line option,
+# we assume they just always emit SHF_MERGE sections unconditionally.
+AM_CFLAGS = $(WARN_CFLAGS) $(LFS_CFLAGS) $(MERGE_CONSTANTS_FLAG)
+AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CFLAGS) $(MERGE_CONSTANTS_FLAG)
+AM_CPPFLAGS = \
+ -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../include \
+ -I$(srcdir)/../../elfcpp -I.. \
+ -DLOCALEDIR="\"$(datadir)/locale\"" \
+ @INCINTL@
+
+
+# COMPILE1, LINK1, CXXCOMPILE1, CXXLINK1 are renamed from COMPILE, LINK,
+# CXXCOMPILE and CXXLINK generated by automake 1.11.1. FIXME: they should
+# be updated if they are different from automake used by gold.
+COMPILE1 = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+
+LINK1 = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CXXCOMPILE1 = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+
+CXXLINK1 = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+
+
+# Strip out -Wp,-D_FORTIFY_SOURCE=, which is rrelevant for the gold
+# testsuite and incompatible with -O0 used in gold tests, from
+# COMPILE, LINK, CXXCOMPILE and CXXLINK.
+COMPILE = `echo $(COMPILE1) | sed -e 's/-Wp,-D_FORTIFY_SOURCE=[0-9[0-9]]*//'`
+LINK = `echo $(LINK1) | sed -e 's/-Wp,-D_FORTIFY_SOURCE=[0-9][0-9]*//'`
+CXXCOMPILE = `echo $(CXXCOMPILE1) | sed -e 's/-Wp,-D_FORTIFY_SOURCE=[0-9][0-9]*//'`
+CXXLINK = `echo $(CXXLINK1) | sed -e 's/-Wp,-D_FORTIFY_SOURCE=[0-9][0-9]*//'`
+
+# Strip out -static-libgcc and -static-libstdc++ options, for tests
+# that must have these libraries linked dynamically. The -shared-libgcc
+# option does not work correctly, and there is no -shared-libstdc++ option.
+# (See GCC PR 55781 and PR 55782.)
+CXXLINK_S = `echo $(CXXLINK1) | sed -e 's/-static-lib\\(gcc\\|stdc++\\)//g'`
+TEST_READELF = $(top_builddir)/../binutils/readelf
+TEST_OBJDUMP = $(top_builddir)/../binutils/objdump
+TEST_OBJCOPY = $(top_builddir)/../binutils/objcopy
+TEST_CXXFILT = $(top_builddir)/../binutils/cxxfilt
+TEST_STRIP = $(top_builddir)/../binutils/strip-new
+TEST_AR = $(top_builddir)/../binutils/ar
+TEST_NM = $(top_builddir)/../binutils/nm-new
+TEST_AS = $(top_builddir)/../gas/as-new
+@PLUGINS_TRUE@LIBDL = -ldl
+@THREADS_TRUE@THREADSLIB = -lpthread
+@OMP_SUPPORT_TRUE@TLS_TEST_C_CFLAGS = -fopenmp
+
+# 'make clean' is good about deleting some intermediate files (such as
+# .o's), but not all of them (such as .so's and .err files). We
+# improve on that here. automake-1.9 info docs say "mostlyclean" is
+# the right choice for files 'make' builds that people rebuild.
+MOSTLYCLEANFILES = *.so *.syms *.stdout $(am__append_4) \
+ $(am__append_17) $(am__append_26) $(am__append_28) \
+ $(am__append_30) $(am__append_36) $(am__append_40) \
+ $(am__append_41) $(am__append_47) $(am__append_63) \
+ $(am__append_66) $(am__append_69) $(am__append_71) \
+ $(am__append_74) $(am__append_77) $(am__append_80) \
+ $(am__append_83) $(am__append_84)
+
+# We will add to these later, for each individual test. Note
+# that we add each test under check_SCRIPTS or check_PROGRAMS;
+# the TESTS variable is automatically populated from these.
+check_SCRIPTS = $(am__append_2) $(am__append_34) $(am__append_38) \
+ $(am__append_42) $(am__append_45) $(am__append_61) \
+ $(am__append_64) $(am__append_67) $(am__append_72) \
+ $(am__append_75) $(am__append_78) $(am__append_81) \
+ $(am__append_85)
+check_DATA = $(am__append_3) $(am__append_27) $(am__append_29) \
+ $(am__append_35) $(am__append_39) $(am__append_43) \
+ $(am__append_46) $(am__append_62) $(am__append_65) \
+ $(am__append_68) $(am__append_73) $(am__append_76) \
+ $(am__append_79) $(am__append_82) $(am__append_86)
+BUILT_SOURCES = $(am__append_25)
+TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
+
+# ---------------------------------------------------------------------
+# These tests test the internals of gold (unittests).
+
+# Infrastucture needed for the unittests
+check_LIBRARIES = libgoldtest.a
+libgoldtest_a_SOURCES = test.cc testmain.cc testfile.cc
+DEPENDENCIES = \
+ libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL_DEP)
+
+LDADD = libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL) \
+ $(THREADSLIB) $(LIBDL)
+
+@NATIVE_OR_CROSS_LINKER_TRUE@object_unittest_SOURCES = object_unittest.cc
+@NATIVE_OR_CROSS_LINKER_TRUE@binary_unittest_SOURCES = binary_unittest.cc
+@NATIVE_OR_CROSS_LINKER_TRUE@leb128_unittest_SOURCES = leb128_unittest.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@large_symbol_alignment_SOURCES = large_symbol_alignment.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@large_symbol_alignment_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@large_symbol_alignment_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@large_symbol_alignment_LDADD =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@constructor_test_SOURCES = constructor_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@constructor_test_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@constructor_test_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@constructor_test_LDADD =
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@constructor_static_test_SOURCES = $(constructor_test_SOURCES)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@constructor_static_test_DEPENDENCIES = $(constructor_test_DEPENDENCIES)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@constructor_static_test_LDFLAGS = $(constructor_test_LDFLAGS) -static
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@constructor_static_test_LDADD = $(constructor_test_LDADD)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_SOURCES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_1.cc \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_1b.cc \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2.cc \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.cc \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test.h
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_LDADD =
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@two_file_static_test_SOURCES = $(two_file_test_SOURCES)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@two_file_static_test_DEPENDENCIES = $(two_file_test_DEPENDENCIES)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@two_file_static_test_LDFLAGS = $(two_file_test_LDFLAGS) -static
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@two_file_static_test_LDADD = $(two_file_test_LDADD)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_pic_test_SOURCES = two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_pic_test_DEPENDENCIES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2_pic.o
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_pic_test_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_pic_test_LDADD = two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_test_SOURCES = two_file_test_2.cc two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_test_DEPENDENCIES = gcctestdir/ld two_file_shared_1.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_test_LDADD = two_file_shared_1.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_test_SOURCES = two_file_test_1.cc two_file_test_1b.cc two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_test_DEPENDENCIES = gcctestdir/ld two_file_shared_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_test_LDADD = two_file_shared_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_pic_2_test_SOURCES = two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_pic_2_test_DEPENDENCIES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_shared_2.so two_file_test_1_pic.o two_file_test_1b_pic.o
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_pic_2_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_pic_2_test_LDADD = two_file_test_1_pic.o two_file_test_1b_pic.o two_file_shared_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_pic_1_test_SOURCES = two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_pic_1_test_DEPENDENCIES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_shared_2.so two_file_test_2_pic.o
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_pic_1_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_pic_1_test_LDADD = two_file_test_2_pic.o two_file_shared_1.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_same_shared_test_SOURCES = two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_same_shared_test_DEPENDENCIES = gcctestdir/ld two_file_shared.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_same_shared_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_same_shared_test_LDADD = two_file_shared.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_12_test_SOURCES = two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_12_test_DEPENDENCIES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_shared_1.so two_file_shared_2.so
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_12_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_12_test_LDADD = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_1.so two_file_shared_2.so
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_21_test_SOURCES = two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_21_test_DEPENDENCIES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_shared_1.so two_file_shared_2.so
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_21_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_21_test_LDADD = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2.so two_file_shared_1.so
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable_test_SOURCES = two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable_test_DEPENDENCIES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_relocatable.o
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable_test_LDADD = two_file_relocatable.o
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic_test_SOURCES = \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2.cc two_file_test_main.cc
+
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic_test_DEPENDENCIES = \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_shared_1_nonpic.so
+
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic_test_LDADD = two_file_shared_1_nonpic.so
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_nonpic_test_SOURCES = \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_1.cc two_file_test_1b.cc two_file_test_main.cc
+
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_nonpic_test_DEPENDENCIES = \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_shared_2_nonpic.so
+
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_nonpic_test_LDADD = two_file_shared_2_nonpic.so
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_same_shared_nonpic_test_SOURCES = two_file_test_main.cc
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_same_shared_nonpic_test_DEPENDENCIES = \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_shared_nonpic.so
+
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_same_shared_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_same_shared_nonpic_test_LDADD = two_file_shared_nonpic.so
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_12_nonpic_test_SOURCES = two_file_test_main.cc
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_12_nonpic_test_DEPENDENCIES = \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_shared_1_nonpic.so two_file_shared_2_nonpic.so
+
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_12_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_12_nonpic_test_LDADD = \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_1_nonpic.so two_file_shared_2_nonpic.so
+
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_21_nonpic_test_SOURCES = two_file_test_main.cc
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_21_nonpic_test_DEPENDENCIES = \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_shared_1_nonpic.so two_file_shared_2_nonpic.so
+
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_21_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_21_nonpic_test_LDADD = \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_nonpic.so two_file_shared_1_nonpic.so
+
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_mixed_shared_test_SOURCES = two_file_test_main.cc
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_mixed_shared_test_DEPENDENCIES = gcctestdir/ld two_file_shared_mixed.so
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_mixed_shared_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_mixed_shared_test_LDADD = two_file_shared_mixed.so
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_mixed_2_shared_test_SOURCES = two_file_test_main.cc
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_mixed_2_shared_test_DEPENDENCIES = gcctestdir/ld two_file_shared_mixed_1.so two_file_shared_2.so
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_mixed_2_shared_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_mixed_2_shared_test_LDADD = two_file_shared_mixed_1.so two_file_shared_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_same_shared_strip_test_SOURCES = two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_same_shared_strip_test_DEPENDENCIES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_shared_strip.so
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_same_shared_strip_test_LDFLAGS = -Bgcctestdir/ -Wl,-R.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_same_shared_strip_test_LDADD = two_file_shared_strip.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@common_test_1_SOURCES = common_test_1.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@common_test_1_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@common_test_1_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@common_test_1_LDADD =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@common_test_2_SOURCES = common_test_1.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@common_test_2_DEPENDENCIES = common_test_2.so common_test_3.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@common_test_2_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@common_test_2_LDADD = common_test_2.so common_test_3.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_test_SOURCES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_main.cc \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_1.cc \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test_2.cc \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_test.h
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_test_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_test_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_test_LDADD =
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@exception_static_test_SOURCES = $(exception_test_SOURCES)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@exception_static_test_DEPENDENCIES = $(exception_test_DEPENDENCIES)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@exception_static_test_LDFLAGS = $(exception_test_LDFLAGS) -static
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@exception_static_test_LDADD = $(exception_test_LDADD)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_1_test_SOURCES = exception_test_2.cc exception_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_1_test_DEPENDENCIES = gcctestdir/ld exception_shared_1.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_1_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_1_test_LDADD = exception_shared_1.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_2_test_SOURCES = exception_test_1.cc exception_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_2_test_DEPENDENCIES = gcctestdir/ld exception_shared_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_2_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_2_test_LDADD = exception_shared_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_same_shared_test_SOURCES = exception_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_same_shared_test_DEPENDENCIES = gcctestdir/ld exception_shared.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_same_shared_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_same_shared_test_LDADD = exception_shared.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_separate_shared_12_test_SOURCES = exception_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_separate_shared_12_test_DEPENDENCIES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld exception_shared_1.so exception_shared_2.so
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_separate_shared_12_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,. \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--no-as-needed
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_separate_shared_12_test_LDADD = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_shared_1.so exception_shared_2.so
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_separate_shared_21_test_SOURCES = exception_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_separate_shared_21_test_DEPENDENCIES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld exception_shared_1.so exception_shared_2.so
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_separate_shared_21_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,. \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--no-as-needed
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_separate_shared_21_test_LDADD = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_shared_2.so exception_shared_1.so
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_test_SOURCES = weak_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_test_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_test_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_test_LDADD =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_test_SOURCES = weak_undef_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_test_DEPENDENCIES = gcctestdir/ld weak_undef_lib.so alt/weak_undef_lib.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,alt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_test_LDADD = -L . weak_undef_lib.so
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_nonpic_test_SOURCES = weak_undef_test.cc
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_nonpic_test_DEPENDENCIES = gcctestdir/ld weak_undef_lib_nonpic.so alt/weak_undef_lib_nonpic.so
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,alt
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_nonpic_test_LDADD = -L . weak_undef_lib_nonpic.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_alias_test_SOURCES = weak_alias_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_alias_test_DEPENDENCIES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld weak_alias_test_1.so weak_alias_test_2.so \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_alias_test_3.o weak_alias_test_4.so weak_alias_test_5.so
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_alias_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_alias_test_LDADD = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_alias_test_1.so weak_alias_test_2.so weak_alias_test_3.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_alias_test_4.so weak_alias_test_5.so
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@copy_test_SOURCES = copy_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@copy_test_DEPENDENCIES = gcctestdir/ld copy_test_1.so copy_test_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@copy_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@copy_test_LDADD = copy_test_1.so copy_test_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_SOURCES = tls_test.cc tls_test_file2.cc tls_test_main.cc tls_test.h
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_DEPENDENCIES = gcctestdir/ld tls_test_c.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_LDADD = tls_test_c.o -lpthread
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_pic_test_SOURCES = tls_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_pic_test_DEPENDENCIES = gcctestdir/ld tls_test_pic.o tls_test_file2_pic.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_c_pic.o
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_pic_test_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_pic_test_LDADD = tls_test_pic.o tls_test_file2_pic.o tls_test_c_pic.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ -lpthread
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_test_SOURCES = tls_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_test_DEPENDENCIES = gcctestdir/ld tls_test_shared.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_test_LDADD = tls_test_shared.so -lpthread
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_ie_test_SOURCES = tls_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_ie_test_DEPENDENCIES = gcctestdir/ld tls_test_ie_shared.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_ie_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_ie_test_LDADD = tls_test_ie_shared.so -lpthread
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_gd_to_ie_test_SOURCES = tls_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_gd_to_ie_test_DEPENDENCIES = gcctestdir/ld tls_test_pic.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_c_pic.o tls_test_shared2.so
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_gd_to_ie_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_gd_to_ie_test_LDADD = tls_test_pic.o tls_test_c_pic.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_shared2.so -lpthread
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_gd_to_ie_test_SOURCES = tls_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_gd_to_ie_test_DEPENDENCIES = gcctestdir/ld tls_test_gnu2.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@ tls_test_c_gnu2.o tls_test_gnu2_shared2.so
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_gd_to_ie_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_gd_to_ie_test_LDADD = tls_test_gnu2.o tls_test_c_gnu2.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@ tls_test_gnu2_shared2.so -lpthread
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_test_SOURCES = tls_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_test_DEPENDENCIES = gcctestdir/ld tls_test_gnu2_shared.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_test_LDADD = tls_test_gnu2_shared.so -lpthread
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@tls_static_test_SOURCES = $(tls_test_SOURCES)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@tls_static_test_DEPENDENCIES = $(tls_test_DEPENDENCIES)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@tls_static_test_LDFLAGS = $(tls_test_LDFLAGS) -static
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@tls_static_test_LDADD = $(tls_test_LDADD)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@tls_static_pic_test_SOURCES = $(tls_pic_test_SOURCES)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@tls_static_pic_test_DEPENDENCIES = $(tls_pic_test_DEPENDENCIES)
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@tls_static_pic_test_LDFLAGS = $(tls_pic_test_LDFLAGS) -static
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@tls_static_pic_test_LDADD = $(tls_pic_test_LDADD)
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_nonpic_test_SOURCES = tls_test_main.cc
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_nonpic_test_DEPENDENCIES = gcctestdir/ld tls_test_shared_nonpic.so
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_nonpic_test_LDADD = tls_test_shared_nonpic.so -lpthread
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_test_SOURCES = many_sections_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_test_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_test_LDFLAGS = -Bgcctestdir/ -rdynamic
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_test_LDADD =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri1_SOURCES = initpri1.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri1_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri1_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri1_LDADD =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri2_SOURCES = initpri2.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri2_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri2_LDFLAGS = -Bgcctestdir/ -Wl,--ctors-in-init-array
+@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri2_LDADD =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri3a_SOURCES = initpri3.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri3a_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri3a_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri3a_LDADD =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_SOURCES = ver_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_DEPENDENCIES = gcctestdir/ld ver_test_1.so ver_test_2.so ver_test_4.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_LDADD = ver_test_1.so ver_test_2.so ver_test_4.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_2_SOURCES = ver_test_main_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_2_DEPENDENCIES = gcctestdir/ld ver_test_4.so ver_test_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_2_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_2_LDADD = ver_test_4.so ver_test_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_6_SOURCES = ver_test_6.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_6_DEPENDENCIES = gcctestdir/ld ver_test_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_6_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_6_LDADD = ver_test_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_8_SOURCES = two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_8_DEPENDENCIES = gcctestdir/ld ver_test_8_1.so ver_test_8_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_8_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_8_LDADD = ver_test_8_1.so ver_test_8_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_9_SOURCES = ver_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_9_DEPENDENCIES = gcctestdir/ld ver_test_9.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_9_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_9_LDADD = ver_test_9.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_11_SOURCES = ver_test_main_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_11_DEPENDENCIES = gcctestdir/ld ver_test_11.a
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_11_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_11_LDADD = ver_test_11.a
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_12_SOURCES = ver_test_main_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_12_DEPENDENCIES = gcctestdir/ld ver_test_12.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_12_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_12_LDADD = ver_test_12.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_1_SOURCES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ protected_main_1.cc protected_main_2.cc protected_main_3.cc
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_1_DEPENDENCIES = gcctestdir/ld protected_1.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_1_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_1_LDADD = protected_1.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_2_SOURCES = protected_main_1.cc protected_3.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_2_DEPENDENCIES = gcctestdir/ld protected_1.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_2_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_2_LDADD = protected_1.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_test_SOURCES = relro_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_test_DEPENDENCIES = gcctestdir/ld relro_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_test_LDADD = relro_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_now_test_SOURCES = relro_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_now_test_DEPENDENCIES = gcctestdir/ld relro_now_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_now_test_LDFLAGS = -Bgcctestdir -Wl,-R,. -Wl,-z,relro -Wl,-z,now
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_now_test_LDADD = relro_now_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_strip_test_SOURCES = relro_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_strip_test_DEPENDENCIES = gcctestdir/ld relro_strip_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_strip_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_strip_test_LDADD = relro_strip_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_script_test_SOURCES = relro_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_script_test_DEPENDENCIES = gcctestdir/ld relro_script_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_script_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_script_test_LDADD = relro_script_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_1_SOURCES = script_test_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_1_DEPENDENCIES = gcctestdir/ld script_test_1.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_1_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -Wl,-T,$(srcdir)/script_test_1.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_1_LDADD =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_2_SOURCES = script_test_2.cc script_test_2a.cc script_test_2b.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_2_DEPENDENCIES = gcctestdir/ld script_test_2.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_2_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -Wl,-T,$(srcdir)/script_test_2.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_2_LDADD =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_SOURCES = justsyms_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_DEPENDENCIES = gcctestdir/ld justsyms_2r.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_LDFLAGS = -Bgcctestdir/ -Wl,-R,justsyms_2r.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_LDADD =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_exec_SOURCES = justsyms_exec.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_exec_DEPENDENCIES = gcctestdir/ld justsyms_lib
+@GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_exec_LDFLAGS = -Bgcctestdir/ -Wl,-R,justsyms_lib
+@GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_exec_LDADD =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@binary_test_SOURCES = binary_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@binary_test_DEPENDENCIES = gcctestdir/ld binary.txt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@binary_test_LDFLAGS = -Bgcctestdir/ -Wl,--format,binary,binary.txt,--format,elf
+@GCC_TRUE@@NATIVE_LINKER_TRUE@binary_test_LDADD =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@tls_phdrs_script_test_SOURCES = $(tls_test_SOURCES)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@tls_phdrs_script_test_DEPENDENCIES = $(tls_test_DEPENDENCIES) $(srcdir)/script_test_3.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@tls_phdrs_script_test_LDFLAGS = $(tls_test_LDFLAGS) -Wl,-T,$(srcdir)/script_test_3.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@tls_phdrs_script_test_LDADD = $(tls_test_LDADD)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@tls_script_test_SOURCES = $(tls_test_SOURCES)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@tls_script_test_DEPENDENCIES = $(tls_test_DEPENDENCIES) $(srcdir)/script_test_4.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@tls_script_test_LDFLAGS = $(tls_test_LDFLAGS) -Wl,-T,$(srcdir)/script_test_4.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@tls_script_test_LDADD = $(tls_test_LDADD)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@thin_archive_test_1_SOURCES = thin_archive_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@thin_archive_test_1_DEPENDENCIES = gcctestdir/ld libthin1.a alt/libthin2.a
+@GCC_TRUE@@NATIVE_LINKER_TRUE@thin_archive_test_1_LDFLAGS = -Bgcctestdir/ -Lalt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@thin_archive_test_1_LDADD = libthin1.a -lthin2
+@GCC_TRUE@@NATIVE_LINKER_TRUE@thin_archive_test_2_SOURCES = thin_archive_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@thin_archive_test_2_DEPENDENCIES = gcctestdir/ld libthinall.a
+@GCC_TRUE@@NATIVE_LINKER_TRUE@thin_archive_test_2_LDFLAGS = -Bgcctestdir/ -L.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@thin_archive_test_2_LDADD = -lthinall
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exclude_libs_test_SOURCES = exclude_libs_test.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exclude_libs_test_DEPENDENCIES = gcctestdir/ld libexclude_libs_test_1.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ libexclude_libs_test_2.a alt/libexclude_libs_test_3.a
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exclude_libs_test_LDFLAGS = -Bgcctestdir/ -L. -Lalt \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--exclude-libs,dummy:libexclude_libs_test_1 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--exclude-libs,libexclude_libs_test_3
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exclude_libs_test_LDADD = -lexclude_libs_test_1 -lexclude_libs_test_2 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/libexclude_libs_test_3.a
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_test_SOURCES = discard_locals_test.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_test_LDFLAGS = -Bgcctestdir/ -Wl,--discard-locals
+@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_SOURCES = large.c
+@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_CFLAGS = -mcmodel=medium
+@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_LDADD =
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_SOURCES = searched_file_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_DEPENDENCIES = alt/searched_file_test_lib.a
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_LDFLAGS = -Bgcctestdir/ -Lalt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_LDADD = -l:searched_file_test_lib.a
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1static_SOURCES = ifuncmain1.c
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1static_DEPENDENCIES = gcctestdir/ld ifuncdep1.o
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1static_LDFLAGS = -Bgcctestdir/ -static
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1static_LDADD = ifuncdep1.o
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1_SOURCES = ifuncmain1.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1_DEPENDENCIES = gcctestdir/ld ifuncmod1.so
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1_LDADD = ifuncmod1.so
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1vis_SOURCES = ifuncmain1vis.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1vis_DEPENDENCIES = gcctestdir/ld ifuncmod1.so
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1vis_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1vis_LDADD = ifuncmod1.so
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain2static_SOURCES = ifuncmain2.c ifuncdep2.c
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain2static_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain2static_LDFLAGS = -Bgcctestdir/ -static
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain2static_LDADD =
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain2_SOURCES = ifuncmain2.c ifuncdep2.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain2_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain2_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain2_LDADD =
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain3_SOURCES = ifuncmain3.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain3_DEPENDENCIES = gcctestdir/ld ifuncmod3.so
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain3_LDFLAGS = -Bgcctestdir/ -Wl,--export-dynamic -Wl,-R,.
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain3_LDADD = -ldl
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain4static_SOURCES = ifuncmain4.c
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain4static_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain4static_LDFLAGS = -Bgcctestdir/ -static
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain4static_LDADD =
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain4_SOURCES = ifuncmain4.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain4_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain4_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain4_LDADD =
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5static_SOURCES = ifuncmain5.c
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5static_DEPENDENCIES = gcctestdir/ld ifuncdep5.o
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5static_LDFLAGS = -Bgcctestdir/ -static
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5static_LDADD = ifuncdep5.o
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5_SOURCES = ifuncmain5.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5_DEPENDENCIES = gcctestdir/ld ifuncmod5.so
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5_LDADD = ifuncmod5.so
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7static_SOURCES = ifuncmain7.c
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7static_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7static_LDFLAGS = -Bgcctestdir/ -static
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7static_LDADD =
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7_SOURCES = ifuncmain7.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7_LDADD =
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar_SOURCES = ifuncvar3.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar_DEPENDENCIES = gcctestdir/ld ifuncvar.so
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar_LDADD = ifuncvar.so
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cc .html .log .o .obj .test .test$(EXEEXT)
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign testsuite/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkLIBRARIES:
+ -test -z "$(check_LIBRARIES)" || rm -f $(check_LIBRARIES)
+libgoldtest.a: $(libgoldtest_a_OBJECTS) $(libgoldtest_a_DEPENDENCIES)
+ -rm -f libgoldtest.a
+ $(libgoldtest_a_AR) libgoldtest.a $(libgoldtest_a_OBJECTS) $(libgoldtest_a_LIBADD)
+ $(RANLIB) libgoldtest.a
+
+clean-checkPROGRAMS:
+ -test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS)
+@GCC_FALSE@basic_pic_test$(EXEEXT): $(basic_pic_test_OBJECTS) $(basic_pic_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f basic_pic_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(basic_pic_test_OBJECTS) $(basic_pic_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@basic_pic_test$(EXEEXT): $(basic_pic_test_OBJECTS) $(basic_pic_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f basic_pic_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(basic_pic_test_OBJECTS) $(basic_pic_test_LDADD) $(LIBS)
+@GCC_FALSE@basic_pie_test$(EXEEXT): $(basic_pie_test_OBJECTS) $(basic_pie_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f basic_pie_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(basic_pie_test_OBJECTS) $(basic_pie_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@basic_pie_test$(EXEEXT): $(basic_pie_test_OBJECTS) $(basic_pie_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f basic_pie_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(basic_pie_test_OBJECTS) $(basic_pie_test_LDADD) $(LIBS)
+@GCC_FALSE@basic_static_pic_test$(EXEEXT): $(basic_static_pic_test_OBJECTS) $(basic_static_pic_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f basic_static_pic_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(basic_static_pic_test_OBJECTS) $(basic_static_pic_test_LDADD) $(LIBS)
+@HAVE_STATIC_FALSE@basic_static_pic_test$(EXEEXT): $(basic_static_pic_test_OBJECTS) $(basic_static_pic_test_DEPENDENCIES)
+@HAVE_STATIC_FALSE@ @rm -f basic_static_pic_test$(EXEEXT)
+@HAVE_STATIC_FALSE@ $(LINK) $(basic_static_pic_test_OBJECTS) $(basic_static_pic_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@basic_static_pic_test$(EXEEXT): $(basic_static_pic_test_OBJECTS) $(basic_static_pic_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f basic_static_pic_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(basic_static_pic_test_OBJECTS) $(basic_static_pic_test_LDADD) $(LIBS)
+@GCC_FALSE@basic_static_test$(EXEEXT): $(basic_static_test_OBJECTS) $(basic_static_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f basic_static_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(basic_static_test_OBJECTS) $(basic_static_test_LDADD) $(LIBS)
+@HAVE_STATIC_FALSE@basic_static_test$(EXEEXT): $(basic_static_test_OBJECTS) $(basic_static_test_DEPENDENCIES)
+@HAVE_STATIC_FALSE@ @rm -f basic_static_test$(EXEEXT)
+@HAVE_STATIC_FALSE@ $(LINK) $(basic_static_test_OBJECTS) $(basic_static_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@basic_static_test$(EXEEXT): $(basic_static_test_OBJECTS) $(basic_static_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f basic_static_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(basic_static_test_OBJECTS) $(basic_static_test_LDADD) $(LIBS)
+@GCC_FALSE@basic_test$(EXEEXT): $(basic_test_OBJECTS) $(basic_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f basic_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(basic_test_OBJECTS) $(basic_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@basic_test$(EXEEXT): $(basic_test_OBJECTS) $(basic_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f basic_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(basic_test_OBJECTS) $(basic_test_LDADD) $(LIBS)
+binary_test$(EXEEXT): $(binary_test_OBJECTS) $(binary_test_DEPENDENCIES)
+ @rm -f binary_test$(EXEEXT)
+ $(binary_test_LINK) $(binary_test_OBJECTS) $(binary_test_LDADD) $(LIBS)
+binary_unittest$(EXEEXT): $(binary_unittest_OBJECTS) $(binary_unittest_DEPENDENCIES)
+ @rm -f binary_unittest$(EXEEXT)
+ $(CXXLINK) $(binary_unittest_OBJECTS) $(binary_unittest_LDADD) $(LIBS)
+common_test_1$(EXEEXT): $(common_test_1_OBJECTS) $(common_test_1_DEPENDENCIES)
+ @rm -f common_test_1$(EXEEXT)
+ $(common_test_1_LINK) $(common_test_1_OBJECTS) $(common_test_1_LDADD) $(LIBS)
+common_test_2$(EXEEXT): $(common_test_2_OBJECTS) $(common_test_2_DEPENDENCIES)
+ @rm -f common_test_2$(EXEEXT)
+ $(common_test_2_LINK) $(common_test_2_OBJECTS) $(common_test_2_LDADD) $(LIBS)
+constructor_static_test$(EXEEXT): $(constructor_static_test_OBJECTS) $(constructor_static_test_DEPENDENCIES)
+ @rm -f constructor_static_test$(EXEEXT)
+ $(constructor_static_test_LINK) $(constructor_static_test_OBJECTS) $(constructor_static_test_LDADD) $(LIBS)
+constructor_test$(EXEEXT): $(constructor_test_OBJECTS) $(constructor_test_DEPENDENCIES)
+ @rm -f constructor_test$(EXEEXT)
+ $(constructor_test_LINK) $(constructor_test_OBJECTS) $(constructor_test_LDADD) $(LIBS)
+copy_test$(EXEEXT): $(copy_test_OBJECTS) $(copy_test_DEPENDENCIES)
+ @rm -f copy_test$(EXEEXT)
+ $(copy_test_LINK) $(copy_test_OBJECTS) $(copy_test_LDADD) $(LIBS)
+discard_locals_test$(EXEEXT): $(discard_locals_test_OBJECTS) $(discard_locals_test_DEPENDENCIES)
+ @rm -f discard_locals_test$(EXEEXT)
+ $(discard_locals_test_LINK) $(discard_locals_test_OBJECTS) $(discard_locals_test_LDADD) $(LIBS)
+exception_same_shared_test$(EXEEXT): $(exception_same_shared_test_OBJECTS) $(exception_same_shared_test_DEPENDENCIES)
+ @rm -f exception_same_shared_test$(EXEEXT)
+ $(exception_same_shared_test_LINK) $(exception_same_shared_test_OBJECTS) $(exception_same_shared_test_LDADD) $(LIBS)
+exception_separate_shared_12_test$(EXEEXT): $(exception_separate_shared_12_test_OBJECTS) $(exception_separate_shared_12_test_DEPENDENCIES)
+ @rm -f exception_separate_shared_12_test$(EXEEXT)
+ $(exception_separate_shared_12_test_LINK) $(exception_separate_shared_12_test_OBJECTS) $(exception_separate_shared_12_test_LDADD) $(LIBS)
+exception_separate_shared_21_test$(EXEEXT): $(exception_separate_shared_21_test_OBJECTS) $(exception_separate_shared_21_test_DEPENDENCIES)
+ @rm -f exception_separate_shared_21_test$(EXEEXT)
+ $(exception_separate_shared_21_test_LINK) $(exception_separate_shared_21_test_OBJECTS) $(exception_separate_shared_21_test_LDADD) $(LIBS)
+exception_shared_1_test$(EXEEXT): $(exception_shared_1_test_OBJECTS) $(exception_shared_1_test_DEPENDENCIES)
+ @rm -f exception_shared_1_test$(EXEEXT)
+ $(exception_shared_1_test_LINK) $(exception_shared_1_test_OBJECTS) $(exception_shared_1_test_LDADD) $(LIBS)
+exception_shared_2_test$(EXEEXT): $(exception_shared_2_test_OBJECTS) $(exception_shared_2_test_DEPENDENCIES)
+ @rm -f exception_shared_2_test$(EXEEXT)
+ $(exception_shared_2_test_LINK) $(exception_shared_2_test_OBJECTS) $(exception_shared_2_test_LDADD) $(LIBS)
+exception_static_test$(EXEEXT): $(exception_static_test_OBJECTS) $(exception_static_test_DEPENDENCIES)
+ @rm -f exception_static_test$(EXEEXT)
+ $(exception_static_test_LINK) $(exception_static_test_OBJECTS) $(exception_static_test_LDADD) $(LIBS)
+exception_test$(EXEEXT): $(exception_test_OBJECTS) $(exception_test_DEPENDENCIES)
+ @rm -f exception_test$(EXEEXT)
+ $(exception_test_LINK) $(exception_test_OBJECTS) $(exception_test_LDADD) $(LIBS)
+exclude_libs_test$(EXEEXT): $(exclude_libs_test_OBJECTS) $(exclude_libs_test_DEPENDENCIES)
+ @rm -f exclude_libs_test$(EXEEXT)
+ $(exclude_libs_test_LINK) $(exclude_libs_test_OBJECTS) $(exclude_libs_test_LDADD) $(LIBS)
+@GCC_FALSE@flagstest_compress_debug_sections$(EXEEXT): $(flagstest_compress_debug_sections_OBJECTS) $(flagstest_compress_debug_sections_DEPENDENCIES)
+@GCC_FALSE@ @rm -f flagstest_compress_debug_sections$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(flagstest_compress_debug_sections_OBJECTS) $(flagstest_compress_debug_sections_LDADD) $(LIBS)
+@HAVE_ZLIB_FALSE@flagstest_compress_debug_sections$(EXEEXT): $(flagstest_compress_debug_sections_OBJECTS) $(flagstest_compress_debug_sections_DEPENDENCIES)
+@HAVE_ZLIB_FALSE@ @rm -f flagstest_compress_debug_sections$(EXEEXT)
+@HAVE_ZLIB_FALSE@ $(LINK) $(flagstest_compress_debug_sections_OBJECTS) $(flagstest_compress_debug_sections_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@flagstest_compress_debug_sections$(EXEEXT): $(flagstest_compress_debug_sections_OBJECTS) $(flagstest_compress_debug_sections_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f flagstest_compress_debug_sections$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(flagstest_compress_debug_sections_OBJECTS) $(flagstest_compress_debug_sections_LDADD) $(LIBS)
+@GCC_FALSE@flagstest_o_specialfile$(EXEEXT): $(flagstest_o_specialfile_OBJECTS) $(flagstest_o_specialfile_DEPENDENCIES)
+@GCC_FALSE@ @rm -f flagstest_o_specialfile$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(flagstest_o_specialfile_OBJECTS) $(flagstest_o_specialfile_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@flagstest_o_specialfile$(EXEEXT): $(flagstest_o_specialfile_OBJECTS) $(flagstest_o_specialfile_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f flagstest_o_specialfile$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(flagstest_o_specialfile_OBJECTS) $(flagstest_o_specialfile_LDADD) $(LIBS)
+@GCC_FALSE@flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT): $(flagstest_o_specialfile_and_compress_debug_sections_OBJECTS) $(flagstest_o_specialfile_and_compress_debug_sections_DEPENDENCIES)
+@GCC_FALSE@ @rm -f flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(flagstest_o_specialfile_and_compress_debug_sections_OBJECTS) $(flagstest_o_specialfile_and_compress_debug_sections_LDADD) $(LIBS)
+@HAVE_ZLIB_FALSE@flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT): $(flagstest_o_specialfile_and_compress_debug_sections_OBJECTS) $(flagstest_o_specialfile_and_compress_debug_sections_DEPENDENCIES)
+@HAVE_ZLIB_FALSE@ @rm -f flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT)
+@HAVE_ZLIB_FALSE@ $(LINK) $(flagstest_o_specialfile_and_compress_debug_sections_OBJECTS) $(flagstest_o_specialfile_and_compress_debug_sections_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT): $(flagstest_o_specialfile_and_compress_debug_sections_OBJECTS) $(flagstest_o_specialfile_and_compress_debug_sections_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(flagstest_o_specialfile_and_compress_debug_sections_OBJECTS) $(flagstest_o_specialfile_and_compress_debug_sections_LDADD) $(LIBS)
+@GCC_FALSE@flagstest_o_ttext_1$(EXEEXT): $(flagstest_o_ttext_1_OBJECTS) $(flagstest_o_ttext_1_DEPENDENCIES)
+@GCC_FALSE@ @rm -f flagstest_o_ttext_1$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(flagstest_o_ttext_1_OBJECTS) $(flagstest_o_ttext_1_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@flagstest_o_ttext_1$(EXEEXT): $(flagstest_o_ttext_1_OBJECTS) $(flagstest_o_ttext_1_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f flagstest_o_ttext_1$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(flagstest_o_ttext_1_OBJECTS) $(flagstest_o_ttext_1_LDADD) $(LIBS)
+@GCC_FALSE@icf_virtual_function_folding_test$(EXEEXT): $(icf_virtual_function_folding_test_OBJECTS) $(icf_virtual_function_folding_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f icf_virtual_function_folding_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(icf_virtual_function_folding_test_OBJECTS) $(icf_virtual_function_folding_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@icf_virtual_function_folding_test$(EXEEXT): $(icf_virtual_function_folding_test_OBJECTS) $(icf_virtual_function_folding_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f icf_virtual_function_folding_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(icf_virtual_function_folding_test_OBJECTS) $(icf_virtual_function_folding_test_LDADD) $(LIBS)
+ifuncmain1$(EXEEXT): $(ifuncmain1_OBJECTS) $(ifuncmain1_DEPENDENCIES)
+ @rm -f ifuncmain1$(EXEEXT)
+ $(ifuncmain1_LINK) $(ifuncmain1_OBJECTS) $(ifuncmain1_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain1pic$(EXEEXT): $(ifuncmain1pic_OBJECTS) $(ifuncmain1pic_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain1pic$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain1pic_OBJECTS) $(ifuncmain1pic_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain1pic$(EXEEXT): $(ifuncmain1pic_OBJECTS) $(ifuncmain1pic_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain1pic$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain1pic_OBJECTS) $(ifuncmain1pic_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain1pic$(EXEEXT): $(ifuncmain1pic_OBJECTS) $(ifuncmain1pic_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain1pic$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain1pic_OBJECTS) $(ifuncmain1pic_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain1picstatic$(EXEEXT): $(ifuncmain1picstatic_OBJECTS) $(ifuncmain1picstatic_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain1picstatic$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain1picstatic_OBJECTS) $(ifuncmain1picstatic_LDADD) $(LIBS)
+@HAVE_STATIC_FALSE@ifuncmain1picstatic$(EXEEXT): $(ifuncmain1picstatic_OBJECTS) $(ifuncmain1picstatic_DEPENDENCIES)
+@HAVE_STATIC_FALSE@ @rm -f ifuncmain1picstatic$(EXEEXT)
+@HAVE_STATIC_FALSE@ $(LINK) $(ifuncmain1picstatic_OBJECTS) $(ifuncmain1picstatic_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain1picstatic$(EXEEXT): $(ifuncmain1picstatic_OBJECTS) $(ifuncmain1picstatic_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain1picstatic$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain1picstatic_OBJECTS) $(ifuncmain1picstatic_LDADD) $(LIBS)
+@IFUNC_STATIC_FALSE@ifuncmain1picstatic$(EXEEXT): $(ifuncmain1picstatic_OBJECTS) $(ifuncmain1picstatic_DEPENDENCIES)
+@IFUNC_STATIC_FALSE@ @rm -f ifuncmain1picstatic$(EXEEXT)
+@IFUNC_STATIC_FALSE@ $(LINK) $(ifuncmain1picstatic_OBJECTS) $(ifuncmain1picstatic_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain1picstatic$(EXEEXT): $(ifuncmain1picstatic_OBJECTS) $(ifuncmain1picstatic_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain1picstatic$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain1picstatic_OBJECTS) $(ifuncmain1picstatic_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain1pie$(EXEEXT): $(ifuncmain1pie_OBJECTS) $(ifuncmain1pie_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain1pie$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain1pie_OBJECTS) $(ifuncmain1pie_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain1pie$(EXEEXT): $(ifuncmain1pie_OBJECTS) $(ifuncmain1pie_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain1pie$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain1pie_OBJECTS) $(ifuncmain1pie_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain1pie$(EXEEXT): $(ifuncmain1pie_OBJECTS) $(ifuncmain1pie_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain1pie$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain1pie_OBJECTS) $(ifuncmain1pie_LDADD) $(LIBS)
+ifuncmain1static$(EXEEXT): $(ifuncmain1static_OBJECTS) $(ifuncmain1static_DEPENDENCIES)
+ @rm -f ifuncmain1static$(EXEEXT)
+ $(ifuncmain1static_LINK) $(ifuncmain1static_OBJECTS) $(ifuncmain1static_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain1staticpic$(EXEEXT): $(ifuncmain1staticpic_OBJECTS) $(ifuncmain1staticpic_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain1staticpic$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain1staticpic_OBJECTS) $(ifuncmain1staticpic_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain1staticpic$(EXEEXT): $(ifuncmain1staticpic_OBJECTS) $(ifuncmain1staticpic_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain1staticpic$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain1staticpic_OBJECTS) $(ifuncmain1staticpic_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain1staticpic$(EXEEXT): $(ifuncmain1staticpic_OBJECTS) $(ifuncmain1staticpic_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain1staticpic$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain1staticpic_OBJECTS) $(ifuncmain1staticpic_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain1staticpie$(EXEEXT): $(ifuncmain1staticpie_OBJECTS) $(ifuncmain1staticpie_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain1staticpie$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain1staticpie_OBJECTS) $(ifuncmain1staticpie_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain1staticpie$(EXEEXT): $(ifuncmain1staticpie_OBJECTS) $(ifuncmain1staticpie_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain1staticpie$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain1staticpie_OBJECTS) $(ifuncmain1staticpie_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain1staticpie$(EXEEXT): $(ifuncmain1staticpie_OBJECTS) $(ifuncmain1staticpie_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain1staticpie$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain1staticpie_OBJECTS) $(ifuncmain1staticpie_LDADD) $(LIBS)
+ifuncmain1vis$(EXEEXT): $(ifuncmain1vis_OBJECTS) $(ifuncmain1vis_DEPENDENCIES)
+ @rm -f ifuncmain1vis$(EXEEXT)
+ $(ifuncmain1vis_LINK) $(ifuncmain1vis_OBJECTS) $(ifuncmain1vis_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain1vispic$(EXEEXT): $(ifuncmain1vispic_OBJECTS) $(ifuncmain1vispic_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain1vispic$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain1vispic_OBJECTS) $(ifuncmain1vispic_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain1vispic$(EXEEXT): $(ifuncmain1vispic_OBJECTS) $(ifuncmain1vispic_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain1vispic$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain1vispic_OBJECTS) $(ifuncmain1vispic_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain1vispic$(EXEEXT): $(ifuncmain1vispic_OBJECTS) $(ifuncmain1vispic_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain1vispic$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain1vispic_OBJECTS) $(ifuncmain1vispic_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain1vispie$(EXEEXT): $(ifuncmain1vispie_OBJECTS) $(ifuncmain1vispie_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain1vispie$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain1vispie_OBJECTS) $(ifuncmain1vispie_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain1vispie$(EXEEXT): $(ifuncmain1vispie_OBJECTS) $(ifuncmain1vispie_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain1vispie$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain1vispie_OBJECTS) $(ifuncmain1vispie_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain1vispie$(EXEEXT): $(ifuncmain1vispie_OBJECTS) $(ifuncmain1vispie_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain1vispie$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain1vispie_OBJECTS) $(ifuncmain1vispie_LDADD) $(LIBS)
+ifuncmain2$(EXEEXT): $(ifuncmain2_OBJECTS) $(ifuncmain2_DEPENDENCIES)
+ @rm -f ifuncmain2$(EXEEXT)
+ $(ifuncmain2_LINK) $(ifuncmain2_OBJECTS) $(ifuncmain2_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain2pic$(EXEEXT): $(ifuncmain2pic_OBJECTS) $(ifuncmain2pic_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain2pic$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain2pic_OBJECTS) $(ifuncmain2pic_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain2pic$(EXEEXT): $(ifuncmain2pic_OBJECTS) $(ifuncmain2pic_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain2pic$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain2pic_OBJECTS) $(ifuncmain2pic_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain2pic$(EXEEXT): $(ifuncmain2pic_OBJECTS) $(ifuncmain2pic_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain2pic$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain2pic_OBJECTS) $(ifuncmain2pic_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain2picstatic$(EXEEXT): $(ifuncmain2picstatic_OBJECTS) $(ifuncmain2picstatic_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain2picstatic$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain2picstatic_OBJECTS) $(ifuncmain2picstatic_LDADD) $(LIBS)
+@HAVE_STATIC_FALSE@ifuncmain2picstatic$(EXEEXT): $(ifuncmain2picstatic_OBJECTS) $(ifuncmain2picstatic_DEPENDENCIES)
+@HAVE_STATIC_FALSE@ @rm -f ifuncmain2picstatic$(EXEEXT)
+@HAVE_STATIC_FALSE@ $(LINK) $(ifuncmain2picstatic_OBJECTS) $(ifuncmain2picstatic_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain2picstatic$(EXEEXT): $(ifuncmain2picstatic_OBJECTS) $(ifuncmain2picstatic_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain2picstatic$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain2picstatic_OBJECTS) $(ifuncmain2picstatic_LDADD) $(LIBS)
+@IFUNC_STATIC_FALSE@ifuncmain2picstatic$(EXEEXT): $(ifuncmain2picstatic_OBJECTS) $(ifuncmain2picstatic_DEPENDENCIES)
+@IFUNC_STATIC_FALSE@ @rm -f ifuncmain2picstatic$(EXEEXT)
+@IFUNC_STATIC_FALSE@ $(LINK) $(ifuncmain2picstatic_OBJECTS) $(ifuncmain2picstatic_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain2picstatic$(EXEEXT): $(ifuncmain2picstatic_OBJECTS) $(ifuncmain2picstatic_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain2picstatic$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain2picstatic_OBJECTS) $(ifuncmain2picstatic_LDADD) $(LIBS)
+ifuncmain2static$(EXEEXT): $(ifuncmain2static_OBJECTS) $(ifuncmain2static_DEPENDENCIES)
+ @rm -f ifuncmain2static$(EXEEXT)
+ $(ifuncmain2static_LINK) $(ifuncmain2static_OBJECTS) $(ifuncmain2static_LDADD) $(LIBS)
+ifuncmain3$(EXEEXT): $(ifuncmain3_OBJECTS) $(ifuncmain3_DEPENDENCIES)
+ @rm -f ifuncmain3$(EXEEXT)
+ $(ifuncmain3_LINK) $(ifuncmain3_OBJECTS) $(ifuncmain3_LDADD) $(LIBS)
+ifuncmain4$(EXEEXT): $(ifuncmain4_OBJECTS) $(ifuncmain4_DEPENDENCIES)
+ @rm -f ifuncmain4$(EXEEXT)
+ $(ifuncmain4_LINK) $(ifuncmain4_OBJECTS) $(ifuncmain4_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain4picstatic$(EXEEXT): $(ifuncmain4picstatic_OBJECTS) $(ifuncmain4picstatic_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain4picstatic$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain4picstatic_OBJECTS) $(ifuncmain4picstatic_LDADD) $(LIBS)
+@HAVE_STATIC_FALSE@ifuncmain4picstatic$(EXEEXT): $(ifuncmain4picstatic_OBJECTS) $(ifuncmain4picstatic_DEPENDENCIES)
+@HAVE_STATIC_FALSE@ @rm -f ifuncmain4picstatic$(EXEEXT)
+@HAVE_STATIC_FALSE@ $(LINK) $(ifuncmain4picstatic_OBJECTS) $(ifuncmain4picstatic_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain4picstatic$(EXEEXT): $(ifuncmain4picstatic_OBJECTS) $(ifuncmain4picstatic_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain4picstatic$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain4picstatic_OBJECTS) $(ifuncmain4picstatic_LDADD) $(LIBS)
+@IFUNC_STATIC_FALSE@ifuncmain4picstatic$(EXEEXT): $(ifuncmain4picstatic_OBJECTS) $(ifuncmain4picstatic_DEPENDENCIES)
+@IFUNC_STATIC_FALSE@ @rm -f ifuncmain4picstatic$(EXEEXT)
+@IFUNC_STATIC_FALSE@ $(LINK) $(ifuncmain4picstatic_OBJECTS) $(ifuncmain4picstatic_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain4picstatic$(EXEEXT): $(ifuncmain4picstatic_OBJECTS) $(ifuncmain4picstatic_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain4picstatic$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain4picstatic_OBJECTS) $(ifuncmain4picstatic_LDADD) $(LIBS)
+ifuncmain4static$(EXEEXT): $(ifuncmain4static_OBJECTS) $(ifuncmain4static_DEPENDENCIES)
+ @rm -f ifuncmain4static$(EXEEXT)
+ $(ifuncmain4static_LINK) $(ifuncmain4static_OBJECTS) $(ifuncmain4static_LDADD) $(LIBS)
+ifuncmain5$(EXEEXT): $(ifuncmain5_OBJECTS) $(ifuncmain5_DEPENDENCIES)
+ @rm -f ifuncmain5$(EXEEXT)
+ $(ifuncmain5_LINK) $(ifuncmain5_OBJECTS) $(ifuncmain5_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain5pic$(EXEEXT): $(ifuncmain5pic_OBJECTS) $(ifuncmain5pic_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain5pic$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain5pic_OBJECTS) $(ifuncmain5pic_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain5pic$(EXEEXT): $(ifuncmain5pic_OBJECTS) $(ifuncmain5pic_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain5pic$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain5pic_OBJECTS) $(ifuncmain5pic_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain5pic$(EXEEXT): $(ifuncmain5pic_OBJECTS) $(ifuncmain5pic_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain5pic$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain5pic_OBJECTS) $(ifuncmain5pic_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain5picstatic$(EXEEXT): $(ifuncmain5picstatic_OBJECTS) $(ifuncmain5picstatic_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain5picstatic$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain5picstatic_OBJECTS) $(ifuncmain5picstatic_LDADD) $(LIBS)
+@HAVE_STATIC_FALSE@ifuncmain5picstatic$(EXEEXT): $(ifuncmain5picstatic_OBJECTS) $(ifuncmain5picstatic_DEPENDENCIES)
+@HAVE_STATIC_FALSE@ @rm -f ifuncmain5picstatic$(EXEEXT)
+@HAVE_STATIC_FALSE@ $(LINK) $(ifuncmain5picstatic_OBJECTS) $(ifuncmain5picstatic_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain5picstatic$(EXEEXT): $(ifuncmain5picstatic_OBJECTS) $(ifuncmain5picstatic_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain5picstatic$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain5picstatic_OBJECTS) $(ifuncmain5picstatic_LDADD) $(LIBS)
+@IFUNC_STATIC_FALSE@ifuncmain5picstatic$(EXEEXT): $(ifuncmain5picstatic_OBJECTS) $(ifuncmain5picstatic_DEPENDENCIES)
+@IFUNC_STATIC_FALSE@ @rm -f ifuncmain5picstatic$(EXEEXT)
+@IFUNC_STATIC_FALSE@ $(LINK) $(ifuncmain5picstatic_OBJECTS) $(ifuncmain5picstatic_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain5picstatic$(EXEEXT): $(ifuncmain5picstatic_OBJECTS) $(ifuncmain5picstatic_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain5picstatic$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain5picstatic_OBJECTS) $(ifuncmain5picstatic_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain5pie$(EXEEXT): $(ifuncmain5pie_OBJECTS) $(ifuncmain5pie_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain5pie$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain5pie_OBJECTS) $(ifuncmain5pie_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain5pie$(EXEEXT): $(ifuncmain5pie_OBJECTS) $(ifuncmain5pie_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain5pie$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain5pie_OBJECTS) $(ifuncmain5pie_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain5pie$(EXEEXT): $(ifuncmain5pie_OBJECTS) $(ifuncmain5pie_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain5pie$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain5pie_OBJECTS) $(ifuncmain5pie_LDADD) $(LIBS)
+ifuncmain5static$(EXEEXT): $(ifuncmain5static_OBJECTS) $(ifuncmain5static_DEPENDENCIES)
+ @rm -f ifuncmain5static$(EXEEXT)
+ $(ifuncmain5static_LINK) $(ifuncmain5static_OBJECTS) $(ifuncmain5static_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain5staticpic$(EXEEXT): $(ifuncmain5staticpic_OBJECTS) $(ifuncmain5staticpic_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain5staticpic$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain5staticpic_OBJECTS) $(ifuncmain5staticpic_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain5staticpic$(EXEEXT): $(ifuncmain5staticpic_OBJECTS) $(ifuncmain5staticpic_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain5staticpic$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain5staticpic_OBJECTS) $(ifuncmain5staticpic_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain5staticpic$(EXEEXT): $(ifuncmain5staticpic_OBJECTS) $(ifuncmain5staticpic_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain5staticpic$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain5staticpic_OBJECTS) $(ifuncmain5staticpic_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain6pie$(EXEEXT): $(ifuncmain6pie_OBJECTS) $(ifuncmain6pie_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain6pie$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain6pie_OBJECTS) $(ifuncmain6pie_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain6pie$(EXEEXT): $(ifuncmain6pie_OBJECTS) $(ifuncmain6pie_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain6pie$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain6pie_OBJECTS) $(ifuncmain6pie_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain6pie$(EXEEXT): $(ifuncmain6pie_OBJECTS) $(ifuncmain6pie_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain6pie$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain6pie_OBJECTS) $(ifuncmain6pie_LDADD) $(LIBS)
+ifuncmain7$(EXEEXT): $(ifuncmain7_OBJECTS) $(ifuncmain7_DEPENDENCIES)
+ @rm -f ifuncmain7$(EXEEXT)
+ $(ifuncmain7_LINK) $(ifuncmain7_OBJECTS) $(ifuncmain7_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain7pic$(EXEEXT): $(ifuncmain7pic_OBJECTS) $(ifuncmain7pic_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain7pic$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain7pic_OBJECTS) $(ifuncmain7pic_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain7pic$(EXEEXT): $(ifuncmain7pic_OBJECTS) $(ifuncmain7pic_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain7pic$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain7pic_OBJECTS) $(ifuncmain7pic_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain7pic$(EXEEXT): $(ifuncmain7pic_OBJECTS) $(ifuncmain7pic_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain7pic$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain7pic_OBJECTS) $(ifuncmain7pic_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain7picstatic$(EXEEXT): $(ifuncmain7picstatic_OBJECTS) $(ifuncmain7picstatic_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain7picstatic$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain7picstatic_OBJECTS) $(ifuncmain7picstatic_LDADD) $(LIBS)
+@HAVE_STATIC_FALSE@ifuncmain7picstatic$(EXEEXT): $(ifuncmain7picstatic_OBJECTS) $(ifuncmain7picstatic_DEPENDENCIES)
+@HAVE_STATIC_FALSE@ @rm -f ifuncmain7picstatic$(EXEEXT)
+@HAVE_STATIC_FALSE@ $(LINK) $(ifuncmain7picstatic_OBJECTS) $(ifuncmain7picstatic_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain7picstatic$(EXEEXT): $(ifuncmain7picstatic_OBJECTS) $(ifuncmain7picstatic_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain7picstatic$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain7picstatic_OBJECTS) $(ifuncmain7picstatic_LDADD) $(LIBS)
+@IFUNC_STATIC_FALSE@ifuncmain7picstatic$(EXEEXT): $(ifuncmain7picstatic_OBJECTS) $(ifuncmain7picstatic_DEPENDENCIES)
+@IFUNC_STATIC_FALSE@ @rm -f ifuncmain7picstatic$(EXEEXT)
+@IFUNC_STATIC_FALSE@ $(LINK) $(ifuncmain7picstatic_OBJECTS) $(ifuncmain7picstatic_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain7picstatic$(EXEEXT): $(ifuncmain7picstatic_OBJECTS) $(ifuncmain7picstatic_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain7picstatic$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain7picstatic_OBJECTS) $(ifuncmain7picstatic_LDADD) $(LIBS)
+@GCC_FALSE@ifuncmain7pie$(EXEEXT): $(ifuncmain7pie_OBJECTS) $(ifuncmain7pie_DEPENDENCIES)
+@GCC_FALSE@ @rm -f ifuncmain7pie$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(ifuncmain7pie_OBJECTS) $(ifuncmain7pie_LDADD) $(LIBS)
+@IFUNC_FALSE@ifuncmain7pie$(EXEEXT): $(ifuncmain7pie_OBJECTS) $(ifuncmain7pie_DEPENDENCIES)
+@IFUNC_FALSE@ @rm -f ifuncmain7pie$(EXEEXT)
+@IFUNC_FALSE@ $(LINK) $(ifuncmain7pie_OBJECTS) $(ifuncmain7pie_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@ifuncmain7pie$(EXEEXT): $(ifuncmain7pie_OBJECTS) $(ifuncmain7pie_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f ifuncmain7pie$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(ifuncmain7pie_OBJECTS) $(ifuncmain7pie_LDADD) $(LIBS)
+ifuncmain7static$(EXEEXT): $(ifuncmain7static_OBJECTS) $(ifuncmain7static_DEPENDENCIES)
+ @rm -f ifuncmain7static$(EXEEXT)
+ $(ifuncmain7static_LINK) $(ifuncmain7static_OBJECTS) $(ifuncmain7static_LDADD) $(LIBS)
+ifuncvar$(EXEEXT): $(ifuncvar_OBJECTS) $(ifuncvar_DEPENDENCIES)
+ @rm -f ifuncvar$(EXEEXT)
+ $(ifuncvar_LINK) $(ifuncvar_OBJECTS) $(ifuncvar_LDADD) $(LIBS)
+@DEFAULT_TARGET_X86_64_FALSE@incremental_comdat_test_1$(EXEEXT): $(incremental_comdat_test_1_OBJECTS) $(incremental_comdat_test_1_DEPENDENCIES)
+@DEFAULT_TARGET_X86_64_FALSE@ @rm -f incremental_comdat_test_1$(EXEEXT)
+@DEFAULT_TARGET_X86_64_FALSE@ $(LINK) $(incremental_comdat_test_1_OBJECTS) $(incremental_comdat_test_1_LDADD) $(LIBS)
+@GCC_FALSE@incremental_comdat_test_1$(EXEEXT): $(incremental_comdat_test_1_OBJECTS) $(incremental_comdat_test_1_DEPENDENCIES)
+@GCC_FALSE@ @rm -f incremental_comdat_test_1$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(incremental_comdat_test_1_OBJECTS) $(incremental_comdat_test_1_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@incremental_comdat_test_1$(EXEEXT): $(incremental_comdat_test_1_OBJECTS) $(incremental_comdat_test_1_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f incremental_comdat_test_1$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(incremental_comdat_test_1_OBJECTS) $(incremental_comdat_test_1_LDADD) $(LIBS)
+@DEFAULT_TARGET_X86_64_FALSE@incremental_common_test_1$(EXEEXT): $(incremental_common_test_1_OBJECTS) $(incremental_common_test_1_DEPENDENCIES)
+@DEFAULT_TARGET_X86_64_FALSE@ @rm -f incremental_common_test_1$(EXEEXT)
+@DEFAULT_TARGET_X86_64_FALSE@ $(LINK) $(incremental_common_test_1_OBJECTS) $(incremental_common_test_1_LDADD) $(LIBS)
+@GCC_FALSE@incremental_common_test_1$(EXEEXT): $(incremental_common_test_1_OBJECTS) $(incremental_common_test_1_DEPENDENCIES)
+@GCC_FALSE@ @rm -f incremental_common_test_1$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(incremental_common_test_1_OBJECTS) $(incremental_common_test_1_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@incremental_common_test_1$(EXEEXT): $(incremental_common_test_1_OBJECTS) $(incremental_common_test_1_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f incremental_common_test_1$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(incremental_common_test_1_OBJECTS) $(incremental_common_test_1_LDADD) $(LIBS)
+@DEFAULT_TARGET_X86_64_FALSE@incremental_copy_test$(EXEEXT): $(incremental_copy_test_OBJECTS) $(incremental_copy_test_DEPENDENCIES)
+@DEFAULT_TARGET_X86_64_FALSE@ @rm -f incremental_copy_test$(EXEEXT)
+@DEFAULT_TARGET_X86_64_FALSE@ $(LINK) $(incremental_copy_test_OBJECTS) $(incremental_copy_test_LDADD) $(LIBS)
+@GCC_FALSE@incremental_copy_test$(EXEEXT): $(incremental_copy_test_OBJECTS) $(incremental_copy_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f incremental_copy_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(incremental_copy_test_OBJECTS) $(incremental_copy_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@incremental_copy_test$(EXEEXT): $(incremental_copy_test_OBJECTS) $(incremental_copy_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f incremental_copy_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(incremental_copy_test_OBJECTS) $(incremental_copy_test_LDADD) $(LIBS)
+@DEFAULT_TARGET_X86_64_FALSE@incremental_test_2$(EXEEXT): $(incremental_test_2_OBJECTS) $(incremental_test_2_DEPENDENCIES)
+@DEFAULT_TARGET_X86_64_FALSE@ @rm -f incremental_test_2$(EXEEXT)
+@DEFAULT_TARGET_X86_64_FALSE@ $(LINK) $(incremental_test_2_OBJECTS) $(incremental_test_2_LDADD) $(LIBS)
+@GCC_FALSE@incremental_test_2$(EXEEXT): $(incremental_test_2_OBJECTS) $(incremental_test_2_DEPENDENCIES)
+@GCC_FALSE@ @rm -f incremental_test_2$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(incremental_test_2_OBJECTS) $(incremental_test_2_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@incremental_test_2$(EXEEXT): $(incremental_test_2_OBJECTS) $(incremental_test_2_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f incremental_test_2$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(incremental_test_2_OBJECTS) $(incremental_test_2_LDADD) $(LIBS)
+@DEFAULT_TARGET_X86_64_FALSE@incremental_test_3$(EXEEXT): $(incremental_test_3_OBJECTS) $(incremental_test_3_DEPENDENCIES)
+@DEFAULT_TARGET_X86_64_FALSE@ @rm -f incremental_test_3$(EXEEXT)
+@DEFAULT_TARGET_X86_64_FALSE@ $(LINK) $(incremental_test_3_OBJECTS) $(incremental_test_3_LDADD) $(LIBS)
+@GCC_FALSE@incremental_test_3$(EXEEXT): $(incremental_test_3_OBJECTS) $(incremental_test_3_DEPENDENCIES)
+@GCC_FALSE@ @rm -f incremental_test_3$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(incremental_test_3_OBJECTS) $(incremental_test_3_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@incremental_test_3$(EXEEXT): $(incremental_test_3_OBJECTS) $(incremental_test_3_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f incremental_test_3$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(incremental_test_3_OBJECTS) $(incremental_test_3_LDADD) $(LIBS)
+@DEFAULT_TARGET_X86_64_FALSE@incremental_test_4$(EXEEXT): $(incremental_test_4_OBJECTS) $(incremental_test_4_DEPENDENCIES)
+@DEFAULT_TARGET_X86_64_FALSE@ @rm -f incremental_test_4$(EXEEXT)
+@DEFAULT_TARGET_X86_64_FALSE@ $(LINK) $(incremental_test_4_OBJECTS) $(incremental_test_4_LDADD) $(LIBS)
+@GCC_FALSE@incremental_test_4$(EXEEXT): $(incremental_test_4_OBJECTS) $(incremental_test_4_DEPENDENCIES)
+@GCC_FALSE@ @rm -f incremental_test_4$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(incremental_test_4_OBJECTS) $(incremental_test_4_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@incremental_test_4$(EXEEXT): $(incremental_test_4_OBJECTS) $(incremental_test_4_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f incremental_test_4$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(incremental_test_4_OBJECTS) $(incremental_test_4_LDADD) $(LIBS)
+@DEFAULT_TARGET_X86_64_FALSE@incremental_test_5$(EXEEXT): $(incremental_test_5_OBJECTS) $(incremental_test_5_DEPENDENCIES)
+@DEFAULT_TARGET_X86_64_FALSE@ @rm -f incremental_test_5$(EXEEXT)
+@DEFAULT_TARGET_X86_64_FALSE@ $(LINK) $(incremental_test_5_OBJECTS) $(incremental_test_5_LDADD) $(LIBS)
+@GCC_FALSE@incremental_test_5$(EXEEXT): $(incremental_test_5_OBJECTS) $(incremental_test_5_DEPENDENCIES)
+@GCC_FALSE@ @rm -f incremental_test_5$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(incremental_test_5_OBJECTS) $(incremental_test_5_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@incremental_test_5$(EXEEXT): $(incremental_test_5_OBJECTS) $(incremental_test_5_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f incremental_test_5$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(incremental_test_5_OBJECTS) $(incremental_test_5_LDADD) $(LIBS)
+@DEFAULT_TARGET_X86_64_FALSE@incremental_test_6$(EXEEXT): $(incremental_test_6_OBJECTS) $(incremental_test_6_DEPENDENCIES)
+@DEFAULT_TARGET_X86_64_FALSE@ @rm -f incremental_test_6$(EXEEXT)
+@DEFAULT_TARGET_X86_64_FALSE@ $(LINK) $(incremental_test_6_OBJECTS) $(incremental_test_6_LDADD) $(LIBS)
+@GCC_FALSE@incremental_test_6$(EXEEXT): $(incremental_test_6_OBJECTS) $(incremental_test_6_DEPENDENCIES)
+@GCC_FALSE@ @rm -f incremental_test_6$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(incremental_test_6_OBJECTS) $(incremental_test_6_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@incremental_test_6$(EXEEXT): $(incremental_test_6_OBJECTS) $(incremental_test_6_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f incremental_test_6$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(incremental_test_6_OBJECTS) $(incremental_test_6_LDADD) $(LIBS)
+initpri1$(EXEEXT): $(initpri1_OBJECTS) $(initpri1_DEPENDENCIES)
+ @rm -f initpri1$(EXEEXT)
+ $(initpri1_LINK) $(initpri1_OBJECTS) $(initpri1_LDADD) $(LIBS)
+initpri2$(EXEEXT): $(initpri2_OBJECTS) $(initpri2_DEPENDENCIES)
+ @rm -f initpri2$(EXEEXT)
+ $(initpri2_LINK) $(initpri2_OBJECTS) $(initpri2_LDADD) $(LIBS)
+initpri3a$(EXEEXT): $(initpri3a_OBJECTS) $(initpri3a_DEPENDENCIES)
+ @rm -f initpri3a$(EXEEXT)
+ $(initpri3a_LINK) $(initpri3a_OBJECTS) $(initpri3a_LDADD) $(LIBS)
+justsyms$(EXEEXT): $(justsyms_OBJECTS) $(justsyms_DEPENDENCIES)
+ @rm -f justsyms$(EXEEXT)
+ $(justsyms_LINK) $(justsyms_OBJECTS) $(justsyms_LDADD) $(LIBS)
+justsyms_exec$(EXEEXT): $(justsyms_exec_OBJECTS) $(justsyms_exec_DEPENDENCIES)
+ @rm -f justsyms_exec$(EXEEXT)
+ $(justsyms_exec_LINK) $(justsyms_exec_OBJECTS) $(justsyms_exec_LDADD) $(LIBS)
+large$(EXEEXT): $(large_OBJECTS) $(large_DEPENDENCIES)
+ @rm -f large$(EXEEXT)
+ $(large_LINK) $(large_OBJECTS) $(large_LDADD) $(LIBS)
+large_symbol_alignment$(EXEEXT): $(large_symbol_alignment_OBJECTS) $(large_symbol_alignment_DEPENDENCIES)
+ @rm -f large_symbol_alignment$(EXEEXT)
+ $(large_symbol_alignment_LINK) $(large_symbol_alignment_OBJECTS) $(large_symbol_alignment_LDADD) $(LIBS)
+leb128_unittest$(EXEEXT): $(leb128_unittest_OBJECTS) $(leb128_unittest_DEPENDENCIES)
+ @rm -f leb128_unittest$(EXEEXT)
+ $(CXXLINK) $(leb128_unittest_OBJECTS) $(leb128_unittest_LDADD) $(LIBS)
+@GCC_FALSE@local_labels_test$(EXEEXT): $(local_labels_test_OBJECTS) $(local_labels_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f local_labels_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(local_labels_test_OBJECTS) $(local_labels_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@local_labels_test$(EXEEXT): $(local_labels_test_OBJECTS) $(local_labels_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f local_labels_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(local_labels_test_OBJECTS) $(local_labels_test_LDADD) $(LIBS)
+@GCC_FALSE@many_sections_r_test$(EXEEXT): $(many_sections_r_test_OBJECTS) $(many_sections_r_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f many_sections_r_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(many_sections_r_test_OBJECTS) $(many_sections_r_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@many_sections_r_test$(EXEEXT): $(many_sections_r_test_OBJECTS) $(many_sections_r_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f many_sections_r_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(many_sections_r_test_OBJECTS) $(many_sections_r_test_LDADD) $(LIBS)
+many_sections_test$(EXEEXT): $(many_sections_test_OBJECTS) $(many_sections_test_DEPENDENCIES)
+ @rm -f many_sections_test$(EXEEXT)
+ $(many_sections_test_LINK) $(many_sections_test_OBJECTS) $(many_sections_test_LDADD) $(LIBS)
+object_unittest$(EXEEXT): $(object_unittest_OBJECTS) $(object_unittest_DEPENDENCIES)
+ @rm -f object_unittest$(EXEEXT)
+ $(CXXLINK) $(object_unittest_OBJECTS) $(object_unittest_LDADD) $(LIBS)
+@GCC_FALSE@permission_test$(EXEEXT): $(permission_test_OBJECTS) $(permission_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f permission_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(permission_test_OBJECTS) $(permission_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@permission_test$(EXEEXT): $(permission_test_OBJECTS) $(permission_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f permission_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(permission_test_OBJECTS) $(permission_test_LDADD) $(LIBS)
+@GCC_FALSE@plugin_test_1$(EXEEXT): $(plugin_test_1_OBJECTS) $(plugin_test_1_DEPENDENCIES)
+@GCC_FALSE@ @rm -f plugin_test_1$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(plugin_test_1_OBJECTS) $(plugin_test_1_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@plugin_test_1$(EXEEXT): $(plugin_test_1_OBJECTS) $(plugin_test_1_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f plugin_test_1$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(plugin_test_1_OBJECTS) $(plugin_test_1_LDADD) $(LIBS)
+@PLUGINS_FALSE@plugin_test_1$(EXEEXT): $(plugin_test_1_OBJECTS) $(plugin_test_1_DEPENDENCIES)
+@PLUGINS_FALSE@ @rm -f plugin_test_1$(EXEEXT)
+@PLUGINS_FALSE@ $(LINK) $(plugin_test_1_OBJECTS) $(plugin_test_1_LDADD) $(LIBS)
+@GCC_FALSE@plugin_test_2$(EXEEXT): $(plugin_test_2_OBJECTS) $(plugin_test_2_DEPENDENCIES)
+@GCC_FALSE@ @rm -f plugin_test_2$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(plugin_test_2_OBJECTS) $(plugin_test_2_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@plugin_test_2$(EXEEXT): $(plugin_test_2_OBJECTS) $(plugin_test_2_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f plugin_test_2$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(plugin_test_2_OBJECTS) $(plugin_test_2_LDADD) $(LIBS)
+@PLUGINS_FALSE@plugin_test_2$(EXEEXT): $(plugin_test_2_OBJECTS) $(plugin_test_2_DEPENDENCIES)
+@PLUGINS_FALSE@ @rm -f plugin_test_2$(EXEEXT)
+@PLUGINS_FALSE@ $(LINK) $(plugin_test_2_OBJECTS) $(plugin_test_2_LDADD) $(LIBS)
+@GCC_FALSE@plugin_test_3$(EXEEXT): $(plugin_test_3_OBJECTS) $(plugin_test_3_DEPENDENCIES)
+@GCC_FALSE@ @rm -f plugin_test_3$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(plugin_test_3_OBJECTS) $(plugin_test_3_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@plugin_test_3$(EXEEXT): $(plugin_test_3_OBJECTS) $(plugin_test_3_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f plugin_test_3$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(plugin_test_3_OBJECTS) $(plugin_test_3_LDADD) $(LIBS)
+@PLUGINS_FALSE@plugin_test_3$(EXEEXT): $(plugin_test_3_OBJECTS) $(plugin_test_3_DEPENDENCIES)
+@PLUGINS_FALSE@ @rm -f plugin_test_3$(EXEEXT)
+@PLUGINS_FALSE@ $(LINK) $(plugin_test_3_OBJECTS) $(plugin_test_3_LDADD) $(LIBS)
+@GCC_FALSE@plugin_test_4$(EXEEXT): $(plugin_test_4_OBJECTS) $(plugin_test_4_DEPENDENCIES)
+@GCC_FALSE@ @rm -f plugin_test_4$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(plugin_test_4_OBJECTS) $(plugin_test_4_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@plugin_test_4$(EXEEXT): $(plugin_test_4_OBJECTS) $(plugin_test_4_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f plugin_test_4$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(plugin_test_4_OBJECTS) $(plugin_test_4_LDADD) $(LIBS)
+@PLUGINS_FALSE@plugin_test_4$(EXEEXT): $(plugin_test_4_OBJECTS) $(plugin_test_4_DEPENDENCIES)
+@PLUGINS_FALSE@ @rm -f plugin_test_4$(EXEEXT)
+@PLUGINS_FALSE@ $(LINK) $(plugin_test_4_OBJECTS) $(plugin_test_4_LDADD) $(LIBS)
+@GCC_FALSE@plugin_test_5$(EXEEXT): $(plugin_test_5_OBJECTS) $(plugin_test_5_DEPENDENCIES)
+@GCC_FALSE@ @rm -f plugin_test_5$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(plugin_test_5_OBJECTS) $(plugin_test_5_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@plugin_test_5$(EXEEXT): $(plugin_test_5_OBJECTS) $(plugin_test_5_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f plugin_test_5$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(plugin_test_5_OBJECTS) $(plugin_test_5_LDADD) $(LIBS)
+@PLUGINS_FALSE@plugin_test_5$(EXEEXT): $(plugin_test_5_OBJECTS) $(plugin_test_5_DEPENDENCIES)
+@PLUGINS_FALSE@ @rm -f plugin_test_5$(EXEEXT)
+@PLUGINS_FALSE@ $(LINK) $(plugin_test_5_OBJECTS) $(plugin_test_5_LDADD) $(LIBS)
+@GCC_FALSE@plugin_test_6$(EXEEXT): $(plugin_test_6_OBJECTS) $(plugin_test_6_DEPENDENCIES)
+@GCC_FALSE@ @rm -f plugin_test_6$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(plugin_test_6_OBJECTS) $(plugin_test_6_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@plugin_test_6$(EXEEXT): $(plugin_test_6_OBJECTS) $(plugin_test_6_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f plugin_test_6$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(plugin_test_6_OBJECTS) $(plugin_test_6_LDADD) $(LIBS)
+@PLUGINS_FALSE@plugin_test_6$(EXEEXT): $(plugin_test_6_OBJECTS) $(plugin_test_6_DEPENDENCIES)
+@PLUGINS_FALSE@ @rm -f plugin_test_6$(EXEEXT)
+@PLUGINS_FALSE@ $(LINK) $(plugin_test_6_OBJECTS) $(plugin_test_6_LDADD) $(LIBS)
+@GCC_FALSE@plugin_test_7$(EXEEXT): $(plugin_test_7_OBJECTS) $(plugin_test_7_DEPENDENCIES)
+@GCC_FALSE@ @rm -f plugin_test_7$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(plugin_test_7_OBJECTS) $(plugin_test_7_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@plugin_test_7$(EXEEXT): $(plugin_test_7_OBJECTS) $(plugin_test_7_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f plugin_test_7$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(plugin_test_7_OBJECTS) $(plugin_test_7_LDADD) $(LIBS)
+@PLUGINS_FALSE@plugin_test_7$(EXEEXT): $(plugin_test_7_OBJECTS) $(plugin_test_7_DEPENDENCIES)
+@PLUGINS_FALSE@ @rm -f plugin_test_7$(EXEEXT)
+@PLUGINS_FALSE@ $(LINK) $(plugin_test_7_OBJECTS) $(plugin_test_7_LDADD) $(LIBS)
+@GCC_FALSE@plugin_test_8$(EXEEXT): $(plugin_test_8_OBJECTS) $(plugin_test_8_DEPENDENCIES)
+@GCC_FALSE@ @rm -f plugin_test_8$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(plugin_test_8_OBJECTS) $(plugin_test_8_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@plugin_test_8$(EXEEXT): $(plugin_test_8_OBJECTS) $(plugin_test_8_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f plugin_test_8$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(plugin_test_8_OBJECTS) $(plugin_test_8_LDADD) $(LIBS)
+@PLUGINS_FALSE@plugin_test_8$(EXEEXT): $(plugin_test_8_OBJECTS) $(plugin_test_8_DEPENDENCIES)
+@PLUGINS_FALSE@ @rm -f plugin_test_8$(EXEEXT)
+@PLUGINS_FALSE@ $(LINK) $(plugin_test_8_OBJECTS) $(plugin_test_8_LDADD) $(LIBS)
+@GCC_FALSE@plugin_test_tls$(EXEEXT): $(plugin_test_tls_OBJECTS) $(plugin_test_tls_DEPENDENCIES)
+@GCC_FALSE@ @rm -f plugin_test_tls$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(plugin_test_tls_OBJECTS) $(plugin_test_tls_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@plugin_test_tls$(EXEEXT): $(plugin_test_tls_OBJECTS) $(plugin_test_tls_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f plugin_test_tls$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(plugin_test_tls_OBJECTS) $(plugin_test_tls_LDADD) $(LIBS)
+@PLUGINS_FALSE@plugin_test_tls$(EXEEXT): $(plugin_test_tls_OBJECTS) $(plugin_test_tls_DEPENDENCIES)
+@PLUGINS_FALSE@ @rm -f plugin_test_tls$(EXEEXT)
+@PLUGINS_FALSE@ $(LINK) $(plugin_test_tls_OBJECTS) $(plugin_test_tls_LDADD) $(LIBS)
+@TLS_FALSE@plugin_test_tls$(EXEEXT): $(plugin_test_tls_OBJECTS) $(plugin_test_tls_DEPENDENCIES)
+@TLS_FALSE@ @rm -f plugin_test_tls$(EXEEXT)
+@TLS_FALSE@ $(LINK) $(plugin_test_tls_OBJECTS) $(plugin_test_tls_LDADD) $(LIBS)
+protected_1$(EXEEXT): $(protected_1_OBJECTS) $(protected_1_DEPENDENCIES)
+ @rm -f protected_1$(EXEEXT)
+ $(protected_1_LINK) $(protected_1_OBJECTS) $(protected_1_LDADD) $(LIBS)
+protected_2$(EXEEXT): $(protected_2_OBJECTS) $(protected_2_DEPENDENCIES)
+ @rm -f protected_2$(EXEEXT)
+ $(protected_2_LINK) $(protected_2_OBJECTS) $(protected_2_LDADD) $(LIBS)
+relro_now_test$(EXEEXT): $(relro_now_test_OBJECTS) $(relro_now_test_DEPENDENCIES)
+ @rm -f relro_now_test$(EXEEXT)
+ $(relro_now_test_LINK) $(relro_now_test_OBJECTS) $(relro_now_test_LDADD) $(LIBS)
+relro_script_test$(EXEEXT): $(relro_script_test_OBJECTS) $(relro_script_test_DEPENDENCIES)
+ @rm -f relro_script_test$(EXEEXT)
+ $(relro_script_test_LINK) $(relro_script_test_OBJECTS) $(relro_script_test_LDADD) $(LIBS)
+relro_strip_test$(EXEEXT): $(relro_strip_test_OBJECTS) $(relro_strip_test_DEPENDENCIES)
+ @rm -f relro_strip_test$(EXEEXT)
+ $(relro_strip_test_LINK) $(relro_strip_test_OBJECTS) $(relro_strip_test_LDADD) $(LIBS)
+relro_test$(EXEEXT): $(relro_test_OBJECTS) $(relro_test_DEPENDENCIES)
+ @rm -f relro_test$(EXEEXT)
+ $(relro_test_LINK) $(relro_test_OBJECTS) $(relro_test_LDADD) $(LIBS)
+script_test_1$(EXEEXT): $(script_test_1_OBJECTS) $(script_test_1_DEPENDENCIES)
+ @rm -f script_test_1$(EXEEXT)
+ $(script_test_1_LINK) $(script_test_1_OBJECTS) $(script_test_1_LDADD) $(LIBS)
+@GCC_FALSE@script_test_11$(EXEEXT): $(script_test_11_OBJECTS) $(script_test_11_DEPENDENCIES)
+@GCC_FALSE@ @rm -f script_test_11$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(script_test_11_OBJECTS) $(script_test_11_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@script_test_11$(EXEEXT): $(script_test_11_OBJECTS) $(script_test_11_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f script_test_11$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(script_test_11_OBJECTS) $(script_test_11_LDADD) $(LIBS)
+script_test_2$(EXEEXT): $(script_test_2_OBJECTS) $(script_test_2_DEPENDENCIES)
+ @rm -f script_test_2$(EXEEXT)
+ $(script_test_2_LINK) $(script_test_2_OBJECTS) $(script_test_2_LDADD) $(LIBS)
+@GCC_FALSE@script_test_3$(EXEEXT): $(script_test_3_OBJECTS) $(script_test_3_DEPENDENCIES)
+@GCC_FALSE@ @rm -f script_test_3$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(script_test_3_OBJECTS) $(script_test_3_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@script_test_3$(EXEEXT): $(script_test_3_OBJECTS) $(script_test_3_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f script_test_3$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(script_test_3_OBJECTS) $(script_test_3_LDADD) $(LIBS)
+searched_file_test$(EXEEXT): $(searched_file_test_OBJECTS) $(searched_file_test_DEPENDENCIES)
+ @rm -f searched_file_test$(EXEEXT)
+ $(searched_file_test_LINK) $(searched_file_test_OBJECTS) $(searched_file_test_LDADD) $(LIBS)
+@GCC_FALSE@start_lib_test$(EXEEXT): $(start_lib_test_OBJECTS) $(start_lib_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f start_lib_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(start_lib_test_OBJECTS) $(start_lib_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@start_lib_test$(EXEEXT): $(start_lib_test_OBJECTS) $(start_lib_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f start_lib_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(start_lib_test_OBJECTS) $(start_lib_test_LDADD) $(LIBS)
+thin_archive_test_1$(EXEEXT): $(thin_archive_test_1_OBJECTS) $(thin_archive_test_1_DEPENDENCIES)
+ @rm -f thin_archive_test_1$(EXEEXT)
+ $(thin_archive_test_1_LINK) $(thin_archive_test_1_OBJECTS) $(thin_archive_test_1_LDADD) $(LIBS)
+thin_archive_test_2$(EXEEXT): $(thin_archive_test_2_OBJECTS) $(thin_archive_test_2_DEPENDENCIES)
+ @rm -f thin_archive_test_2$(EXEEXT)
+ $(thin_archive_test_2_LINK) $(thin_archive_test_2_OBJECTS) $(thin_archive_test_2_LDADD) $(LIBS)
+tls_phdrs_script_test$(EXEEXT): $(tls_phdrs_script_test_OBJECTS) $(tls_phdrs_script_test_DEPENDENCIES)
+ @rm -f tls_phdrs_script_test$(EXEEXT)
+ $(tls_phdrs_script_test_LINK) $(tls_phdrs_script_test_OBJECTS) $(tls_phdrs_script_test_LDADD) $(LIBS)
+tls_pic_test$(EXEEXT): $(tls_pic_test_OBJECTS) $(tls_pic_test_DEPENDENCIES)
+ @rm -f tls_pic_test$(EXEEXT)
+ $(tls_pic_test_LINK) $(tls_pic_test_OBJECTS) $(tls_pic_test_LDADD) $(LIBS)
+@GCC_FALSE@tls_pie_pic_test$(EXEEXT): $(tls_pie_pic_test_OBJECTS) $(tls_pie_pic_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f tls_pie_pic_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(tls_pie_pic_test_OBJECTS) $(tls_pie_pic_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@tls_pie_pic_test$(EXEEXT): $(tls_pie_pic_test_OBJECTS) $(tls_pie_pic_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f tls_pie_pic_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(tls_pie_pic_test_OBJECTS) $(tls_pie_pic_test_LDADD) $(LIBS)
+@TLS_FALSE@tls_pie_pic_test$(EXEEXT): $(tls_pie_pic_test_OBJECTS) $(tls_pie_pic_test_DEPENDENCIES)
+@TLS_FALSE@ @rm -f tls_pie_pic_test$(EXEEXT)
+@TLS_FALSE@ $(LINK) $(tls_pie_pic_test_OBJECTS) $(tls_pie_pic_test_LDADD) $(LIBS)
+@GCC_FALSE@tls_pie_test$(EXEEXT): $(tls_pie_test_OBJECTS) $(tls_pie_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f tls_pie_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(tls_pie_test_OBJECTS) $(tls_pie_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@tls_pie_test$(EXEEXT): $(tls_pie_test_OBJECTS) $(tls_pie_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f tls_pie_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(tls_pie_test_OBJECTS) $(tls_pie_test_LDADD) $(LIBS)
+@TLS_FALSE@tls_pie_test$(EXEEXT): $(tls_pie_test_OBJECTS) $(tls_pie_test_DEPENDENCIES)
+@TLS_FALSE@ @rm -f tls_pie_test$(EXEEXT)
+@TLS_FALSE@ $(LINK) $(tls_pie_test_OBJECTS) $(tls_pie_test_LDADD) $(LIBS)
+tls_script_test$(EXEEXT): $(tls_script_test_OBJECTS) $(tls_script_test_DEPENDENCIES)
+ @rm -f tls_script_test$(EXEEXT)
+ $(tls_script_test_LINK) $(tls_script_test_OBJECTS) $(tls_script_test_LDADD) $(LIBS)
+tls_shared_gd_to_ie_test$(EXEEXT): $(tls_shared_gd_to_ie_test_OBJECTS) $(tls_shared_gd_to_ie_test_DEPENDENCIES)
+ @rm -f tls_shared_gd_to_ie_test$(EXEEXT)
+ $(tls_shared_gd_to_ie_test_LINK) $(tls_shared_gd_to_ie_test_OBJECTS) $(tls_shared_gd_to_ie_test_LDADD) $(LIBS)
+tls_shared_gnu2_gd_to_ie_test$(EXEEXT): $(tls_shared_gnu2_gd_to_ie_test_OBJECTS) $(tls_shared_gnu2_gd_to_ie_test_DEPENDENCIES)
+ @rm -f tls_shared_gnu2_gd_to_ie_test$(EXEEXT)
+ $(tls_shared_gnu2_gd_to_ie_test_LINK) $(tls_shared_gnu2_gd_to_ie_test_OBJECTS) $(tls_shared_gnu2_gd_to_ie_test_LDADD) $(LIBS)
+tls_shared_gnu2_test$(EXEEXT): $(tls_shared_gnu2_test_OBJECTS) $(tls_shared_gnu2_test_DEPENDENCIES)
+ @rm -f tls_shared_gnu2_test$(EXEEXT)
+ $(tls_shared_gnu2_test_LINK) $(tls_shared_gnu2_test_OBJECTS) $(tls_shared_gnu2_test_LDADD) $(LIBS)
+tls_shared_ie_test$(EXEEXT): $(tls_shared_ie_test_OBJECTS) $(tls_shared_ie_test_DEPENDENCIES)
+ @rm -f tls_shared_ie_test$(EXEEXT)
+ $(tls_shared_ie_test_LINK) $(tls_shared_ie_test_OBJECTS) $(tls_shared_ie_test_LDADD) $(LIBS)
+tls_shared_nonpic_test$(EXEEXT): $(tls_shared_nonpic_test_OBJECTS) $(tls_shared_nonpic_test_DEPENDENCIES)
+ @rm -f tls_shared_nonpic_test$(EXEEXT)
+ $(tls_shared_nonpic_test_LINK) $(tls_shared_nonpic_test_OBJECTS) $(tls_shared_nonpic_test_LDADD) $(LIBS)
+tls_shared_test$(EXEEXT): $(tls_shared_test_OBJECTS) $(tls_shared_test_DEPENDENCIES)
+ @rm -f tls_shared_test$(EXEEXT)
+ $(tls_shared_test_LINK) $(tls_shared_test_OBJECTS) $(tls_shared_test_LDADD) $(LIBS)
+tls_static_pic_test$(EXEEXT): $(tls_static_pic_test_OBJECTS) $(tls_static_pic_test_DEPENDENCIES)
+ @rm -f tls_static_pic_test$(EXEEXT)
+ $(tls_static_pic_test_LINK) $(tls_static_pic_test_OBJECTS) $(tls_static_pic_test_LDADD) $(LIBS)
+tls_static_test$(EXEEXT): $(tls_static_test_OBJECTS) $(tls_static_test_DEPENDENCIES)
+ @rm -f tls_static_test$(EXEEXT)
+ $(tls_static_test_LINK) $(tls_static_test_OBJECTS) $(tls_static_test_LDADD) $(LIBS)
+tls_test$(EXEEXT): $(tls_test_OBJECTS) $(tls_test_DEPENDENCIES)
+ @rm -f tls_test$(EXEEXT)
+ $(tls_test_LINK) $(tls_test_OBJECTS) $(tls_test_LDADD) $(LIBS)
+two_file_mixed_2_shared_test$(EXEEXT): $(two_file_mixed_2_shared_test_OBJECTS) $(two_file_mixed_2_shared_test_DEPENDENCIES)
+ @rm -f two_file_mixed_2_shared_test$(EXEEXT)
+ $(two_file_mixed_2_shared_test_LINK) $(two_file_mixed_2_shared_test_OBJECTS) $(two_file_mixed_2_shared_test_LDADD) $(LIBS)
+@FN_PTRS_IN_SO_WITHOUT_PIC_FALSE@two_file_mixed_pie_test$(EXEEXT): $(two_file_mixed_pie_test_OBJECTS) $(two_file_mixed_pie_test_DEPENDENCIES)
+@FN_PTRS_IN_SO_WITHOUT_PIC_FALSE@ @rm -f two_file_mixed_pie_test$(EXEEXT)
+@FN_PTRS_IN_SO_WITHOUT_PIC_FALSE@ $(LINK) $(two_file_mixed_pie_test_OBJECTS) $(two_file_mixed_pie_test_LDADD) $(LIBS)
+@GCC_FALSE@two_file_mixed_pie_test$(EXEEXT): $(two_file_mixed_pie_test_OBJECTS) $(two_file_mixed_pie_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f two_file_mixed_pie_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(two_file_mixed_pie_test_OBJECTS) $(two_file_mixed_pie_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@two_file_mixed_pie_test$(EXEEXT): $(two_file_mixed_pie_test_OBJECTS) $(two_file_mixed_pie_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f two_file_mixed_pie_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(two_file_mixed_pie_test_OBJECTS) $(two_file_mixed_pie_test_LDADD) $(LIBS)
+two_file_mixed_shared_test$(EXEEXT): $(two_file_mixed_shared_test_OBJECTS) $(two_file_mixed_shared_test_DEPENDENCIES)
+ @rm -f two_file_mixed_shared_test$(EXEEXT)
+ $(two_file_mixed_shared_test_LINK) $(two_file_mixed_shared_test_OBJECTS) $(two_file_mixed_shared_test_LDADD) $(LIBS)
+two_file_pic_test$(EXEEXT): $(two_file_pic_test_OBJECTS) $(two_file_pic_test_DEPENDENCIES)
+ @rm -f two_file_pic_test$(EXEEXT)
+ $(two_file_pic_test_LINK) $(two_file_pic_test_OBJECTS) $(two_file_pic_test_LDADD) $(LIBS)
+@GCC_FALSE@two_file_pie_test$(EXEEXT): $(two_file_pie_test_OBJECTS) $(two_file_pie_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f two_file_pie_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(two_file_pie_test_OBJECTS) $(two_file_pie_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@two_file_pie_test$(EXEEXT): $(two_file_pie_test_OBJECTS) $(two_file_pie_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f two_file_pie_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(two_file_pie_test_OBJECTS) $(two_file_pie_test_LDADD) $(LIBS)
+two_file_relocatable_test$(EXEEXT): $(two_file_relocatable_test_OBJECTS) $(two_file_relocatable_test_DEPENDENCIES)
+ @rm -f two_file_relocatable_test$(EXEEXT)
+ $(two_file_relocatable_test_LINK) $(two_file_relocatable_test_OBJECTS) $(two_file_relocatable_test_LDADD) $(LIBS)
+two_file_same_shared_nonpic_test$(EXEEXT): $(two_file_same_shared_nonpic_test_OBJECTS) $(two_file_same_shared_nonpic_test_DEPENDENCIES)
+ @rm -f two_file_same_shared_nonpic_test$(EXEEXT)
+ $(two_file_same_shared_nonpic_test_LINK) $(two_file_same_shared_nonpic_test_OBJECTS) $(two_file_same_shared_nonpic_test_LDADD) $(LIBS)
+two_file_same_shared_strip_test$(EXEEXT): $(two_file_same_shared_strip_test_OBJECTS) $(two_file_same_shared_strip_test_DEPENDENCIES)
+ @rm -f two_file_same_shared_strip_test$(EXEEXT)
+ $(two_file_same_shared_strip_test_LINK) $(two_file_same_shared_strip_test_OBJECTS) $(two_file_same_shared_strip_test_LDADD) $(LIBS)
+two_file_same_shared_test$(EXEEXT): $(two_file_same_shared_test_OBJECTS) $(two_file_same_shared_test_DEPENDENCIES)
+ @rm -f two_file_same_shared_test$(EXEEXT)
+ $(two_file_same_shared_test_LINK) $(two_file_same_shared_test_OBJECTS) $(two_file_same_shared_test_LDADD) $(LIBS)
+two_file_separate_shared_12_nonpic_test$(EXEEXT): $(two_file_separate_shared_12_nonpic_test_OBJECTS) $(two_file_separate_shared_12_nonpic_test_DEPENDENCIES)
+ @rm -f two_file_separate_shared_12_nonpic_test$(EXEEXT)
+ $(two_file_separate_shared_12_nonpic_test_LINK) $(two_file_separate_shared_12_nonpic_test_OBJECTS) $(two_file_separate_shared_12_nonpic_test_LDADD) $(LIBS)
+two_file_separate_shared_12_test$(EXEEXT): $(two_file_separate_shared_12_test_OBJECTS) $(two_file_separate_shared_12_test_DEPENDENCIES)
+ @rm -f two_file_separate_shared_12_test$(EXEEXT)
+ $(two_file_separate_shared_12_test_LINK) $(two_file_separate_shared_12_test_OBJECTS) $(two_file_separate_shared_12_test_LDADD) $(LIBS)
+two_file_separate_shared_21_nonpic_test$(EXEEXT): $(two_file_separate_shared_21_nonpic_test_OBJECTS) $(two_file_separate_shared_21_nonpic_test_DEPENDENCIES)
+ @rm -f two_file_separate_shared_21_nonpic_test$(EXEEXT)
+ $(two_file_separate_shared_21_nonpic_test_LINK) $(two_file_separate_shared_21_nonpic_test_OBJECTS) $(two_file_separate_shared_21_nonpic_test_LDADD) $(LIBS)
+two_file_separate_shared_21_test$(EXEEXT): $(two_file_separate_shared_21_test_OBJECTS) $(two_file_separate_shared_21_test_DEPENDENCIES)
+ @rm -f two_file_separate_shared_21_test$(EXEEXT)
+ $(two_file_separate_shared_21_test_LINK) $(two_file_separate_shared_21_test_OBJECTS) $(two_file_separate_shared_21_test_LDADD) $(LIBS)
+two_file_shared_1_nonpic_test$(EXEEXT): $(two_file_shared_1_nonpic_test_OBJECTS) $(two_file_shared_1_nonpic_test_DEPENDENCIES)
+ @rm -f two_file_shared_1_nonpic_test$(EXEEXT)
+ $(two_file_shared_1_nonpic_test_LINK) $(two_file_shared_1_nonpic_test_OBJECTS) $(two_file_shared_1_nonpic_test_LDADD) $(LIBS)
+two_file_shared_1_pic_2_test$(EXEEXT): $(two_file_shared_1_pic_2_test_OBJECTS) $(two_file_shared_1_pic_2_test_DEPENDENCIES)
+ @rm -f two_file_shared_1_pic_2_test$(EXEEXT)
+ $(two_file_shared_1_pic_2_test_LINK) $(two_file_shared_1_pic_2_test_OBJECTS) $(two_file_shared_1_pic_2_test_LDADD) $(LIBS)
+two_file_shared_1_test$(EXEEXT): $(two_file_shared_1_test_OBJECTS) $(two_file_shared_1_test_DEPENDENCIES)
+ @rm -f two_file_shared_1_test$(EXEEXT)
+ $(two_file_shared_1_test_LINK) $(two_file_shared_1_test_OBJECTS) $(two_file_shared_1_test_LDADD) $(LIBS)
+two_file_shared_2_nonpic_test$(EXEEXT): $(two_file_shared_2_nonpic_test_OBJECTS) $(two_file_shared_2_nonpic_test_DEPENDENCIES)
+ @rm -f two_file_shared_2_nonpic_test$(EXEEXT)
+ $(two_file_shared_2_nonpic_test_LINK) $(two_file_shared_2_nonpic_test_OBJECTS) $(two_file_shared_2_nonpic_test_LDADD) $(LIBS)
+two_file_shared_2_pic_1_test$(EXEEXT): $(two_file_shared_2_pic_1_test_OBJECTS) $(two_file_shared_2_pic_1_test_DEPENDENCIES)
+ @rm -f two_file_shared_2_pic_1_test$(EXEEXT)
+ $(two_file_shared_2_pic_1_test_LINK) $(two_file_shared_2_pic_1_test_OBJECTS) $(two_file_shared_2_pic_1_test_LDADD) $(LIBS)
+two_file_shared_2_test$(EXEEXT): $(two_file_shared_2_test_OBJECTS) $(two_file_shared_2_test_DEPENDENCIES)
+ @rm -f two_file_shared_2_test$(EXEEXT)
+ $(two_file_shared_2_test_LINK) $(two_file_shared_2_test_OBJECTS) $(two_file_shared_2_test_LDADD) $(LIBS)
+two_file_static_test$(EXEEXT): $(two_file_static_test_OBJECTS) $(two_file_static_test_DEPENDENCIES)
+ @rm -f two_file_static_test$(EXEEXT)
+ $(two_file_static_test_LINK) $(two_file_static_test_OBJECTS) $(two_file_static_test_LDADD) $(LIBS)
+@GCC_FALSE@two_file_strip_test$(EXEEXT): $(two_file_strip_test_OBJECTS) $(two_file_strip_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f two_file_strip_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(two_file_strip_test_OBJECTS) $(two_file_strip_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@two_file_strip_test$(EXEEXT): $(two_file_strip_test_OBJECTS) $(two_file_strip_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f two_file_strip_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(two_file_strip_test_OBJECTS) $(two_file_strip_test_LDADD) $(LIBS)
+two_file_test$(EXEEXT): $(two_file_test_OBJECTS) $(two_file_test_DEPENDENCIES)
+ @rm -f two_file_test$(EXEEXT)
+ $(two_file_test_LINK) $(two_file_test_OBJECTS) $(two_file_test_LDADD) $(LIBS)
+ver_test$(EXEEXT): $(ver_test_OBJECTS) $(ver_test_DEPENDENCIES)
+ @rm -f ver_test$(EXEEXT)
+ $(ver_test_LINK) $(ver_test_OBJECTS) $(ver_test_LDADD) $(LIBS)
+ver_test_11$(EXEEXT): $(ver_test_11_OBJECTS) $(ver_test_11_DEPENDENCIES)
+ @rm -f ver_test_11$(EXEEXT)
+ $(ver_test_11_LINK) $(ver_test_11_OBJECTS) $(ver_test_11_LDADD) $(LIBS)
+ver_test_12$(EXEEXT): $(ver_test_12_OBJECTS) $(ver_test_12_DEPENDENCIES)
+ @rm -f ver_test_12$(EXEEXT)
+ $(ver_test_12_LINK) $(ver_test_12_OBJECTS) $(ver_test_12_LDADD) $(LIBS)
+ver_test_2$(EXEEXT): $(ver_test_2_OBJECTS) $(ver_test_2_DEPENDENCIES)
+ @rm -f ver_test_2$(EXEEXT)
+ $(ver_test_2_LINK) $(ver_test_2_OBJECTS) $(ver_test_2_LDADD) $(LIBS)
+ver_test_6$(EXEEXT): $(ver_test_6_OBJECTS) $(ver_test_6_DEPENDENCIES)
+ @rm -f ver_test_6$(EXEEXT)
+ $(ver_test_6_LINK) $(ver_test_6_OBJECTS) $(ver_test_6_LDADD) $(LIBS)
+ver_test_8$(EXEEXT): $(ver_test_8_OBJECTS) $(ver_test_8_DEPENDENCIES)
+ @rm -f ver_test_8$(EXEEXT)
+ $(ver_test_8_LINK) $(ver_test_8_OBJECTS) $(ver_test_8_LDADD) $(LIBS)
+ver_test_9$(EXEEXT): $(ver_test_9_OBJECTS) $(ver_test_9_DEPENDENCIES)
+ @rm -f ver_test_9$(EXEEXT)
+ $(ver_test_9_LINK) $(ver_test_9_OBJECTS) $(ver_test_9_LDADD) $(LIBS)
+weak_alias_test$(EXEEXT): $(weak_alias_test_OBJECTS) $(weak_alias_test_DEPENDENCIES)
+ @rm -f weak_alias_test$(EXEEXT)
+ $(weak_alias_test_LINK) $(weak_alias_test_OBJECTS) $(weak_alias_test_LDADD) $(LIBS)
+@GCC_FALSE@weak_plt$(EXEEXT): $(weak_plt_OBJECTS) $(weak_plt_DEPENDENCIES)
+@GCC_FALSE@ @rm -f weak_plt$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(weak_plt_OBJECTS) $(weak_plt_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@weak_plt$(EXEEXT): $(weak_plt_OBJECTS) $(weak_plt_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f weak_plt$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(weak_plt_OBJECTS) $(weak_plt_LDADD) $(LIBS)
+weak_test$(EXEEXT): $(weak_test_OBJECTS) $(weak_test_DEPENDENCIES)
+ @rm -f weak_test$(EXEEXT)
+ $(weak_test_LINK) $(weak_test_OBJECTS) $(weak_test_LDADD) $(LIBS)
+weak_undef_nonpic_test$(EXEEXT): $(weak_undef_nonpic_test_OBJECTS) $(weak_undef_nonpic_test_DEPENDENCIES)
+ @rm -f weak_undef_nonpic_test$(EXEEXT)
+ $(weak_undef_nonpic_test_LINK) $(weak_undef_nonpic_test_OBJECTS) $(weak_undef_nonpic_test_LDADD) $(LIBS)
+weak_undef_test$(EXEEXT): $(weak_undef_test_OBJECTS) $(weak_undef_test_DEPENDENCIES)
+ @rm -f weak_undef_test$(EXEEXT)
+ $(weak_undef_test_LINK) $(weak_undef_test_OBJECTS) $(weak_undef_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_pic_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_pie_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_static_pic_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_static_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binary_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binary_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_test_1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/constructor_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copy_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/discard_locals_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exception_test_1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exception_test_2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exception_test_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exclude_libs_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flagstest_compress_debug_sections.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flagstest_o_specialfile.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flagstest_o_specialfile_and_compress_debug_sections.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flagstest_o_ttext_1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icf_virtual_function_folding_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncdep2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain1pic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain1picstatic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain1pie.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain1staticpic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain1staticpie.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain1vis.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain1vispic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain1vispie.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain2pic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain2picstatic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain4.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain4picstatic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain5.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain5pic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain5picstatic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain5pie.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain5staticpic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain6pie.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain7.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain7pic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain7picstatic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain7pie.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncvar3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental_comdat_test_1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental_common_test_1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental_copy_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental_test_2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental_test_3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental_test_4.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental_test_5.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental_test_6.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initpri1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initpri2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initpri3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/justsyms_1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/justsyms_exec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/large-large.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/large_symbol_alignment.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/leb128_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local_labels_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/many_sections_r_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/many_sections_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/permission_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_4.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_5.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_6.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_7.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_8.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_tls.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protected_3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protected_main_1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protected_main_2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protected_main_3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/relro_test_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_11.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_2a.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_2b.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/searched_file_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/start_lib_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testfile.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testmain.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thin_archive_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_pie_pic_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_pie_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_test_file2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_test_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_mixed_pie_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_pie_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_strip_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_test_1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_test_1b.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_test_2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_test_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ver_test_6.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ver_test_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ver_test_main_2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/weak_alias_test_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/weak_plt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/weak_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/weak_undef_test.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) '$<'`
+
+large-large.o: large.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(large_CFLAGS) $(CFLAGS) -MT large-large.o -MD -MP -MF $(DEPDIR)/large-large.Tpo -c -o large-large.o `test -f 'large.c' || echo '$(srcdir)/'`large.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/large-large.Tpo $(DEPDIR)/large-large.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='large.c' object='large-large.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(large_CFLAGS) $(CFLAGS) -c -o large-large.o `test -f 'large.c' || echo '$(srcdir)/'`large.c
+
+large-large.obj: large.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(large_CFLAGS) $(CFLAGS) -MT large-large.obj -MD -MP -MF $(DEPDIR)/large-large.Tpo -c -o large-large.obj `if test -f 'large.c'; then $(CYGPATH_W) 'large.c'; else $(CYGPATH_W) '$(srcdir)/large.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/large-large.Tpo $(DEPDIR)/large-large.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='large.c' object='large-large.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(large_CFLAGS) $(CFLAGS) -c -o large-large.obj `if test -f 'large.c'; then $(CYGPATH_W) 'large.c'; else $(CYGPATH_W) '$(srcdir)/large.c'; fi`
+
+.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) '$<'`
+
+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: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ 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; }; }'`; \
+ 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: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ 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; }; }'`; \
+ 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"'"'
+incremental_test.sh.log: incremental_test.sh
+ @p='incremental_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+gc_comdat_test.sh.log: gc_comdat_test.sh
+ @p='gc_comdat_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+gc_tls_test.sh.log: gc_tls_test.sh
+ @p='gc_tls_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+gc_orphan_section_test.sh.log: gc_orphan_section_test.sh
+ @p='gc_orphan_section_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+pr14265.sh.log: pr14265.sh
+ @p='pr14265.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+icf_test.sh.log: icf_test.sh
+ @p='icf_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+icf_keep_unique_test.sh.log: icf_keep_unique_test.sh
+ @p='icf_keep_unique_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+icf_safe_test.sh.log: icf_safe_test.sh
+ @p='icf_safe_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+icf_safe_so_test.sh.log: icf_safe_so_test.sh
+ @p='icf_safe_so_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+final_layout.sh.log: final_layout.sh
+ @p='final_layout.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+text_section_grouping.sh.log: text_section_grouping.sh
+ @p='text_section_grouping.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+section_sorting_name.sh.log: section_sorting_name.sh
+ @p='section_sorting_name.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+icf_preemptible_functions_test.sh.log: icf_preemptible_functions_test.sh
+ @p='icf_preemptible_functions_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+icf_string_merge_test.sh.log: icf_string_merge_test.sh
+ @p='icf_string_merge_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+icf_sht_rel_addend_test.sh.log: icf_sht_rel_addend_test.sh
+ @p='icf_sht_rel_addend_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+merge_string_literals.sh.log: merge_string_literals.sh
+ @p='merge_string_literals.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_shared.sh.log: two_file_shared.sh
+ @p='two_file_shared.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+weak_plt.sh.log: weak_plt.sh
+ @p='weak_plt.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+debug_msg.sh.log: debug_msg.sh
+ @p='debug_msg.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+missing_key_func.sh.log: missing_key_func.sh
+ @p='missing_key_func.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+undef_symbol.sh.log: undef_symbol.sh
+ @p='undef_symbol.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_test_1.sh.log: ver_test_1.sh
+ @p='ver_test_1.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_test_2.sh.log: ver_test_2.sh
+ @p='ver_test_2.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_test_4.sh.log: ver_test_4.sh
+ @p='ver_test_4.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_test_5.sh.log: ver_test_5.sh
+ @p='ver_test_5.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_test_7.sh.log: ver_test_7.sh
+ @p='ver_test_7.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_test_10.sh.log: ver_test_10.sh
+ @p='ver_test_10.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+relro_test.sh.log: relro_test.sh
+ @p='relro_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_matching_test.sh.log: ver_matching_test.sh
+ @p='ver_matching_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_3.sh.log: script_test_3.sh
+ @p='script_test_3.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_4.sh.log: script_test_4.sh
+ @p='script_test_4.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_5.sh.log: script_test_5.sh
+ @p='script_test_5.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_6.sh.log: script_test_6.sh
+ @p='script_test_6.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_7.sh.log: script_test_7.sh
+ @p='script_test_7.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_8.sh.log: script_test_8.sh
+ @p='script_test_8.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_9.sh.log: script_test_9.sh
+ @p='script_test_9.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+dynamic_list.sh.log: dynamic_list.sh
+ @p='dynamic_list.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_1.sh.log: plugin_test_1.sh
+ @p='plugin_test_1.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_2.sh.log: plugin_test_2.sh
+ @p='plugin_test_2.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_3.sh.log: plugin_test_3.sh
+ @p='plugin_test_3.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_4.sh.log: plugin_test_4.sh
+ @p='plugin_test_4.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_6.sh.log: plugin_test_6.sh
+ @p='plugin_test_6.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_7.sh.log: plugin_test_7.sh
+ @p='plugin_test_7.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_tls.sh.log: plugin_test_tls.sh
+ @p='plugin_test_tls.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_final_layout.sh.log: plugin_final_layout.sh
+ @p='plugin_final_layout.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+exclude_libs_test.sh.log: exclude_libs_test.sh
+ @p='exclude_libs_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+discard_locals_test.sh.log: discard_locals_test.sh
+ @p='discard_locals_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+hidden_test.sh.log: hidden_test.sh
+ @p='hidden_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+retain_symbols_file_test.sh.log: retain_symbols_file_test.sh
+ @p='retain_symbols_file_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+no_version_test.sh.log: no_version_test.sh
+ @p='no_version_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+strong_ref_weak_def.sh.log: strong_ref_weak_def.sh
+ @p='strong_ref_weak_def.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+dyn_weak_ref.sh.log: dyn_weak_ref.sh
+ @p='dyn_weak_ref.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+memory_test.sh.log: memory_test.sh
+ @p='memory_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+gdb_index_test_1.sh.log: gdb_index_test_1.sh
+ @p='gdb_index_test_1.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+gdb_index_test_2.sh.log: gdb_index_test_2.sh
+ @p='gdb_index_test_2.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+gdb_index_test_3.sh.log: gdb_index_test_3.sh
+ @p='gdb_index_test_3.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+gdb_index_test_4.sh.log: gdb_index_test_4.sh
+ @p='gdb_index_test_4.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_10.sh.log: script_test_10.sh
+ @p='script_test_10.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+split_i386.sh.log: split_i386.sh
+ @p='split_i386.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+split_x86_64.sh.log: split_x86_64.sh
+ @p='split_x86_64.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_abs_global.sh.log: arm_abs_global.sh
+ @p='arm_abs_global.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_branch_in_range.sh.log: arm_branch_in_range.sh
+ @p='arm_branch_in_range.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_branch_out_of_range.sh.log: arm_branch_out_of_range.sh
+ @p='arm_branch_out_of_range.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_fix_v4bx.sh.log: arm_fix_v4bx.sh
+ @p='arm_fix_v4bx.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_attr_merge.sh.log: arm_attr_merge.sh
+ @p='arm_attr_merge.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_fix_1176.sh.log: arm_fix_1176.sh
+ @p='arm_fix_1176.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_cortex_a8.sh.log: arm_cortex_a8.sh
+ @p='arm_cortex_a8.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_exidx_test.sh.log: arm_exidx_test.sh
+ @p='arm_exidx_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+pr12826.sh.log: pr12826.sh
+ @p='pr12826.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_unaligned_reloc.sh.log: arm_unaligned_reloc.sh
+ @p='arm_unaligned_reloc.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_farcall_arm_arm.sh.log: arm_farcall_arm_arm.sh
+ @p='arm_farcall_arm_arm.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_farcall_arm_thumb.sh.log: arm_farcall_arm_thumb.sh
+ @p='arm_farcall_arm_thumb.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_farcall_thumb_thumb.sh.log: arm_farcall_thumb_thumb.sh
+ @p='arm_farcall_thumb_thumb.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_farcall_thumb_arm.sh.log: arm_farcall_thumb_arm.sh
+ @p='arm_farcall_thumb_arm.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+dwp_test_1.sh.log: dwp_test_1.sh
+ @p='dwp_test_1.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+dwp_test_2.sh.log: dwp_test_2.sh
+ @p='dwp_test_2.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+object_unittest.log: object_unittest$(EXEEXT)
+ @p='object_unittest$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+binary_unittest.log: binary_unittest$(EXEEXT)
+ @p='binary_unittest$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+leb128_unittest.log: leb128_unittest$(EXEEXT)
+ @p='leb128_unittest$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+icf_virtual_function_folding_test.log: icf_virtual_function_folding_test$(EXEEXT)
+ @p='icf_virtual_function_folding_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+large_symbol_alignment.log: large_symbol_alignment$(EXEEXT)
+ @p='large_symbol_alignment$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+basic_test.log: basic_test$(EXEEXT)
+ @p='basic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+basic_pic_test.log: basic_pic_test$(EXEEXT)
+ @p='basic_pic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+basic_static_test.log: basic_static_test$(EXEEXT)
+ @p='basic_static_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+basic_static_pic_test.log: basic_static_pic_test$(EXEEXT)
+ @p='basic_static_pic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+basic_pie_test.log: basic_pie_test$(EXEEXT)
+ @p='basic_pie_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+constructor_test.log: constructor_test$(EXEEXT)
+ @p='constructor_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+constructor_static_test.log: constructor_static_test$(EXEEXT)
+ @p='constructor_static_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_test.log: two_file_test$(EXEEXT)
+ @p='two_file_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_pic_test.log: two_file_pic_test$(EXEEXT)
+ @p='two_file_pic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_static_test.log: two_file_static_test$(EXEEXT)
+ @p='two_file_static_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_shared_1_test.log: two_file_shared_1_test$(EXEEXT)
+ @p='two_file_shared_1_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_shared_2_test.log: two_file_shared_2_test$(EXEEXT)
+ @p='two_file_shared_2_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_shared_1_pic_2_test.log: two_file_shared_1_pic_2_test$(EXEEXT)
+ @p='two_file_shared_1_pic_2_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_shared_2_pic_1_test.log: two_file_shared_2_pic_1_test$(EXEEXT)
+ @p='two_file_shared_2_pic_1_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_same_shared_test.log: two_file_same_shared_test$(EXEEXT)
+ @p='two_file_same_shared_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_separate_shared_12_test.log: two_file_separate_shared_12_test$(EXEEXT)
+ @p='two_file_separate_shared_12_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_separate_shared_21_test.log: two_file_separate_shared_21_test$(EXEEXT)
+ @p='two_file_separate_shared_21_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_relocatable_test.log: two_file_relocatable_test$(EXEEXT)
+ @p='two_file_relocatable_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_pie_test.log: two_file_pie_test$(EXEEXT)
+ @p='two_file_pie_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_shared_1_nonpic_test.log: two_file_shared_1_nonpic_test$(EXEEXT)
+ @p='two_file_shared_1_nonpic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_shared_2_nonpic_test.log: two_file_shared_2_nonpic_test$(EXEEXT)
+ @p='two_file_shared_2_nonpic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_same_shared_nonpic_test.log: two_file_same_shared_nonpic_test$(EXEEXT)
+ @p='two_file_same_shared_nonpic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_separate_shared_12_nonpic_test.log: two_file_separate_shared_12_nonpic_test$(EXEEXT)
+ @p='two_file_separate_shared_12_nonpic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_separate_shared_21_nonpic_test.log: two_file_separate_shared_21_nonpic_test$(EXEEXT)
+ @p='two_file_separate_shared_21_nonpic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_mixed_shared_test.log: two_file_mixed_shared_test$(EXEEXT)
+ @p='two_file_mixed_shared_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_mixed_2_shared_test.log: two_file_mixed_2_shared_test$(EXEEXT)
+ @p='two_file_mixed_2_shared_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_mixed_pie_test.log: two_file_mixed_pie_test$(EXEEXT)
+ @p='two_file_mixed_pie_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_strip_test.log: two_file_strip_test$(EXEEXT)
+ @p='two_file_strip_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+two_file_same_shared_strip_test.log: two_file_same_shared_strip_test$(EXEEXT)
+ @p='two_file_same_shared_strip_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+common_test_1.log: common_test_1$(EXEEXT)
+ @p='common_test_1$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+common_test_2.log: common_test_2$(EXEEXT)
+ @p='common_test_2$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+exception_test.log: exception_test$(EXEEXT)
+ @p='exception_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+exception_shared_1_test.log: exception_shared_1_test$(EXEEXT)
+ @p='exception_shared_1_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+exception_shared_2_test.log: exception_shared_2_test$(EXEEXT)
+ @p='exception_shared_2_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+exception_same_shared_test.log: exception_same_shared_test$(EXEEXT)
+ @p='exception_same_shared_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+exception_separate_shared_12_test.log: exception_separate_shared_12_test$(EXEEXT)
+ @p='exception_separate_shared_12_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+exception_separate_shared_21_test.log: exception_separate_shared_21_test$(EXEEXT)
+ @p='exception_separate_shared_21_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+exception_static_test.log: exception_static_test$(EXEEXT)
+ @p='exception_static_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+weak_test.log: weak_test$(EXEEXT)
+ @p='weak_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+weak_undef_test.log: weak_undef_test$(EXEEXT)
+ @p='weak_undef_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+weak_undef_nonpic_test.log: weak_undef_nonpic_test$(EXEEXT)
+ @p='weak_undef_nonpic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+weak_alias_test.log: weak_alias_test$(EXEEXT)
+ @p='weak_alias_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+weak_plt.log: weak_plt$(EXEEXT)
+ @p='weak_plt$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+copy_test.log: copy_test$(EXEEXT)
+ @p='copy_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_test.log: tls_test$(EXEEXT)
+ @p='tls_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_pic_test.log: tls_pic_test$(EXEEXT)
+ @p='tls_pic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_pie_test.log: tls_pie_test$(EXEEXT)
+ @p='tls_pie_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_pie_pic_test.log: tls_pie_pic_test$(EXEEXT)
+ @p='tls_pie_pic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_shared_test.log: tls_shared_test$(EXEEXT)
+ @p='tls_shared_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_shared_ie_test.log: tls_shared_ie_test$(EXEEXT)
+ @p='tls_shared_ie_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_shared_gd_to_ie_test.log: tls_shared_gd_to_ie_test$(EXEEXT)
+ @p='tls_shared_gd_to_ie_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_shared_gnu2_gd_to_ie_test.log: tls_shared_gnu2_gd_to_ie_test$(EXEEXT)
+ @p='tls_shared_gnu2_gd_to_ie_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_shared_gnu2_test.log: tls_shared_gnu2_test$(EXEEXT)
+ @p='tls_shared_gnu2_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_static_test.log: tls_static_test$(EXEEXT)
+ @p='tls_static_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_static_pic_test.log: tls_static_pic_test$(EXEEXT)
+ @p='tls_static_pic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_shared_nonpic_test.log: tls_shared_nonpic_test$(EXEEXT)
+ @p='tls_shared_nonpic_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+many_sections_test.log: many_sections_test$(EXEEXT)
+ @p='many_sections_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+many_sections_r_test.log: many_sections_r_test$(EXEEXT)
+ @p='many_sections_r_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+initpri1.log: initpri1$(EXEEXT)
+ @p='initpri1$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+initpri2.log: initpri2$(EXEEXT)
+ @p='initpri2$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+initpri3a.log: initpri3a$(EXEEXT)
+ @p='initpri3a$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+flagstest_o_specialfile.log: flagstest_o_specialfile$(EXEEXT)
+ @p='flagstest_o_specialfile$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+flagstest_compress_debug_sections.log: flagstest_compress_debug_sections$(EXEEXT)
+ @p='flagstest_compress_debug_sections$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+flagstest_o_specialfile_and_compress_debug_sections.log: flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT)
+ @p='flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+flagstest_o_ttext_1.log: flagstest_o_ttext_1$(EXEEXT)
+ @p='flagstest_o_ttext_1$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_test.log: ver_test$(EXEEXT)
+ @p='ver_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_test_2.log: ver_test_2$(EXEEXT)
+ @p='ver_test_2$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_test_6.log: ver_test_6$(EXEEXT)
+ @p='ver_test_6$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_test_8.log: ver_test_8$(EXEEXT)
+ @p='ver_test_8$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_test_9.log: ver_test_9$(EXEEXT)
+ @p='ver_test_9$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_test_11.log: ver_test_11$(EXEEXT)
+ @p='ver_test_11$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ver_test_12.log: ver_test_12$(EXEEXT)
+ @p='ver_test_12$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+protected_1.log: protected_1$(EXEEXT)
+ @p='protected_1$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+protected_2.log: protected_2$(EXEEXT)
+ @p='protected_2$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+relro_test.log: relro_test$(EXEEXT)
+ @p='relro_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+relro_now_test.log: relro_now_test$(EXEEXT)
+ @p='relro_now_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+relro_strip_test.log: relro_strip_test$(EXEEXT)
+ @p='relro_strip_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+relro_script_test.log: relro_script_test$(EXEEXT)
+ @p='relro_script_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_1.log: script_test_1$(EXEEXT)
+ @p='script_test_1$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_2.log: script_test_2$(EXEEXT)
+ @p='script_test_2$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+justsyms.log: justsyms$(EXEEXT)
+ @p='justsyms$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+justsyms_exec.log: justsyms_exec$(EXEEXT)
+ @p='justsyms_exec$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+binary_test.log: binary_test$(EXEEXT)
+ @p='binary_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_3.log: script_test_3$(EXEEXT)
+ @p='script_test_3$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_phdrs_script_test.log: tls_phdrs_script_test$(EXEEXT)
+ @p='tls_phdrs_script_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+tls_script_test.log: tls_script_test$(EXEEXT)
+ @p='tls_script_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_11.log: script_test_11$(EXEEXT)
+ @p='script_test_11$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+thin_archive_test_1.log: thin_archive_test_1$(EXEEXT)
+ @p='thin_archive_test_1$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+thin_archive_test_2.log: thin_archive_test_2$(EXEEXT)
+ @p='thin_archive_test_2$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_1.log: plugin_test_1$(EXEEXT)
+ @p='plugin_test_1$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_2.log: plugin_test_2$(EXEEXT)
+ @p='plugin_test_2$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_3.log: plugin_test_3$(EXEEXT)
+ @p='plugin_test_3$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_4.log: plugin_test_4$(EXEEXT)
+ @p='plugin_test_4$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_5.log: plugin_test_5$(EXEEXT)
+ @p='plugin_test_5$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_6.log: plugin_test_6$(EXEEXT)
+ @p='plugin_test_6$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_7.log: plugin_test_7$(EXEEXT)
+ @p='plugin_test_7$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_8.log: plugin_test_8$(EXEEXT)
+ @p='plugin_test_8$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+plugin_test_tls.log: plugin_test_tls$(EXEEXT)
+ @p='plugin_test_tls$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+exclude_libs_test.log: exclude_libs_test$(EXEEXT)
+ @p='exclude_libs_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+local_labels_test.log: local_labels_test$(EXEEXT)
+ @p='local_labels_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+discard_locals_test.log: discard_locals_test$(EXEEXT)
+ @p='discard_locals_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+large.log: large$(EXEEXT)
+ @p='large$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+permission_test.log: permission_test$(EXEEXT)
+ @p='permission_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+searched_file_test.log: searched_file_test$(EXEEXT)
+ @p='searched_file_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain1static.log: ifuncmain1static$(EXEEXT)
+ @p='ifuncmain1static$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain1picstatic.log: ifuncmain1picstatic$(EXEEXT)
+ @p='ifuncmain1picstatic$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain1.log: ifuncmain1$(EXEEXT)
+ @p='ifuncmain1$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain1pic.log: ifuncmain1pic$(EXEEXT)
+ @p='ifuncmain1pic$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain1vis.log: ifuncmain1vis$(EXEEXT)
+ @p='ifuncmain1vis$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain1vispic.log: ifuncmain1vispic$(EXEEXT)
+ @p='ifuncmain1vispic$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain1staticpic.log: ifuncmain1staticpic$(EXEEXT)
+ @p='ifuncmain1staticpic$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain1pie.log: ifuncmain1pie$(EXEEXT)
+ @p='ifuncmain1pie$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain1vispie.log: ifuncmain1vispie$(EXEEXT)
+ @p='ifuncmain1vispie$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain1staticpie.log: ifuncmain1staticpie$(EXEEXT)
+ @p='ifuncmain1staticpie$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain2static.log: ifuncmain2static$(EXEEXT)
+ @p='ifuncmain2static$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain2picstatic.log: ifuncmain2picstatic$(EXEEXT)
+ @p='ifuncmain2picstatic$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain2.log: ifuncmain2$(EXEEXT)
+ @p='ifuncmain2$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain2pic.log: ifuncmain2pic$(EXEEXT)
+ @p='ifuncmain2pic$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain3.log: ifuncmain3$(EXEEXT)
+ @p='ifuncmain3$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain4static.log: ifuncmain4static$(EXEEXT)
+ @p='ifuncmain4static$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain4picstatic.log: ifuncmain4picstatic$(EXEEXT)
+ @p='ifuncmain4picstatic$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain4.log: ifuncmain4$(EXEEXT)
+ @p='ifuncmain4$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain5static.log: ifuncmain5static$(EXEEXT)
+ @p='ifuncmain5static$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain5picstatic.log: ifuncmain5picstatic$(EXEEXT)
+ @p='ifuncmain5picstatic$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain5.log: ifuncmain5$(EXEEXT)
+ @p='ifuncmain5$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain5pic.log: ifuncmain5pic$(EXEEXT)
+ @p='ifuncmain5pic$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain5staticpic.log: ifuncmain5staticpic$(EXEEXT)
+ @p='ifuncmain5staticpic$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain5pie.log: ifuncmain5pie$(EXEEXT)
+ @p='ifuncmain5pie$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain6pie.log: ifuncmain6pie$(EXEEXT)
+ @p='ifuncmain6pie$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain7static.log: ifuncmain7static$(EXEEXT)
+ @p='ifuncmain7static$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain7picstatic.log: ifuncmain7picstatic$(EXEEXT)
+ @p='ifuncmain7picstatic$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain7.log: ifuncmain7$(EXEEXT)
+ @p='ifuncmain7$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain7pic.log: ifuncmain7pic$(EXEEXT)
+ @p='ifuncmain7pic$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncmain7pie.log: ifuncmain7pie$(EXEEXT)
+ @p='ifuncmain7pie$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ifuncvar.log: ifuncvar$(EXEEXT)
+ @p='ifuncvar$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+start_lib_test.log: start_lib_test$(EXEEXT)
+ @p='start_lib_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+incremental_test_2.log: incremental_test_2$(EXEEXT)
+ @p='incremental_test_2$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+incremental_test_3.log: incremental_test_3$(EXEEXT)
+ @p='incremental_test_3$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+incremental_test_4.log: incremental_test_4$(EXEEXT)
+ @p='incremental_test_4$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+incremental_test_5.log: incremental_test_5$(EXEEXT)
+ @p='incremental_test_5$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+incremental_test_6.log: incremental_test_6$(EXEEXT)
+ @p='incremental_test_6$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+incremental_copy_test.log: incremental_copy_test$(EXEEXT)
+ @p='incremental_copy_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+incremental_common_test_1.log: incremental_common_test_1$(EXEEXT)
+ @p='incremental_common_test_1$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+incremental_comdat_test_1.log: incremental_comdat_test_1$(EXEEXT)
+ @p='incremental_comdat_test_1$(EXEEXT)'; $(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_LIBRARIES) $(check_PROGRAMS) \
+ $(check_SCRIPTS) $(check_DATA)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile
+installdirs:
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+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 "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+ -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."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-checkLIBRARIES clean-checkPROGRAMS clean-generic \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: all check check-am check-html install install-am install-strip \
+ recheck recheck-html
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am check-html \
+ clean clean-checkLIBRARIES clean-checkPROGRAMS clean-generic \
+ ctags distclean distclean-compile distclean-generic \
+ distclean-tags dvi dvi-am html html-am info info-am install \
+ install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am 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 \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
+ recheck recheck-html tags uninstall uninstall-am
+
+
+# Export make variables to the shell scripts so that they can see
+# (for example) DEFAULT_TARGET.
+.EXPORT_ALL_VARIABLES:
+
+# The unittests themselves
+
+# Infrastucture needed for the unittests: a directory where the linker
+# is named 'ld'. This is because the -B flag appends 'ld' to its arg.
+@GCC_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@gcctestdir/ld: ../ld-new
+@GCC_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ test -d gcctestdir || mkdir -p gcctestdir
+@GCC_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ rm -f gcctestdir/ld
+@GCC_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ (cd gcctestdir && $(LN_S) ../../ld-new ld)
+
+# Some tests require the latest features of an in-tree assembler.
+@GCC_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@gcctestdir/as: $(TEST_AS)
+@GCC_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ test -d gcctestdir || mkdir -p gcctestdir
+@GCC_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ rm -f gcctestdir/as
+@GCC_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ (cd gcctestdir && $(LN_S) $(abs_top_builddir)/../gas/as-new as)
+
+# ---------------------------------------------------------------------
+# These tests test the output of gold (end-to-end tests). In
+# particular, they make sure that gold can link "difficult" object
+# files, and the resulting object files run correctly. These can only
+# run if we've built ld-new for the native architecture (that is,
+# we're not cross-compiling it), since we run ld-new as part of these
+# tests. We use the gcc-specific flag '-B' to use our linker instead
+# of the default linker, which is why we only run our tests under gcc.
+
+# Each of these .o's is a useful, small complete program. They're
+# particularly useful for making sure ld-new's flags do what they're
+# supposed to (hence their names), but are used for many tests that
+# don't actually involve analyzing input data.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@flagstest_debug.o: constructor_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@flagstest_ndebug.o: constructor_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_1.o: incremental_test_1.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_2.o: incremental_test_2.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test: incremental_test_1.o incremental_test_2.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -Wl,--incremental-full incremental_test_1.o incremental_test_2.o -Wl,-debug 2> incremental_test.cmdline
+@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test.stdout: incremental_test ../incremental-dump
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ../incremental-dump incremental_test > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@gc_comdat_test_1.o: gc_comdat_test_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@gc_comdat_test_2.o: gc_comdat_test_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@gc_comdat_test: gc_comdat_test_1.o gc_comdat_test_2.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--gc-sections gc_comdat_test_1.o gc_comdat_test_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@gc_comdat_test.stdout: gc_comdat_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -C gc_comdat_test > gc_comdat_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@gc_tls_test.o: gc_tls_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@gc_tls_test:gc_tls_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--gc-sections gc_tls_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@gc_tls_test.stdout: gc_tls_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -C gc_tls_test > gc_tls_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@gc_orphan_section_test.o: gc_orphan_section_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@gc_orphan_section_test:gc_orphan_section_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--gc-sections gc_orphan_section_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@gc_orphan_section_test.stdout: gc_orphan_section_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) gc_orphan_section_test > gc_orphan_section_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@pr14265.o: pr14265.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -O0 -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@pr14265: pr14265.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -Wl,--gc-sections -Wl,-T,$(srcdir)/pr14265.t -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@pr14265.stdout: pr14265
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) --format=bsd --numeric-sort $< > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test.o: icf_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test: icf_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -o icf_test -Bgcctestdir/ -Wl,--icf=all,-Map,icf_test.map icf_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test.map: icf_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @touch icf_test.map
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_keep_unique_test.o: icf_keep_unique_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_keep_unique_test: icf_keep_unique_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all -Wl,--keep-unique,_Z11unique_funcv icf_keep_unique_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_keep_unique_test.stdout: icf_keep_unique_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -C $< > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_test.o: icf_safe_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_test: icf_safe_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -o icf_safe_test -Bgcctestdir/ -Wl,--icf=safe,-Map,icf_safe_test.map icf_safe_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_test.map: icf_safe_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @touch icf_safe_test.map
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_test_1.stdout: icf_safe_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) $< > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_test_2.stdout: icf_safe_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -h $< > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_so_test.o: icf_safe_so_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_so_test: icf_safe_so_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -o icf_safe_so_test -Bgcctestdir/ -Wl,--icf=safe,-Map,icf_safe_so_test.map icf_safe_so_test.o -fPIC -shared
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_so_test.map:
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @touch icf_safe_so_test.map
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_so_test_1.stdout: icf_safe_so_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) $< > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_so_test_2.stdout: icf_safe_so_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -h $< > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@final_layout.o: final_layout.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -fdata-sections -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@final_layout_sequence.txt:
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ (echo "*_Z3barv*" && echo ".text._Z3bazv" && echo "*_Z3foov*" && echo "*global_varb*" && echo "*global_vara*" && echo "*global_varc*") > final_layout_sequence.txt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@final_layout_script.lds:
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ (echo "SECTIONS { .text : { *(.text*) } .got : { *(.got .toc) } .sbss : { *(.sbss*) } .bss : { *(.bss*) } }") > final_layout_script.lds
+@GCC_TRUE@@NATIVE_LINKER_TRUE@final_layout: final_layout.o final_layout_sequence.txt final_layout_script.lds gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--section-ordering-file,final_layout_sequence.txt -Wl,-T,final_layout_script.lds final_layout.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@final_layout.stdout: final_layout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -n --synthetic final_layout > final_layout.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@text_section_grouping.o: text_section_grouping.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@text_section_grouping: text_section_grouping.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ text_section_grouping.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@text_section_no_grouping: text_section_grouping.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--no-text-reorder text_section_grouping.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@text_section_grouping.stdout: text_section_grouping
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -n --synthetic text_section_grouping > text_section_grouping.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@text_section_no_grouping.stdout: text_section_no_grouping
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -n --synthetic text_section_no_grouping > text_section_no_grouping.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@section_sorting_name.o: section_sorting_name.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@section_sorting_name: section_sorting_name.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--sort-section=name section_sorting_name.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@section_sorting_name.stdout: section_sorting_name
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -n --synthetic section_sorting_name > section_sorting_name.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_virtual_function_folding_test.o: icf_virtual_function_folding_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIE -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_virtual_function_folding_test: icf_virtual_function_folding_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_virtual_function_folding_test.o -pie
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_preemptible_functions_test.o: icf_preemptible_functions_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_preemptible_functions_test: icf_preemptible_functions_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_preemptible_functions_test.o -fPIC -shared
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_preemptible_functions_test.stdout: icf_preemptible_functions_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) icf_preemptible_functions_test > icf_preemptible_functions_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_string_merge_test.o: icf_string_merge_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_string_merge_test: icf_string_merge_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_string_merge_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_string_merge_test.stdout: icf_string_merge_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) icf_string_merge_test > icf_string_merge_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_sht_rel_addend_test_1.o: icf_sht_rel_addend_test_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_sht_rel_addend_test_2.o: icf_sht_rel_addend_test_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_sht_rel_addend_test: icf_sht_rel_addend_test_1.o icf_sht_rel_addend_test_2.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_sht_rel_addend_test_1.o icf_sht_rel_addend_test_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_sht_rel_addend_test.stdout: icf_sht_rel_addend_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) icf_sht_rel_addend_test > icf_sht_rel_addend_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@merge_string_literals_1.o: merge_string_literals_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O2 -c -fPIC -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@merge_string_literals_2.o: merge_string_literals_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O2 -c -fPIC -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@merge_string_literals: merge_string_literals_1.o merge_string_literals_2.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ merge_string_literals_1.o merge_string_literals_2.o -O2 -shared -nostdlib
+@GCC_TRUE@@NATIVE_LINKER_TRUE@merge_string_literals.stdout: merge_string_literals
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_OBJDUMP) -s -j.rodata merge_string_literals > merge_string_literals.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_test.o: basic_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_test: basic_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@basic_static_test: basic_test.o gcctestdir/ld
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -static basic_test.o
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_pic_test.o: basic_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_pic_test: basic_pic_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_pic_test.o
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@basic_static_pic_test: basic_pic_test.o gcctestdir/ld
+@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -static basic_pic_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_pie_test.o: basic_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_pie_test: basic_pie_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -pie basic_pie_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1_pic.o: two_file_test_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1b_pic.o: two_file_test_1b.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_2_pic.o: two_file_test_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1.so: two_file_test_1_pic.o two_file_test_1b_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_1b_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2.so: two_file_test_2_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared.so: two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable.o: gcctestdir/ld two_file_test_1.o two_file_test_1b.o two_file_test_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -r -o $@ two_file_test_1.o two_file_test_1b.o two_file_test_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1_pie.o: two_file_test_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1b_pie.o: two_file_test_1b.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_2_pie.o: two_file_test_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_main_pie.o: two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_pie_test: two_file_test_1_pie.o two_file_test_1b_pie.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2_pie.o two_file_test_main_pie.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -pie two_file_test_1_pie.o two_file_test_1b_pie.o two_file_test_2_pie.o two_file_test_main_pie.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared.dbg: two_file_shared.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -w $< >$@ 2>/dev/null
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic.so: two_file_test_1.o gcctestdir/ld
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o two_file_test_1b.o -Wl,-z,notext
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_nonpic.so: two_file_test_2.o gcctestdir/ld
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2.o
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_nonpic.so: two_file_test_1.o two_file_test_1b.o two_file_test_2.o gcctestdir/ld
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o two_file_test_1b.o two_file_test_2.o -Wl,-z,notext
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_mixed.so: two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2.o gcctestdir/ld
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2.o -Wl,-z,notext
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_mixed_1.so: two_file_test_1.o two_file_test_1b_pic.o two_file_shared_2.so gcctestdir/ld
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o two_file_test_1b_pic.o two_file_shared_2.so -Wl,-z,notext
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_mixed_pie_test: two_file_test_1.o two_file_test_1b_pie.o \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main_pie.o two_file_shared_2.so gcctestdir/ld
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,-R,. -pie two_file_test_1.o two_file_test_1b_pie.o two_file_test_main_pie.o two_file_shared_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_strip_test: two_file_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_STRIP) -o two_file_strip_test two_file_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_strip.so: two_file_shared.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_STRIP) -S -o two_file_shared_strip.so two_file_shared.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@common_test_2_pic.o: common_test_2.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@common_test_2.so: common_test_2_pic.o common_test_3.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -shared common_test_2_pic.o common_test_3.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@common_test_3_pic.o: common_test_3.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@common_test_3.so: common_test_3_pic.o ver_test_2.script gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -shared common_test_3_pic.o -Wl,--version-script,$(srcdir)/ver_test_2.script
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_test_1_pic.o: exception_test_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_test_2_pic.o: exception_test_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_1.so: exception_test_1_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared exception_test_1_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_2.so: exception_test_2_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared exception_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared.so: exception_test_1_pic.o exception_test_2_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared exception_test_1_pic.o exception_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_file1.o: weak_undef_file1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_file2.o: weak_undef_file2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_lib.so: weak_undef_file1.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared weak_undef_file1.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@alt/weak_undef_lib.so: weak_undef_file2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d alt || mkdir -p alt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared weak_undef_file2.o
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_file1_nonpic.o: weak_undef_file1.cc
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -o $@ $<
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_file2_nonpic.o: weak_undef_file2.cc
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -o $@ $<
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_undef_lib_nonpic.so: weak_undef_file1_nonpic.o
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared weak_undef_file1_nonpic.o -Wl,-z,notext
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@alt/weak_undef_lib_nonpic.so: weak_undef_file2_nonpic.o
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d alt || mkdir -p alt
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared weak_undef_file2_nonpic.o -Wl,-z,notext
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_alias_test_1_pic.o: weak_alias_test_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_alias_test_1.so: weak_alias_test_1_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared weak_alias_test_1_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_alias_test_2_pic.o: weak_alias_test_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_alias_test_2.so: weak_alias_test_2_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared weak_alias_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_alias_test_3.o: weak_alias_test_3.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_alias_test_4_pic.o: weak_alias_test_4.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_alias_test_4.so: weak_alias_test_4_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared weak_alias_test_4_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_alias_test_5_pic.o: weak_alias_test_5.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_alias_test_5.so: weak_alias_test_5_pic.o $(srcdir)/weak_alias_test.script gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared weak_alias_test_5_pic.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--version-script,$(srcdir)/weak_alias_test.script
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_plt_main_pic.o: weak_plt_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_plt: weak_plt_main_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ weak_plt_main_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_plt_shared_pic.o: weak_plt_shared.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@weak_plt_shared.so: weak_plt_shared_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared weak_plt_shared_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@copy_test_1_pic.o: copy_test_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@copy_test_1.so: gcctestdir/ld copy_test_1_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared copy_test_1_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@copy_test_2_pic.o: copy_test_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@copy_test_2.so: gcctestdir/ld copy_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared copy_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_pic.o: tls_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_file2_pic.o: tls_test_file2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_c_pic.o: tls_test_c.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(COMPILE) -c -fpic $(TLS_TEST_C_CFLAGS) -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared.so: tls_test_pic.o tls_test_file2_pic.o tls_test_c_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared tls_test_pic.o tls_test_file2_pic.o tls_test_c_pic.o -Wl,-z,defs
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared2.so: tls_test_file2_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared tls_test_file2_pic.o
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_pic_ie.o: tls_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpic -ftls-model=initial-exec -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_file2_pic_ie.o: tls_test_file2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpic -ftls-model=initial-exec -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_c_pic_ie.o: tls_test_c.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(COMPILE) -c -fpic -ftls-model=initial-exec $(TLS_TEST_C_CFLAGS) -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_ie_shared.so: tls_test_pic_ie.o tls_test_file2_pic_ie.o tls_test_c_pic_ie.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared tls_test_pic_ie.o tls_test_file2_pic_ie.o tls_test_c_pic_ie.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_c.o: tls_test_c.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(COMPILE) -c $(TLS_TEST_C_CFLAGS) -o $@ $<
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_main_pie.o: tls_test_main.cc tls_test.h
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_pie.o: tls_test.cc tls_test.h
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_file2_pie.o: tls_test_file2.cc tls_test.h
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_c_pie.o: tls_test_c.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(COMPILE) -c -fpic $(TLS_TEST_C_CFLAGS) -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_pie_test: tls_test_main_pie.o tls_test_pie.o tls_test_file2_pie.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_c_pie.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -Bgcctestdir/ -pie tls_test_main_pie.o tls_test_pie.o tls_test_file2_pie.o tls_test_c_pie.o -lpthread
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_pie_pic_test: tls_test_main_pie.o tls_test_pic.o tls_test_file2_pic.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_c_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -Bgcctestdir/ -pie tls_test_main_pie.o tls_test_pic.o tls_test_file2_pic.o tls_test_c_pic.o -lpthread
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_gnu2.o: tls_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_file2_gnu2.o: tls_test_file2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_c_gnu2.o: tls_test_c.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@ $(COMPILE) -c -fpic -mtls-dialect=gnu2 $(TLS_TEST_C_CFLAGS) -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_gnu2_shared2.so: tls_test_file2_gnu2.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared tls_test_file2_gnu2.o
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_gnu2_shared.so: tls_test_gnu2.o tls_test_file2_gnu2.o tls_test_c_gnu2.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared tls_test_gnu2.o tls_test_file2_gnu2.o tls_test_c_gnu2.o
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared_nonpic.so: tls_test.o tls_test_file2.o tls_test_c.o gcctestdir/ld
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared tls_test.o tls_test_file2.o tls_test_c.o -Wl,-z,notext
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_define.h:
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ (for i in `seq 1 70000`; do \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo "int var_$$i __attribute__((section(\"section_$$i\"))) = $$i;"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ done) > $@.tmp
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ mv -f $@.tmp $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_check.h:
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ (for i in `seq 1 1000 70000`; do \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo "assert(var_$$i == $$i);"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ done) > $@.tmp
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ mv -f $@.tmp $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_r_test.o: many_sections_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -r -o $@ many_sections_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_r_test: many_sections_r_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ many_sections_r_test.o $(LIBS)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@debug_msg.o: debug_msg.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/debug_msg.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@odr_violation1.o: odr_violation1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation1.cc
+# Compile with different optimization flags to check that rearranged
+# instructions don't cause a false positive.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@odr_violation2.o: odr_violation2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O2 -g -c -w -o $@ $(srcdir)/odr_violation2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@debug_msg.err: debug_msg.o odr_violation1.o odr_violation2.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @echo $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o "2>$@"
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @if $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o 2>$@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ then \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 1>&2 "Link of debug_msg should have failed"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exit 1; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ fi
+@GCC_TRUE@@NATIVE_LINKER_TRUE@missing_key_func.o: missing_key_func.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -o $@ $(srcdir)/missing_key_func.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@missing_key_func.err: missing_key_func.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @echo $(CXXLINK) -Bgcctestdir/ -o missing_key_func missing_key_func.o "2>$@"
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @if $(CXXLINK) -Bgcctestdir/ -o missing_key_func missing_key_func.o 2>$@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ then \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 1>&2 "Link of missing_key_func should have failed"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exit 1; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ fi
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@debug_msg_cdebug.o: debug_msg.cc gcctestdir/as
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g -Wa,--compress-debug-sections -c -w -o $@ $(srcdir)/debug_msg.cc
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@odr_violation1_cdebug.o: odr_violation1.cc gcctestdir/as
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g -Wa,--compress-debug-sections -c -w -o $@ $(srcdir)/odr_violation1.cc
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@odr_violation2_cdebug.o: odr_violation2.cc gcctestdir/as
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -Bgcctestdir/ -O2 -g -Wa,--compress-debug-sections -c -w -o $@ $(srcdir)/odr_violation2.cc
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@debug_msg_cdebug.err: debug_msg_cdebug.o odr_violation1_cdebug.o odr_violation2_cdebug.o gcctestdir/ld
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ @echo $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg_cdebug debug_msg_cdebug.o odr_violation1_cdebug.o odr_violation2_cdebug.o "2>$@"
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ @if $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg_cdebug debug_msg_cdebug.o odr_violation1_cdebug.o odr_violation2_cdebug.o 2>$@; \
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ then \
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ echo 1>&2 "Link of debug_msg_cdebug should have failed"; \
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@; \
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ exit 1; \
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ fi
+@GCC_TRUE@@NATIVE_LINKER_TRUE@debug_msg.so: debug_msg.cc gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g -shared -fPIC -w -o $@ $(srcdir)/debug_msg.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@odr_violation1.so: odr_violation1.cc gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g -shared -fPIC -w -o $@ $(srcdir)/odr_violation1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@odr_violation2.so: odr_violation2.cc gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -Bgcctestdir/ -O2 -g -shared -fPIC -w -o $@ $(srcdir)/odr_violation2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@debug_msg_so.err: debug_msg.so odr_violation1.so odr_violation2.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @echo $(CXXLINK_S) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg_so debug_msg.so odr_violation1.so odr_violation2.so "2>$@"
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @if $(CXXLINK_S) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg_so debug_msg.so odr_violation1.so odr_violation2.so 2>$@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ then \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 1>&2 "Link of debug_msg_so should have failed"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exit 1; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ fi
+@GCC_TRUE@@NATIVE_LINKER_TRUE@debug_msg_ndebug.so: debug_msg.cc gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g0 -shared -fPIC -w -o $@ $(srcdir)/debug_msg.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@odr_violation1_ndebug.so: odr_violation1.cc gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g0 -shared -fPIC -w -o $@ $(srcdir)/odr_violation1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@odr_violation2_ndebug.so: odr_violation2.cc gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -Bgcctestdir/ -O2 -g0 -shared -fPIC -w -o $@ $(srcdir)/odr_violation2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@debug_msg_ndebug.err: debug_msg_ndebug.so odr_violation1_ndebug.so odr_violation2_ndebug.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @echo $(CXXLINK_S) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg_ndebug debug_msg_ndebug.so odr_violation1_ndebug.so odr_violation2_ndebug.so -shared-libgcc -Bdynamic -lstdc++ "2>$@"
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @if $(CXXLINK_S) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg_ndebug debug_msg_ndebug.so odr_violation1_ndebug.so odr_violation2_ndebug.so -shared-libgcc -Bdynamic -lstdc++ 2>$@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ then \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 1>&2 "Link of debug_msg_ndebug should have failed"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exit 1; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ fi
+@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.o: undef_symbol.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -fPIC $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.so: undef_symbol.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared undef_symbol.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.err: undef_symbol_main.o undef_symbol.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @echo $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so "2>$@"
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @if $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so 2>$@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ then \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 1>&2 "Link of undef_symbol_test should have failed"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exit 1; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ fi
+@GCC_TRUE@@NATIVE_LINKER_TRUE@flagstest_o_specialfile: flagstest_debug.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -o /dev/stdout $< 2>&1 | cat > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ chmod a+x $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -s $@
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@flagstest_compress_debug_sections: flagstest_debug.o gcctestdir/ld
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -o $@ $< -Wl,--compress-debug-sections=zlib
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ test -s $@
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@flagstest_o_specialfile_and_compress_debug_sections: flagstest_debug.o \
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -o /dev/stdout $< -Wl,--compress-debug-sections=zlib 2>&1 | cat > $@
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ chmod a+x $@
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ test -s $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@flagstest_o_ttext_1: flagstest_debug.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -o $@ $< -Wl,-Ttext,0x400000 -Wl,-Tdata,0x800000
+@GCC_TRUE@@NATIVE_LINKER_TRUE@flagstest_o_ttext_2: flagstest_debug.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -o $@ $< -Wl,-Ttext,0x400010 -Wl,-Tdata,0x800010
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_1.so: ver_test_1.o ver_test_2.so ver_test_3.o ver_test_4.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared ver_test_1.o ver_test_2.so ver_test_3.o ver_test_4.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_2.so: ver_test_2.o $(srcdir)/ver_test_2.script ver_test_4.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_2.script -Wl,-R,. ver_test_2.o ver_test_4.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_4.so: ver_test_4.o $(srcdir)/ver_test_4.script gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_4.script ver_test_4.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_1.o: ver_test_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_2.o: ver_test_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_3.o: ver_test_3.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_4.o: ver_test_4.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_1.syms: ver_test_1.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -s $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_2.syms: ver_test_2
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -s $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_4.syms: ver_test_4.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -s $< >$@ 2>/dev/null
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_5.so: ver_test_5.o $(srcdir)/ver_test_5.script ver_test_4.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_5.script ver_test_5.o ver_test_4.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_5.o: ver_test_5.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_5.syms: ver_test_5.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -s $< >$@ 2>/dev/null
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_7.so: ver_test_4.o $(srcdir)/ver_test_4.script ver_test_7.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_4.script ver_test_4.o ver_test_7.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_7.o: ver_test_7.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_7.syms: ver_test_7.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -s $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_8_1.so: two_file_test_1_pic.o two_file_test_1b_pic.o ver_test_8_2.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_1b_pic.o ver_test_8_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_8_2.so: two_file_test_2_pic.o $(srcdir)/ver_test_8.script gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_8.script two_file_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_9.so: ver_test_9.o ver_test_4.so ver_test_5.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-R,. ver_test_9.o ver_test_5.so ver_test_4.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_9.o: ver_test_9.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_10.syms: ver_test_10.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -s $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_10.so: gcctestdir/ld ver_test_2.o ver_test_10.script
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_10.script ver_test_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_11.a: ver_test_1.o ver_test_2.o ver_test_4.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc $@ $^
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_12.o: gcctestdir/ld ver_test_1.o ver_test_2.o ver_test_4.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -r -o $@ ver_test_1.o ver_test_2.o ver_test_4.o
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_1.so: gcctestdir/ld protected_1_pic.o protected_2_pic.o protected_3_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared protected_1_pic.o protected_2_pic.o protected_3_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_1_pic.o: protected_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_2_pic.o: protected_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_3_pic.o: protected_3.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_4_pic.o: protected_4.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@protected_3.err: protected_4_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @echo $(CXXLINK) -Bgcctestdir/ -shared -o protected_4.so protected_4_pic.o "2>$@"
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @if $(CXXLINK) -Bgcctestdir/ -shared -o protected_4.so protected_4_pic.o 2>$@; then \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 1>&2 "Link of protected_4.so should have failed"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ exit 1; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ fi
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_test.so: gcctestdir/ld relro_test_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-z,relro relro_test_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_test_pic.o: relro_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_test.stdout: relro_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -SlW relro_test.so > relro_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_now_test.so: gcctestdir/ld relro_test_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-z,relro -Wl,-z,now relro_test_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_strip_test.so: relro_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_STRIP) -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_script_test.so: gcctestdir/ld relro_script_test.t relro_test_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-z,relro -Wl,-T,$(srcdir)/relro_script_test.t relro_test_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_2.o: justsyms_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_2r.o: justsyms_2.o gcctestdir/ld $(srcdir)/justsyms.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -o $@ -r -T $(srcdir)/justsyms.t justsyms_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_lib.o: justsyms_lib.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_lib: justsyms_lib.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -o $@ -Ttext=0x1000200 -Tdata=0x2000000 -e exported_func justsyms_lib.o
+# Copy the file to the build directory to avoid worrying about the
+# full pathname in the generated symbols.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@binary.txt: $(srcdir)/binary.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LN_S) $< $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_matching_def.so: ver_matching_def_pic.o $(srcdir)/version_script.map gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -O0 -Bgcctestdir/ -shared ver_matching_def_pic.o -Wl,--version-script=$(srcdir)/version_script.map
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_matching_def_pic.o: ver_matching_def.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_matching_test.stdout: ver_matching_def.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_OBJDUMP) -T ver_matching_def.so | $(TEST_CXXFILT) > ver_matching_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_3: basic_test.o gcctestdir/ld script_test_3.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o -Wl,-T,$(srcdir)/script_test_3.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_3.stdout: script_test_3
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -SlW script_test_3 > script_test_3.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_4: basic_test.o gcctestdir/ld $(srcdir)/script_test_4.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o -Wl,-T,$(srcdir)/script_test_4.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_4.stdout: script_test_4
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -SlW script_test_4 > script_test_4.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_5: script_test_5.o gcctestdir/ld $(srcdir)/script_test_5.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ script_test_5.o -Wl,-T,$(srcdir)/script_test_5.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_5.stdout: script_test_5
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -SW script_test_5 > script_test_5.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_6: basic_test.o gcctestdir/ld $(srcdir)/script_test_6.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o -Wl,-T,$(srcdir)/script_test_6.t \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,-Ttext=0x10001000 -Wl,-Tdata=0x10200000 -Wl,-Tbss=0x10400000
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_6.stdout: script_test_6
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -SlW script_test_6 > script_test_6.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_7: basic_test.o gcctestdir/ld $(srcdir)/script_test_7.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o -Wl,-T,$(srcdir)/script_test_7.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_7.stdout: script_test_7
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -SlW script_test_7 > script_test_7.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_8: basic_test.o gcctestdir/ld $(srcdir)/script_test_7.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o -Wl,-T,$(srcdir)/script_test_7.t \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,-Ttext=0x20001000 -Wl,-Tdata=0x20200000 -Wl,-Tbss=0x20400000
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_8.stdout: script_test_8
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -SlW script_test_8 > script_test_8.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_9.o: script_test_9.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_9: gcctestdir/ld $(srcdir)/script_test_9.t script_test_9.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ script_test_9.o -Wl,-T,$(srcdir)/script_test_9.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_9.stdout: script_test_9
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -lW script_test_9 > script_test_9.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_11: gcctestdir/ld script_test_11_r.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ script_test_11_r.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_11_r.o: gcctestdir/ld $(srcdir)/script_test_11.t script_test_11.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -r -o $@ -T $(srcdir)/script_test_11.t script_test_11.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_11.o: script_test_11.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@dynamic_list: basic_test.o gcctestdir/ld $(srcdir)/dynamic_list.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--dynamic-list $(srcdir)/dynamic_list.t \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--dynamic-list-data \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--dynamic-list-cpp-new \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--dynamic-list-cpp-typeinfo
+@GCC_TRUE@@NATIVE_LINKER_TRUE@dynamic_list.stdout: dynamic_list
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -W --dyn-syms dynamic_list > dynamic_list.stdout
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@libthin1.a: thin_archive_test_1.o alt/thin_archive_test_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) crT $@ $^
+@GCC_TRUE@@NATIVE_LINKER_TRUE@alt/libthin2.a: thin_archive_test_3.o alt/thin_archive_test_4.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) crT $@ $^
+@GCC_TRUE@@NATIVE_LINKER_TRUE@libthin3.a: thin_archive_test_1.o alt/thin_archive_test_4.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) crT $@ $^
+@GCC_TRUE@@NATIVE_LINKER_TRUE@alt/libthin4.a: alt/thin_archive_test_2.o thin_archive_test_3.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) crT $@ $^
+@GCC_TRUE@@NATIVE_LINKER_TRUE@libthinall.a: libthin3.a alt/libthin4.a
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) crT $@ $^
+@GCC_TRUE@@NATIVE_LINKER_TRUE@alt/thin_archive_test_2.o: thin_archive_test_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d alt || mkdir -p alt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@alt/thin_archive_test_4.o: thin_archive_test_4.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d alt || mkdir -p alt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_1: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms empty.syms gcctestdir/ld plugin_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv" two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms empty.syms 2>plugin_test_1.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_1.err: plugin_test_1
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ @touch plugin_test_1.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_2: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_shared_2.so gcctestdir/ld plugin_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,-R,.,--plugin,"./plugin_test.so" two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_shared_2.so 2>plugin_test_2.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_2.err: plugin_test_2
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ @touch plugin_test_2.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_3: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms empty.syms gcctestdir/ld plugin_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--export-dynamic -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv" two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms empty.syms 2>plugin_test_3.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_3.err: plugin_test_3
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ @touch plugin_test_3.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_4: two_file_test_main.o plugin_test_4.a gcctestdir/ld plugin_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv" two_file_test_main.o -Wl,--whole-archive,plugin_test_4.a,--no-whole-archive 2>plugin_test_4.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_4.err: plugin_test_4
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ @touch plugin_test_4.err
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_4.a: two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_AR) cr $@ $^
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_5: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms unused.syms gcctestdir/ld plugin_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv",--gc-sections two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms unused.syms
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_6: plugin_common_test_1.syms plugin_common_test_2.syms gcctestdir/ld plugin_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so" plugin_common_test_1.syms plugin_common_test_2.syms 2>plugin_test_6.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_6.err: plugin_test_6
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ @touch plugin_test_6.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_7: plugin_test_7_1.o plugin_test_7_1.syms plugin_test_7_2.o gcctestdir/ld plugin_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(LINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--gc-sections,--print-gc-sections plugin_test_7_1.syms plugin_test_7_2.o 2>plugin_test_7.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_7.syms: plugin_test_7
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_7_1.o: plugin_test_7_1.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(COMPILE) -DLTO -O0 -c -ffunction-sections -fdata-sections -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_7_1_orig.o: plugin_test_7_1.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(COMPILE) -O0 -c -ffunction-sections -fdata-sections -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_7_1.syms: plugin_test_7_1_orig.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_7_2.o: plugin_test_7_2.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(COMPILE) -O0 -c -ffunction-sections -fdata-sections -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_7.err: plugin_test_7
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_8.o: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.o ../ld-new plugin_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ ../ld-new -r -o $@ --no-demangle --plugin "./plugin_test.so" two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_8: plugin_test_8.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle plugin_test_8.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_9.err: two_file_test_main.o two_file_test_1c.syms two_file_test_2.syms gcctestdir/ld plugin_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ @echo $(CXXLINK) -Bgcctestdir/ -o plugin_test_9 -Wl,--no-demangle,--plugin,"./plugin_test.so" two_file_test_main.o two_file_test_1c.syms two_file_test_2.syms "2>$@"
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ @if $(CXXLINK) -Bgcctestdir/ -o plugin_test_9 -Wl,--no-demangle,--plugin,"./plugin_test.so" two_file_test_main.o two_file_test_1c.syms two_file_test_2.syms 2>$@; then \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ echo 1>&2 "Link of plugin_test_9 should have failed"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ rm -f $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ exit 1; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ fi
+# Make a .syms file that claims to define the symbol _Z4t16av.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@two_file_test_1c.syms: two_file_test_1.syms two_file_test_1c.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ cp two_file_test_1.syms $@.tmp
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ grep "_Z4t16av" two_file_test_1b.syms >> $@.tmp
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ mv -f $@.tmp $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@two_file_test_1c.o: two_file_test_1.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ cp two_file_test_1.o $@
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test.so: plugin_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(LINK) -Bgcctestdir/ -shared plugin_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test.o: plugin_test.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(COMPILE) -O0 -c -fpic -o $@ $<
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@two_file_test_main.syms: two_file_test_main.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@two_file_test_1.syms: two_file_test_1.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@two_file_test_1b.syms: two_file_test_1b.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@two_file_test_2.syms: two_file_test_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_common_test_1.syms: plugin_common_test_1.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_common_test_2.syms: plugin_common_test_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@empty.syms:
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ @echo "" >$@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ @echo "Symbol table" >>$@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@@TLS_TRUE@plugin_test_tls: two_file_test_tls.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2_tls.syms gcctestdir/ld plugin_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@@TLS_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv" two_file_test_tls.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2_tls.syms 2>plugin_test_tls.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@@TLS_TRUE@plugin_test_tls.err: plugin_test_tls
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@@TLS_TRUE@ @touch plugin_test_tls.err
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@@TLS_TRUE@two_file_test_2_tls.syms: two_file_test_2_tls.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@@TLS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@unused.syms: unused.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ @echo " 1: 00000000 4 FUNC GLOBAL DEFAULT 1 UNUSED" >>$@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@unused.o: unused.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(COMPILE) -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@unused.c:
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ @cp /dev/null $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_final_layout.o: plugin_final_layout.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -fdata-sections -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_final_layout: plugin_final_layout.o plugin_section_order.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--plugin,"./plugin_section_order.so" plugin_final_layout.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_final_layout.stdout: plugin_final_layout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_NM) -n --synthetic plugin_final_layout > plugin_final_layout.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_final_layout_readelf.stdout: plugin_final_layout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -Wl plugin_final_layout > plugin_final_layout_readelf.stdout
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_section_order.so: plugin_section_order.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(LINK) -Bgcctestdir/ -shared plugin_section_order.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_section_order.o: plugin_section_order.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(COMPILE) -O0 -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exclude_libs_test.syms: exclude_libs_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@libexclude_libs_test_1.a: exclude_libs_test_1.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc $@ $^
+@GCC_TRUE@@NATIVE_LINKER_TRUE@libexclude_libs_test_2.a: exclude_libs_test_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc $@ $^
+@GCC_TRUE@@NATIVE_LINKER_TRUE@alt/libexclude_libs_test_3.a: exclude_libs_test_3.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d alt || mkdir -p alt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc $@ $^
+@GCC_TRUE@@NATIVE_LINKER_TRUE@local_labels_test.o: ver_test_6.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -g -c -Wa,-L -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@local_labels_test: local_labels_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ local_labels_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_test.syms: discard_locals_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+# '-Wa,-L' is required to preserve the local label used for testing.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_test.o: discard_locals_test.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -Wa,-L -o $@ $<
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_relocatable_test1.syms: discard_locals_relocatable_test1.out
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_relocatable_test.o: discard_locals_relocatable_test.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -Wa,-L -fPIC -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_relocatable_test1.out: discard_locals_relocatable_test.o ../ld-new
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ../ld-new --discard-locals -relocatable -o $@ $<
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_relocatable_test2.syms: discard_locals_relocatable_test2.out
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_relocatable_test2.out: discard_locals_relocatable_test.o ../ld-new
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ../ld-new --discard-all -relocatable -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@libhidden.so: hidden_test_1.c gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -Bgcctestdir/ -g -shared -fPIC -w -o $@ $(srcdir)/hidden_test_1.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@hidden_test: hidden_test_main.o libhidden.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -Wl,-R,. hidden_test_main.o libhidden.so 2>hidden_test.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@hidden_test.err: hidden_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @touch hidden_test.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@retain_symbols_file_test.so: basic_pic_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 'main' > retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 't1' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo '_ZN4t16bC1Ev' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo '_ZNK4t20a3getEv' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo '_Z3t18v' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo '__tcf_0' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-retain-symbols-file,retain_symbols_file_test.in basic_pic_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@retain_symbols_file_test.stdout: retain_symbols_file_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -C retain_symbols_file_test.so > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@permission_test: basic_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ umask 022; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ touch $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ chmod 600 $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_lib.o: searched_file_test_lib.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@alt/searched_file_test_lib.a: searched_file_test_lib.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d alt || mkdir -p alt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc $@ $^
+# We invoke the linker directly since gcc may include additional objects that
+# uses symbol versioning.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@libno_version_test.so: no_version_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -shared -o $@ no_version_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@no_version_test.o: no_version_test.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -o $@ -c -fPIC $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@no_version_test.stdout: libno_version_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_OBJDUMP) -h $< > $@
+
+# Test STT_GNU_IFUNC symbols.
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmod1.o: ifuncmod1.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIC -o $@ $<
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmod1.so: ifuncmod1.o gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -shared ifuncmod1.o
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncdep1.o: ifuncmod1.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -o $@ $<
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1pic.o: ifuncmain1.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIC -o $@ $<
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1pie.o: ifuncmain1.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIE -o $@ $<
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1picstatic: ifuncmain1pic.o ifuncmod1.o gcctestdir/ld
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -static ifuncmain1pic.o ifuncmod1.o
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1pic: ifuncmain1pic.o ifuncmod1.so gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ ifuncmain1pic.o ifuncmod1.so -Wl,-R,.
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1vispic.o: ifuncmain1vis.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIC -o $@ $<
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1vispic: ifuncmain1vispic.o ifuncmod1.so gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ ifuncmain1pic.o ifuncmod1.so -Wl,-R,.
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1staticpic: ifuncmain1pic.o ifuncmod1.o gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ ifuncmain1pic.o ifuncmod1.o
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1pie: ifuncmain1pie.o ifuncmod1.so gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -pie ifuncmain1pie.o ifuncmod1.so -Wl,-R,.
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1vispie.o: ifuncmain1vis.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIE -o $@ $<
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1vispie: ifuncmain1vispie.o ifuncmod1.so gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -pie ifuncmain1vispie.o ifuncmod1.so -Wl,-R,.
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain1staticpie: ifuncmain1pie.o ifuncmod1.o gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -pie ifuncmain1pie.o ifuncmod1.o
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain2pic.o: ifuncmain2.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIC -o $@ $<
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncdep2pic.o: ifuncdep2.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIC -o $@ $<
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain2picstatic: ifuncmain2pic.o ifuncdep2pic.o gcctestdir/ld
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -static ifuncmain2pic.o ifuncdep2pic.o
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain2pic: ifuncmain2pic.o ifuncdep2pic.o gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ ifuncmain2pic.o ifuncdep2pic.o
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmod3.o: ifuncmod3.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIC -o $@ $<
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmod3.so: ifuncmod3.o gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -shared ifuncmod3.o
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain4pic.o: ifuncmain4.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIC -o $@ $<
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain4picstatic: ifuncmain4pic.o gcctestdir/ld
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -static ifuncmain4pic.o
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5pic.o: ifuncmain5.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIC -o $@ $<
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5pie.o: ifuncmain5.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIE -o $@ $<
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmod5.o: ifuncmod5.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIC -o $@ $<
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmod5.so: ifuncmod5.o gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -shared ifuncmod5.o
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncdep5.o: ifuncmod5.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -o $@ $<
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5picstatic: ifuncmain5pic.o ifuncmod5.o gcctestdir/ld
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -static ifuncmain5pic.o ifuncmod5.o
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5pic: ifuncmain5pic.o ifuncmod5.so gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ ifuncmain5pic.o ifuncmod5.so -Wl,-R,.
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5staticpic: ifuncmain5pic.o ifuncmod5.o gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ ifuncmain5pic.o ifuncmod5.o
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain5pie: ifuncmain5pie.o ifuncmod5.so gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -pie ifuncmain5pie.o ifuncmod5.so -Wl,-R,.
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain6pie.o: ifuncmain6pie.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIE -o $@ $<
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmod6.o: ifuncmod6.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIC -o $@ $<
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmod6.so: ifuncmod6.o gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -shared ifuncmod6.o
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain6pie: ifuncmain6pie.o ifuncmod6.so gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -pie ifuncmain6pie.o ifuncmod6.so -Wl,-R,.
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7pic.o: ifuncmain7.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIC -o $@ $<
+
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7pie.o: ifuncmain7.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIE -o $@ $<
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7picstatic: ifuncmain7pic.o gcctestdir/ld
+@GCC_TRUE@@HAVE_STATIC_TRUE@@IFUNC_STATIC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -static ifuncmain7pic.o
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7pic: ifuncmain7pic.o gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ ifuncmain7pic.o
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7pie: ifuncmain7pie.o gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -pie ifuncmain7pie.o
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar1_pic.o: ifuncvar1.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIC -o $@ $<
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar2_pic.o: ifuncvar2.c
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fPIC -o $@ $<
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar.so: ifuncvar1_pic.o ifuncvar2_pic.o gcctestdir/ld
+@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -shared ifuncvar1_pic.o ifuncvar2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@strong_ref_weak_def_2.o: strong_ref_weak_def_2.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -o $@ -c -fPIC $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@strong_ref_weak_def_2.so: strong_ref_weak_def_2.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -shared -o $@ strong_ref_weak_def_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@strong_ref_weak_def_1.o: strong_ref_weak_def_1.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -o $@ -c -fPIC $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@strong_ref_weak_def_1.so: strong_ref_weak_def_1.o strong_ref_weak_def_2.so \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -shared -o $@ strong_ref_weak_def_1.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ strong_ref_weak_def_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@strong_ref_weak_def.stdout: strong_ref_weak_def_1.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -sWD $< > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@dyn_weak_ref_2.o: dyn_weak_ref_2.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -o $@ -c -fPIC $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@dyn_weak_ref_2.so: dyn_weak_ref_2.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -shared -o $@ dyn_weak_ref_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@dyn_weak_ref_1.o: dyn_weak_ref_1.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -o $@ -c -fPIC $<
+# We intentionally put dyn_weak_ref_2.so in front of dyn_weak_ref_1.o
+# so that the weak ref there goes to gold's symbol table first.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@dyn_weak_ref_1.so: dyn_weak_ref_1.o dyn_weak_ref_2.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -shared -o $@ dyn_weak_ref_2.so dyn_weak_ref_1.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@dyn_weak_ref.stdout: dyn_weak_ref_1.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -sWD $< > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@start_lib_test: start_lib_test_main.o libstart_lib_test.a start_lib_test_2.o start_lib_test_3.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -o $@ start_lib_test_main.o -L. -lstart_lib_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--start-lib start_lib_test_2.o start_lib_test_3.o -Wl,--end-lib
+@GCC_TRUE@@NATIVE_LINKER_TRUE@libstart_lib_test.a: start_lib_test_1.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc $@ $^
+@GCC_TRUE@@NATIVE_LINKER_TRUE@memory_test.o: memory_test.s
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -o $@ -c $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@memory_test: memory_test.o gcctestdir/ld $(srcdir)/memory_test.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -nostartfiles -nostdlib -z max-page-size=0x1000 -z common-page-size=0x1000 -Wl,-T,$(srcdir)/memory_test.t -o $@ memory_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@memory_test.stdout: memory_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -lWS $< > $@
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test.o: gdb_index_test.cc
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -gno-pubnames -c -o $@ $<
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_1: gdb_index_test.o gcctestdir/ld
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--gdb-index $<
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_1.stdout: gdb_index_test_1
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) --debug-dump=gdb_index $< > $@
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_cdebug.o: gdb_index_test.cc
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g -Wa,--compress-debug-sections -c -o $@ $<
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_2: gdb_index_test_cdebug.o gcctestdir/ld
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--gdb-index $<
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_2.stdout: gdb_index_test_2
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) --debug-dump=gdb_index $< > $@
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_3.o: gdb_index_test_3.c
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -O0 -g -c -o $@ $<
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_3: gdb_index_test_3.o gcctestdir/ld
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -Wl,--gdb-index,--fatal-warnings $<
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_3.stdout: gdb_index_test_3
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) --debug-dump=gdb_index $< > $@
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_pub.o: gdb_index_test.cc
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -gpubnames -c -o $@ $<
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_4: gdb_index_test_pub.o gcctestdir/ld
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--gdb-index $<
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_4.stdout: gdb_index_test_4
+@GCC_TRUE@@HAVE_PUBNAMES_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) --debug-dump=gdb_index $< > $@
+
+# End-to-end incremental linking tests.
+# Incremental linking is currently supported only on the x86_64 target.
+
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1_v1_ndebug.o: two_file_test_1_v1.cc
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g0 -c -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1_ndebug.o: two_file_test_1.cc
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g0 -c -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1b_ndebug.o: two_file_test_1b.cc
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g0 -c -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_2_ndebug.o: two_file_test_2.cc
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g0 -c -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_main_ndebug.o: two_file_test_main.cc
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g0 -c -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_2: two_file_test_1_v1_ndebug.o two_file_test_1_ndebug.o two_file_test_1b_ndebug.o \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2_ndebug.o two_file_test_main_ndebug.o gcctestdir/ld
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f two_file_test_1_v1_ndebug.o two_file_test_tmp_2.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_tmp_2.o two_file_test_1b_ndebug.o two_file_test_2_ndebug.o two_file_test_main_ndebug.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ @sleep 1
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f two_file_test_1_ndebug.o two_file_test_tmp_2.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_tmp_2.o two_file_test_1b_ndebug.o two_file_test_2_ndebug.o two_file_test_main_ndebug.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_3: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2.o two_file_test_main.o gcctestdir/ld
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f two_file_test_1b_v1.o two_file_test_tmp_3.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ @sleep 1
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f two_file_test_1b.o two_file_test_tmp_3.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_4: two_file_test_1.o two_file_test_1b.o two_file_test_2_v1.o \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2.o two_file_test_main.o gcctestdir/ld
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f two_file_test_2_v1.o two_file_test_tmp_4.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ mv -f incremental_test_4 incremental_test_4.base
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ @sleep 1
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f two_file_test_2.o two_file_test_tmp_4.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-update,--incremental-base=incremental_test_4.base -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_5: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2.o two_file_test_main.o gcctestdir/ld
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f two_file_test_1b_v1.o two_file_test_tmp_5.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ @sleep 1
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f two_file_test_1b.o two_file_test_tmp_5.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_6: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2.o two_file_test_main.o gcctestdir/ld
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f two_file_test_1b.o two_file_test_tmp_6.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ @sleep 1
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f two_file_test_1b_v1.o two_file_test_tmp_6.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_main.o -Wl,--incremental-unchanged two_file_test_6.a -Wl,--incremental-unknown
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_copy_test: copy_test_v1.o copy_test.o copy_test_1.so copy_test_2.so
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f copy_test_v1.o copy_test_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ -Wl,-R,. -Wl,--no-as-needed copy_test_tmp.o copy_test_1.so copy_test_2.so
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ @sleep 1
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f copy_test.o copy_test_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ -Wl,-R,. -Wl,--no-as-needed copy_test_tmp.o copy_test_1.so copy_test_2.so
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_common_test_1: common_test_1_v1.o common_test_1_v2.o gcctestdir/ld
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f common_test_1_v1.o common_test_1_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ common_test_1_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ @sleep 1
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f common_test_1_v2.o common_test_1_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ common_test_1_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_comdat_test_1: incr_comdat_test_1.o incr_comdat_test_2_v1.o incr_comdat_test_2_v2.o incr_comdat_test_2_v3.o gcctestdir/ld
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f incr_comdat_test_2_v1.o incr_comdat_test_1_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ incr_comdat_test_1.o incr_comdat_test_1_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ @sleep 1
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f incr_comdat_test_2_v2.o incr_comdat_test_1_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ incr_comdat_test_1.o incr_comdat_test_1_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ @sleep 1
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ cp -f incr_comdat_test_2_v3.o incr_comdat_test_1_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ incr_comdat_test_1.o incr_comdat_test_1_tmp.o
+@NATIVE_OR_CROSS_LINKER_TRUE@script_test_10.o: script_test_10.s
+@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+@NATIVE_OR_CROSS_LINKER_TRUE@script_test_10: $(srcdir)/script_test_10.t script_test_10.o gcctestdir/ld
+@NATIVE_OR_CROSS_LINKER_TRUE@ gcctestdir/ld -o $@ script_test_10.o -T $(srcdir)/script_test_10.t
+@NATIVE_OR_CROSS_LINKER_TRUE@script_test_10.stdout: script_test_10
+@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_READELF) -SW script_test_10 > $@
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_1.o: split_i386_1.s
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_2.o: split_i386_2.s
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_3.o: split_i386_3.s
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_4.o: split_i386_4.s
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_n.o: split_i386_n.s
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_1: split_i386_1.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_1.o split_i386_n.o
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_1.stdout: split_i386_1
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_2: split_i386_2.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_2.o split_i386_n.o
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_2.stdout: split_i386_2
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_3.stdout: split_i386_3.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o split_i386_3 split_i386_3.o split_i386_n.o > $@ 2>&1 || exit 0
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_4: split_i386_4.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_4.o split_i386_n.o
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_4.stdout: split_i386_4
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_r.stdout: split_i386_1.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -r split_i386_1.o split_i386_n.o -o split_i386_r > $@ 2>&1 || exit 0
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_1.o: split_x86_64_1.s
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_2.o: split_x86_64_2.s
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_3.o: split_x86_64_3.s
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_4.o: split_x86_64_4.s
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_n.o: split_x86_64_n.s
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_1: split_x86_64_1.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_1.o split_x86_64_n.o
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_1.stdout: split_x86_64_1
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_2: split_x86_64_2.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_2.o split_x86_64_n.o
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_2.stdout: split_x86_64_2
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_3.stdout: split_x86_64_3.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o split_x86_64_3 split_x86_64_3.o split_x86_64_n.o > $@ 2>&1 || exit 0
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_4: split_x86_64_4.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_4.o split_x86_64_n.o
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_4.stdout: split_x86_64_4
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_r.stdout: split_x86_64_1.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -r split_x86_64_1.o split_x86_64_n.o -o split_x86_64_r > $@ 2>&1 || exit 0
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_abs_lib.o: arm_abs_lib.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv7-a -o $@ $<
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@libarm_abs.so: arm_abs_lib.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -shared -o $@ arm_abs_lib.o
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_abs_global.o: arm_abs_global.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv7-a -o $@ $<
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_abs_global: arm_abs_global.o libarm_abs.so ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -o $@ arm_abs_global.o -L. -larm_abs
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_abs_global.stdout: arm_abs_global
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_READELF) -r $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_bl_in_range.stdout: arm_bl_in_range
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_bl_in_range: arm_bl_in_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -T $(srcdir)/arm_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_bl_in_range.o: arm_bl_in_range.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_bl_out_of_range.stdout: arm_bl_out_of_range
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -S $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_bl_out_of_range: arm_bl_out_of_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -T $(srcdir)/arm_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_bl_out_of_range.o: arm_bl_out_of_range.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_bl_in_range.stdout: thumb_bl_in_range
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_bl_in_range: thumb_bl_in_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --no-fix-arm1176 -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_bl_in_range.o: thumb_bl_in_range.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ -march=armv5te $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_bl_out_of_range.stdout: thumb_bl_out_of_range
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_bl_out_of_range: thumb_bl_out_of_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --no-fix-arm1176 -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_bl_out_of_range.o: thumb_bl_out_of_range.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ -march=armv5te $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb2_bl_in_range.stdout: thumb2_bl_in_range
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb2_bl_in_range: thumb2_bl_in_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb2_bl_in_range.o: thumb_bl_in_range.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ -march=armv7-a $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb2_bl_out_of_range.stdout: thumb2_bl_out_of_range
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb2_bl_out_of_range: thumb2_bl_out_of_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb2_bl_out_of_range.o: thumb_bl_out_of_range.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ -march=armv7-a $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_blx_in_range.stdout: thumb_blx_in_range
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_blx_in_range: thumb_blx_in_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --no-fix-arm1176 -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_blx_in_range.o: thumb_blx_in_range.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ -march=armv5te $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_blx_out_of_range.stdout: thumb_blx_out_of_range
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_blx_out_of_range: thumb_blx_out_of_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --no-fix-arm1176 -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_blx_out_of_range.o: thumb_blx_out_of_range.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ -march=armv5te $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb2_blx_in_range.stdout: thumb2_blx_in_range
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb2_blx_in_range: thumb2_blx_in_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb2_blx_in_range.o: thumb_blx_in_range.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ -march=armv7-a $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb2_blx_out_of_range.stdout: thumb2_blx_out_of_range
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb2_blx_out_of_range: thumb2_blx_out_of_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb2_blx_out_of_range.o: thumb_blx_out_of_range.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ -march=armv7-a $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_bl_out_of_range_local.stdout: thumb_bl_out_of_range_local
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_bl_out_of_range_local: thumb_bl_out_of_range_local.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --no-fix-arm1176 -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@thumb_bl_out_of_range_local.o: thumb_bl_out_of_range_local.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ -march=armv5te $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_thm_jump11.stdout: arm_thm_jump11
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_thm_jump11: arm_thm_jump11.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -T $(srcdir)/arm_thm_jump11.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_thm_jump11.o: arm_thm_jump11.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_thm_jump8.stdout: arm_thm_jump8
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_thm_jump8: arm_thm_jump8.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -T $(srcdir)/arm_thm_jump8.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_thm_jump8.o: arm_thm_jump8.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_v4bx.stdout: arm_fix_v4bx
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_v4bx: arm_fix_v4bx.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --no-fix-arm1176 --fix-v4bx -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_v4bx.o: arm_fix_v4bx.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_v4bx_interworking.stdout: arm_fix_v4bx_interworking
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_v4bx_interworking: arm_fix_v4bx.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --no-fix-arm1176 --fix-v4bx-interworking -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_no_fix_v4bx.stdout: arm_no_fix_v4bx
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_no_fix_v4bx: arm_fix_v4bx.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --no-fix-arm1176 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_attr_merge_6.stdout: arm_attr_merge_6
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_READELF) -A $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_attr_merge_6: arm_attr_merge_6a.o arm_attr_merge_6b.o
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -o $@ arm_attr_merge_6a.o arm_attr_merge_6b.o
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_attr_merge_6a.o: arm_attr_merge_6a.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_attr_merge_6b.o: arm_attr_merge_6b.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_attr_merge_6r.stdout: arm_attr_merge_6r
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_READELF) -A $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_attr_merge_6r: arm_attr_merge_6b.o arm_attr_merge_6a.o
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -o $@ arm_attr_merge_6b.o arm_attr_merge_6a.o
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_attr_merge_7.stdout: arm_attr_merge_7
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_READELF) -A $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_attr_merge_7: arm_attr_merge_7a.o arm_attr_merge_7b.o
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -o $@ arm_attr_merge_7a.o arm_attr_merge_7b.o
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_attr_merge_7a.o: arm_attr_merge_7a.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_attr_merge_7b.o: arm_attr_merge_7b.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_default_v6z.stdout: arm_fix_1176_default_v6z
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.foo $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_default_v6z: arm_fix_1176_default_v6z.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --section-start=.foo=0x2001014 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_default_v6z.o: arm_fix_1176.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv6z -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_on_v6z.stdout: arm_fix_1176_on_v6z
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.foo $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_on_v6z: arm_fix_1176_on_v6z.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --section-start=.foo=0x2001014 --fix-arm1176 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_on_v6z.o: arm_fix_1176.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv6z -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_off_v6z.stdout: arm_fix_1176_off_v6z
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.foo $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_off_v6z: arm_fix_1176_off_v6z.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --section-start=.foo=0x2001014 --no-fix-arm1176 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_off_v6z.o: arm_fix_1176.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv6z -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_default_v5te.stdout: arm_fix_1176_default_v5te
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.foo $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_default_v5te: arm_fix_1176_default_v5te.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --section-start=.foo=0x2001014 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_default_v5te.o: arm_fix_1176.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv5te -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_default_v7a.stdout: arm_fix_1176_default_v7a
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.foo $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_default_v7a: arm_fix_1176_default_v7a.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --section-start=.foo=0x2001014 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_default_v7a.o: arm_fix_1176.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv7-a -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_default_1156t2f_s.stdout: arm_fix_1176_default_1156t2f_s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.foo $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_default_1156t2f_s: arm_fix_1176_default_1156t2f_s.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --section-start=.foo=0x2001014 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_fix_1176_default_1156t2f_s.o: arm_fix_1176.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -mcpu=arm1156t2f-s -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_b_cond.stdout: arm_cortex_a8_b_cond
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_b_cond: arm_cortex_a8_b_cond.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_b_cond.o: arm_cortex_a8_b_cond.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_b.stdout: arm_cortex_a8_b
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_b: arm_cortex_a8_b.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --fix-cortex-a8 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_b.o: arm_cortex_a8_b.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_bl.stdout: arm_cortex_a8_bl
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_bl: arm_cortex_a8_bl.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_bl.o: arm_cortex_a8_bl.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_blx.stdout: arm_cortex_a8_blx
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_blx: arm_cortex_a8_blx.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_blx.o: arm_cortex_a8_blx.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_local.stdout: arm_cortex_a8_local
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_local: arm_cortex_a8_local.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_local.o: arm_cortex_a8_local.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_local_reloc.stdout: arm_cortex_a8_local_reloc
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_local_reloc: arm_cortex_a8_local_reloc.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_cortex_a8_local_reloc.o: arm_cortex_a8_local_reloc.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_exidx_test.stdout: arm_exidx_test.so
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_READELF) -Sr $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_exidx_test.so: arm_exidx_test.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -shared -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_exidx_test.o: arm_exidx_test.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@pr12826.stdout: pr12826.so
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_READELF) -A $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@pr12826.so: pr12826_1.o pr12826_2.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -shared -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@pr12826_1.o: pr12826_1.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@pr12826_2.o: pr12826_2.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_unaligned_reloc.stdout: arm_unaligned_reloc
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_unaligned_reloc_r.stdout: arm_unaligned_reloc_r
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -Dr $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_unaligned_reloc: arm_unaligned_reloc.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_unaligned_reloc_r: arm_unaligned_reloc.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -r -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_unaligned_reloc.o: arm_unaligned_reloc.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_arm_arm.stdout: arm_farcall_arm_arm
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_arm_arm: arm_farcall_arm_arm.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --no-fix-arm1176 --section-start .text=0x1000 --section-start .foo=0x2001020 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_arm_arm.o: arm_farcall_arm_arm.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_arm_thumb.stdout: arm_farcall_arm_thumb
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_arm_thumb: arm_farcall_arm_thumb.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --section-start .text=0x1000 --section-start .foo=0x2001014 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_arm_thumb.o: arm_farcall_arm_thumb.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_arm_thumb_5t.stdout: arm_farcall_arm_thumb_5t
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_arm_thumb_5t: arm_farcall_arm_thumb_5t.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --no-fix-arm1176 --section-start .text=0x1000 --section-start .foo=0x2001014 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_arm_thumb_5t.o: arm_farcall_arm_thumb.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv5t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_thumb.stdout: arm_farcall_thumb_thumb
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_thumb: arm_farcall_thumb_thumb.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --section-start .text=0x1000 --section-start .foo=0x2001014 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_thumb.o: arm_farcall_thumb_thumb.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv4t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_thumb_5t.stdout: arm_farcall_thumb_thumb_5t
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_thumb_5t: arm_farcall_thumb_thumb_5t.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --no-fix-arm1176 --section-start .text=0x1000 --section-start .foo=0x2001014 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_thumb_5t.o: arm_farcall_thumb_thumb.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv5t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_thumb_7m.stdout: arm_farcall_thumb_thumb_7m
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_thumb_7m: arm_farcall_thumb_thumb_7m.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --section-start .text=0x1000 --section-start .foo=0x2001014 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_thumb_7m.o: arm_farcall_thumb_thumb.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv7-m -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_thumb_6m.stdout: arm_farcall_thumb_thumb_6m
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_thumb_6m: arm_farcall_thumb_thumb_6m.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --section-start .text=0x1000 --section-start .foo=0x2001014 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_thumb_6m.o: arm_farcall_thumb_thumb.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv6-m -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_arm.stdout: arm_farcall_thumb_arm
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_arm: arm_farcall_thumb_arm.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --section-start .text=0x1c01010 --section-start .foo=0x2001014 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_arm.o: arm_farcall_thumb_arm.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_arm_5t.stdout: arm_farcall_thumb_arm_5t
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_arm_5t: arm_farcall_thumb_arm_5t.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new --no-fix-arm1176 --section-start .text=0x1c01010 --section-start .foo=0x2001014 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_arm_5t.o: arm_farcall_thumb_arm.s
+@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv5t -o $@ $<
+
+# Tests for the dwp tool.
+# We don't want to rely yet on GCC support for -gsplit-dwarf,
+# so we use (for now) test cases in x86 assembly language,
+# compiled from the dwp_test_*.cc sources.
+
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_main.o: dwp_test_main.s
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_1.o: dwp_test_1.s
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_1b.o: dwp_test_1b.s
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_2.o: dwp_test_2.s
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_main.dwo: dwp_test_main.o
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_OBJCOPY) --extract-dwo $< $@
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_1.dwo: dwp_test_1.o
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_OBJCOPY) --extract-dwo $< $@
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_1b.dwo: dwp_test_1b.o
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_OBJCOPY) --extract-dwo $< $@
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_2.dwo: dwp_test_2.o
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_OBJCOPY) --extract-dwo $< $@
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_1.stdout: dwp_test_1.dwp
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_READELF) -wi $< > $@
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_1.dwp: ../dwp dwp_test_main.dwo dwp_test_1.dwo dwp_test_1b.dwo dwp_test_2.dwo
+@DEFAULT_TARGET_X86_64_TRUE@ ../dwp -o $@ dwp_test_main.dwo dwp_test_1.dwo dwp_test_1b.dwo dwp_test_2.dwo
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_2.stdout: dwp_test_2.dwp
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_READELF) -wi $< > $@
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_2.dwp: ../dwp dwp_test_2a.dwp dwp_test_2b.dwp
+@DEFAULT_TARGET_X86_64_TRUE@ ../dwp -o $@ dwp_test_2a.dwp dwp_test_2b.dwp
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_2a.dwp: ../dwp dwp_test_main.dwo dwp_test_1.dwo
+@DEFAULT_TARGET_X86_64_TRUE@ ../dwp -o $@ dwp_test_main.dwo dwp_test_1.dwo
+@DEFAULT_TARGET_X86_64_TRUE@dwp_test_2b.dwp: ../dwp dwp_test_1b.dwo dwp_test_2.dwo
+@DEFAULT_TARGET_X86_64_TRUE@ ../dwp -o $@ dwp_test_1b.dwo dwp_test_2.dwo
+
+# 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/testsuite/arm_abs_global.s b/binutils-2.25/gold/testsuite/arm_abs_global.s
new file mode 100644
index 00000000..65cb309b
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_abs_global.s
@@ -0,0 +1,31 @@
+ .syntax unified
+
+ .text
+ .align 2
+
+ .global _start
+ .type _start, %function
+_start:
+ bx lr
+ .size _start, .-_start
+
+ .global _arm_test
+ .type _arm_test, %function
+_arm_test:
+ movt r0, #:upper16:_movt_abs_global
+ movw r0, #:lower16:_movw_abs_global
+ bx lr
+ .size _arm_test, .-_arm_test
+
+ .thumb
+ .global _thumb_test
+_thumb_test:
+ movt r0, #:upper16:_thm_movt_abs_global
+ movw r0, #:lower16:_thm_movw_abs_global
+ bx lr
+ .size _thumb_test, .-_thumb_test
+
+ .data
+_data_test:
+ .word _abs32_global
+ .word _abs32_global_plt
diff --git a/binutils-2.25/gold/testsuite/arm_abs_global.sh b/binutils-2.25/gold/testsuite/arm_abs_global.sh
new file mode 100755
index 00000000..26abc24a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_abs_global.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+# arm_abs_global.sh -- test ARM absolute relocations against global symbols.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>
+
+# 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 goes with the assembler source file arm_abs_global.s,
+# that is assembled and linked with a shared object libarm_abs.so. We
+# want to check that a MOV[TW] instruction referencing an external function
+# causes a PLT to be created.
+
+check()
+{
+ file=$1
+ sym=$2
+ reloc=$3
+
+ found=`grep " $sym\$" $file`
+ if test -z "$found"; then
+ echo "Symbol $sym not found."
+ exit 1
+ fi
+
+ match_reloc=`grep " $sym\$" $file | grep " $reloc "`
+ if test -z "$match_reloc"; then
+ echo "Expected symbol $sym to have relocation $reloc but found"
+ echo "$found"
+ exit 1
+ fi
+}
+
+check "arm_abs_global.stdout" "_movt_abs_global" "R_ARM_JUMP_SLOT"
+check "arm_abs_global.stdout" "_movw_abs_global" "R_ARM_JUMP_SLOT"
+check "arm_abs_global.stdout" "_thm_movt_abs_global" "R_ARM_JUMP_SLOT"
+check "arm_abs_global.stdout" "_thm_movw_abs_global" "R_ARM_JUMP_SLOT"
+check "arm_abs_global.stdout" "_abs32_global_plt" "R_ARM_JUMP_SLOT"
+check "arm_abs_global.stdout" "_abs32_global" "R_ARM_ABS32"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/arm_abs_lib.s b/binutils-2.25/gold/testsuite/arm_abs_lib.s
new file mode 100644
index 00000000..a2d72071
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_abs_lib.s
@@ -0,0 +1,37 @@
+ .syntax unified
+
+ .text
+ .align 2
+ .global _movt_abs_global
+ .type _movt_abs_global, %function
+_movt_abs_global:
+ bx lr
+ .size _movt_abs_global, .-_movt_abs_global
+
+ .global _movw_abs_global
+ .type _movw_abs_global, %function
+_movw_abs_global:
+ bx lr
+ .size _movw_abs_global, .-_movw_abs_global
+
+ .thumb
+ .align 2
+ .global _thm_movt_abs_global
+ .type _thm_movt_abs_global, %function
+_thm_movt_abs_global:
+ bx lr
+ .size _thm_movt_abs_global, .-_thm_movt_abs_global
+
+ .global _thm_movw_abs_global
+ .type _thm_movw_abs_global, %function
+_thm_movw_abs_global:
+ bx lr
+ .size _thm_movw_abs_global, .-_thm_movw_abs_global
+
+ .global _abs32_global_plt
+ .type _abs32_global_plt, %function
+_abs32_global_plt:
+ bx lr
+ .size _abs32_global_plt, .-_abs32_global_plt
+
+ .comm _abs32_global,4,4
diff --git a/binutils-2.25/gold/testsuite/arm_attr_merge.sh b/binutils-2.25/gold/testsuite/arm_attr_merge.sh
new file mode 100755
index 00000000..3066f4f1
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_attr_merge.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# arm_attr_merge.sh -- test ARM attributes merging.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>
+
+# 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 goes with the assembler source files arm_attr_merge*.s
+
+check()
+{
+ file=$1
+ pattern=$2
+ found=`grep "$pattern" $file`
+ if test -z "$found"; then
+ echo "pattern \"$pattern\" not found in file $file."
+ exit 1
+ fi
+}
+
+# This is a bit crude.
+
+check arm_attr_merge_6.stdout "Tag_MPextension_use: Allowed"
+check arm_attr_merge_6r.stdout "Tag_MPextension_use: Allowed"
+check arm_attr_merge_7.stdout "Tag_MPextension_use: Allowed"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/arm_attr_merge_6a.s b/binutils-2.25/gold/testsuite/arm_attr_merge_6a.s
new file mode 100644
index 00000000..df62e535
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_attr_merge_6a.s
@@ -0,0 +1,4 @@
+ .cpu cortex-a9
+ .fpu softvfp
+ .eabi_attribute 70, 1
+ .file "arm_attr_merge_6a.s"
diff --git a/binutils-2.25/gold/testsuite/arm_attr_merge_6b.s b/binutils-2.25/gold/testsuite/arm_attr_merge_6b.s
new file mode 100644
index 00000000..b06e3e09
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_attr_merge_6b.s
@@ -0,0 +1,3 @@
+ .cpu cortex-a9
+ .fpu softvfp
+ .file "arm_attr_merge_6b.s"
diff --git a/binutils-2.25/gold/testsuite/arm_attr_merge_7a.s b/binutils-2.25/gold/testsuite/arm_attr_merge_7a.s
new file mode 100644
index 00000000..4f550293
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_attr_merge_7a.s
@@ -0,0 +1,4 @@
+ .cpu cortex-a9
+ .fpu softvfp
+ .eabi_attribute 70, 1
+ .file "arm_attr_merge_7a.s"
diff --git a/binutils-2.25/gold/testsuite/arm_attr_merge_7b.s b/binutils-2.25/gold/testsuite/arm_attr_merge_7b.s
new file mode 100644
index 00000000..69135b51
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_attr_merge_7b.s
@@ -0,0 +1,4 @@
+ .cpu cortex-a9
+ .fpu softvfp
+ .eabi_attribute Tag_MPextension_use, 1
+ .file "arm_attr_merge_7b.s"
diff --git a/binutils-2.25/gold/testsuite/arm_bl_in_range.s b/binutils-2.25/gold/testsuite/arm_bl_in_range.s
new file mode 100644
index 00000000..23960f9a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_bl_in_range.s
@@ -0,0 +1,45 @@
+# arm_bl_in_range.s
+# Test ARM bl instructions just within branch range limits.
+ .syntax unified
+ .arch armv5te
+
+ .section .text.pre,"x"
+
+# Add padding so that target is just within branch range.
+ .space 12
+
+ .align 2
+ .global _backward_target
+_backward_target:
+ bx lr
+ .size _backward_target, .-_backward_target
+
+ .text
+ .align 2
+
+# Define _start so that linker does not complain.
+ .global _start
+_start:
+ bx lr
+ .size _start, .-_start
+
+ .global _backward_test
+_backward_test:
+ bl _backward_target
+ .size _backward_test, .-_backward_test
+
+ .global _forward_test
+_forward_test:
+ bl _forward_target
+ .size _forward_test, .-_forward_test
+
+ .section .text.post,"x"
+
+# Add padding so that target is just within of branch range.
+ .space 12
+
+ .align 2
+ .global _forward_target
+_forward_target:
+ bx lr
+ .size _forward_target, .-_forward_target
diff --git a/binutils-2.25/gold/testsuite/arm_bl_out_of_range.s b/binutils-2.25/gold/testsuite/arm_bl_out_of_range.s
new file mode 100644
index 00000000..cb5ff535
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_bl_out_of_range.s
@@ -0,0 +1,46 @@
+# arm_bl_out_of_range.s
+# Test ARM bl instructions just out of the branch range limits.
+ .syntax unified
+ .arch armv5te
+
+ .section .text.pre,"x"
+
+# Add padding so that target is just out of branch range.
+ .space 8
+
+ .align 2
+ .global _backward_target
+_backward_target:
+ bx lr
+ .size _backward_target, .-_backward_target
+
+ .text
+# Use 256-byte alignment so that we know where the stubs start.
+ .align 8
+
+# Define _start so that linker does not complain.
+ .global _start
+_start:
+ bx lr
+ .size _start, .-_start
+
+ .global _backward_test
+_backward_test:
+ bl _backward_target
+ .size _backward_test, .-_backward_test
+
+ .global _forward_test
+_forward_test:
+ bl _forward_target
+ .size _forward_test, .-_forward_test
+
+ .section .text.post,"x"
+
+# Add padding so that target is just out of branch range.
+ .space 16
+
+ .align 2
+ .global _forward_target
+_forward_target:
+ bx lr
+ .size _forward_target, .-_forward_target
diff --git a/binutils-2.25/gold/testsuite/arm_branch_in_range.sh b/binutils-2.25/gold/testsuite/arm_branch_in_range.sh
new file mode 100755
index 00000000..dc6f36f3
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_branch_in_range.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+# arm_branch_in_range.sh -- test ARM/THUMB/THUMB branch instructions whose
+# targets are just within the branch range limits.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>
+
+# 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 goes with the assembler source files arm_bl_in_range.s
+# thumb_bl_in_range.s that are assembled and linked to check that branches
+# whose target are just within the branch range limits are handle correctly.
+
+check()
+{
+ file=$1
+ pattern=$2
+
+ found=`grep "$pattern" $file`
+ if test -z "$found"; then
+ echo "pattern \"$pattern\" not found in file $file."
+ exit 1
+ fi
+}
+
+# This is a bit crude. Also, there are tabs in the grep patterns.
+
+check arm_bl_in_range.stdout \
+ " 4000004: eb800000 bl 200000c <_backward_target>"
+check arm_bl_in_range.stdout \
+ " 4000008: eb7fffff bl 600000c <_forward_target>"
+check thumb_bl_in_range.stdout \
+ " 800004: f400 f800 bl 400008 <_backward_target>"
+check thumb_bl_in_range.stdout \
+ " 800008: f3ff ffff bl c0000a <_forward_target>"
+check thumb2_bl_in_range.stdout \
+ " 2000004: f400 d000 bl 1000008 <_backward_target>"
+check thumb2_bl_in_range.stdout \
+ " 2000008: f3ff d7ff bl 300000a <_forward_target>"
+check thumb_blx_in_range.stdout \
+ " 800006: f400 e800 blx 400008 <_backward_target>"
+check thumb_blx_in_range.stdout \
+ " 80000c: f3ff effe blx c0000c <_forward_target>"
+check thumb2_blx_in_range.stdout \
+ " 2000006: f400 c000 blx 1000008 <_backward_target>"
+check thumb2_blx_in_range.stdout \
+ " 200000c: f3ff c7fe blx 300000c <_forward_target>"
+check arm_thm_jump11.stdout \
+ " 8804: e400 b.n 8008 <_backward_target>"
+check arm_thm_jump11.stdout \
+ " 8806: e3ff b.n 9008 <_forward_target>"
+check arm_thm_jump8.stdout \
+ " 8104: d080 beq.n 8008 <_backward_target>"
+check arm_thm_jump8.stdout \
+ " 8106: d07f beq.n 8208 <_forward_target>"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/arm_branch_out_of_range.sh b/binutils-2.25/gold/testsuite/arm_branch_out_of_range.sh
new file mode 100755
index 00000000..aac638f3
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_branch_out_of_range.sh
@@ -0,0 +1,123 @@
+#!/bin/sh
+
+# arm_branch_out_of_range.sh -- test ARM/THUMB/THUMB branch instructions whose
+# targets are just out of the branch range limits.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>
+
+# 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 goes with the assembler source files arm_bl_out_of_range.s,
+# thumb_bl_out_of_range.s and thumb_bl_out_of_range_local.s that are assembled
+# and linked to check that branches whose target are just out of the branch
+# range limits are handle correctly.
+
+check()
+{
+ file=$1
+ pattern=$2
+
+ found=`grep "$pattern" $file`
+ if test -z "$found"; then
+ echo "pattern \"$pattern\" not found in file $file."
+ exit 1
+ fi
+}
+
+# This is a bit crude. Also, there are tabs in the grep patterns.
+
+check arm_bl_out_of_range.stdout \
+ " 4000004: eb00003d bl 4000100 <.*>"
+check arm_bl_out_of_range.stdout \
+ " 4000008: eb00003e bl 4000108 <.*>"
+check arm_bl_out_of_range.stdout \
+ " 4000100: e51ff004 ldr pc, \[pc, #-4\]"
+check arm_bl_out_of_range.stdout \
+ " 4000104: 02000008 "
+check arm_bl_out_of_range.stdout \
+ " 4000108: e51ff004 ldr pc, \[pc, #-4\]"
+check arm_bl_out_of_range.stdout \
+ " 400010c: 06000010 "
+
+check thumb_bl_out_of_range.stdout \
+ " 800004: f000 e87c blx 800100 <.*>"
+check thumb_bl_out_of_range.stdout \
+ " 800008: f000 e87e blx 800108 <.*>"
+check thumb_bl_out_of_range.stdout \
+ " 800100: e51ff004 ldr pc, \[pc, #-4\]"
+check thumb_bl_out_of_range.stdout \
+ " 800104: 00400007 "
+check thumb_bl_out_of_range.stdout \
+ " 800108: e51ff004 ldr pc, \[pc, #-4\]"
+check thumb_bl_out_of_range.stdout \
+ " 80010c: 00c0000d "
+
+check thumb_blx_out_of_range.stdout \
+ " 800004: f000 e87c blx 800100 <.*>"
+check thumb_blx_out_of_range.stdout \
+ " 80000a: f000 e87e blx 800108 <.*>"
+check thumb_blx_out_of_range.stdout \
+ " 800100: e51ff004 ldr pc, \[pc, #-4\]"
+check thumb_blx_out_of_range.stdout \
+ " 800104: 00400004 "
+check thumb_blx_out_of_range.stdout \
+ " 800108: e51ff004 ldr pc, \[pc, #-4\]"
+check thumb_blx_out_of_range.stdout \
+ " 80010c: 00c0000c "
+
+check thumb_bl_out_of_range_local.stdout \
+ " 800004: f000 e87c blx 800100 <.*>"
+check thumb_bl_out_of_range_local.stdout \
+ " 800008: f000 e87e blx 800108 <.*>"
+check thumb_bl_out_of_range_local.stdout \
+ " 800100: e51ff004 ldr pc, \[pc, #-4\]"
+check thumb_bl_out_of_range_local.stdout \
+ " 800104: 00400007 "
+check thumb_bl_out_of_range_local.stdout \
+ " 800108: e51ff004 ldr pc, \[pc, #-4\]"
+check thumb_bl_out_of_range_local.stdout \
+ " 80010c: 00c0000d "
+
+check thumb2_bl_out_of_range.stdout \
+ " 2000004: f000 e87c blx 2000100 <.*>"
+check thumb2_bl_out_of_range.stdout \
+ " 2000008: f000 e87e blx 2000108 <.*>"
+check thumb2_bl_out_of_range.stdout \
+ " 2000100: e51ff004 ldr pc, \[pc, #-4\]"
+check thumb2_bl_out_of_range.stdout \
+ " 2000104: 01000007 "
+check thumb2_bl_out_of_range.stdout \
+ " 2000108: e51ff004 ldr pc, \[pc, #-4\]"
+check thumb2_bl_out_of_range.stdout \
+ " 200010c: 0300000d "
+
+check thumb2_blx_out_of_range.stdout \
+ " 2000004: f000 e87c blx 2000100 <.*>"
+check thumb2_blx_out_of_range.stdout \
+ " 200000a: f000 e87e blx 2000108 <.*>"
+check thumb2_blx_out_of_range.stdout \
+ " 2000100: e51ff004 ldr pc, \[pc, #-4\]"
+check thumb2_blx_out_of_range.stdout \
+ " 2000104: 01000004 "
+check thumb2_blx_out_of_range.stdout \
+ " 2000108: e51ff004 ldr pc, \[pc, #-4\]"
+check thumb2_blx_out_of_range.stdout \
+ " 200010c: 0300000c "
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/arm_branch_range.t b/binutils-2.25/gold/testsuite/arm_branch_range.t
new file mode 100644
index 00000000..865e4042
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_branch_range.t
@@ -0,0 +1,36 @@
+/* arm_banch_range.t -- linker script to test ARM branch range.
+
+ Copyright 2010 Free Software Foundation, Inc.
+ Written by Doug Kwan <dougkwan@google.com>.
+
+ 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. */
+
+SECTIONS
+{
+ . = 0x2000000;
+
+ .text.pre : { *(.text.pre) }
+ . = ALIGN(0x2000000);
+ .text : { *(.text) }
+ . = ALIGN(0x2000000);
+ .text.post : { *(.text.post) }
+ . += 0x1000;
+ .data : { *(.data) }
+ .bss : { *(.bss) }
+ .ARM.attributes : { *(.ARM.attributes) }
+}
diff --git a/binutils-2.25/gold/testsuite/arm_cortex_a8.sh b/binutils-2.25/gold/testsuite/arm_cortex_a8.sh
new file mode 100755
index 00000000..5e25c251
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_cortex_a8.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+# arm_cortex_a8.sh -- a test case for the Cortex-A8 workaround.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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 goes with arm_v4bx.s, an ARM assembly source file constructed to
+# have test the handling of R_ARM_V4BX relocation.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected instruction in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual instructions below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+# Test branch.
+check arm_cortex_a8_b.stdout ".*ffe: .* b.w .*000 <.*>"
+check arm_cortex_a8_b.stdout ".000: .* b.w .*100 <_func>"
+
+# Test conditional branch.
+check arm_cortex_a8_b_cond.stdout ".*ffe: .* b.w .*000 <.*>"
+check arm_cortex_a8_b_cond.stdout ".000: .* beq.n .*006 <.*>"
+check arm_cortex_a8_b_cond.stdout ".002: .* b.w .*002 <.*>"
+check arm_cortex_a8_b_cond.stdout ".006: .* b.w .*100 <_func>"
+
+# Test branch and link.
+check arm_cortex_a8_bl.stdout ".*ffe: .* bl .*000 <.*>"
+check arm_cortex_a8_bl.stdout ".000: .* b.w .*100 <_func>"
+
+# Test blx
+check arm_cortex_a8_blx.stdout ".*ffe: .* blx .*000 <.*>"
+check arm_cortex_a8_blx.stdout ".000: .* b .*100 <_func>"
+
+# Test a local branch without relocation.
+check arm_cortex_a8_local.stdout ".*ffe: .* b.w .*000 <.*>"
+check arm_cortex_a8_local.stdout ".000: .* bpl.n .*006 <.*>"
+check arm_cortex_a8_local.stdout ".002: .* b.w .*002 <.*>"
+check arm_cortex_a8_local.stdout ".006: .* b.w .*100 <.*>"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/arm_cortex_a8_b.s b/binutils-2.25/gold/testsuite/arm_cortex_a8_b.s
new file mode 100644
index 00000000..d2316a07
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_cortex_a8_b.s
@@ -0,0 +1,30 @@
+ .syntax unified
+ .cpu cortex-a8
+
+ .text
+ .align 12
+
+_start:
+ .type _start,%function
+ bx lr
+ .size _start,.-_start
+
+ .align 8
+ .thumb
+ .global _func
+ .type _func,%function
+_func:
+ bx lr
+ .size _func,.-_func
+
+ .align 11
+ .space 2042
+
+ .align 1
+ .thumb
+ .global _test
+ .type _test,%function
+_test:
+ add.w r0, r0, 0
+ b.w _func
+ .size _test,.-_test
diff --git a/binutils-2.25/gold/testsuite/arm_cortex_a8_b_cond.s b/binutils-2.25/gold/testsuite/arm_cortex_a8_b_cond.s
new file mode 100644
index 00000000..a244aa70
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_cortex_a8_b_cond.s
@@ -0,0 +1,30 @@
+ .syntax unified
+ .cpu cortex-a8
+
+ .text
+ .align 12
+
+_start:
+ .type _start,%function
+ bx lr
+ .size _start,.-_start
+
+ .align 8
+ .thumb
+ .global _func
+ .type _func,%function
+_func:
+ bx lr
+ .size _func,.-_func
+
+ .align 11
+ .space 2042
+
+ .align 1
+ .thumb
+ .global _test
+ .type _test,%function
+_test:
+ add.w r0, r0, 0
+ beq.w _func
+ .size _test,.-_test
diff --git a/binutils-2.25/gold/testsuite/arm_cortex_a8_b_local.s b/binutils-2.25/gold/testsuite/arm_cortex_a8_b_local.s
new file mode 100644
index 00000000..2432d91c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_cortex_a8_b_local.s
@@ -0,0 +1,52 @@
+ .syntax unified
+ .cpu cortex-a8
+
+ .section .text.0, "x"
+ .align 12
+
+_start:
+ .type _start,%function
+ bx lr
+ .size _start,.-_start
+
+ .section .text.1, "x"
+ .align 11
+ .thumb
+ .type .Lfunc1,%function
+.Lfunc1:
+ bx lr
+ .size .Lfunc1,.-.Lfunc1
+
+ .section .text.2, "x"
+ .align 11
+ .space 2042
+
+ .align 1
+ .thumb
+ .global _test1
+ .type _test1,%function
+_test1:
+ add.w r0, r0, 0
+ b.w .Lfunc1
+ .size _test1,.-_test1
+
+ .align 8
+ .thumb
+ .type .Lfunc2,%function
+.Lfunc2:
+ bx lr
+ .size .Lfunc2,.-.Lfunc1
+
+ .align 11
+ .space 2042
+
+ .align 1
+ .thumb
+ .global _test2
+ .type _test2,%function
+_test2:
+ add.w r0, r0, 0
+ b.w .Lfunc2
+ .size _test2,.-_test2
+
+
diff --git a/binutils-2.25/gold/testsuite/arm_cortex_a8_bl.s b/binutils-2.25/gold/testsuite/arm_cortex_a8_bl.s
new file mode 100644
index 00000000..c78fa8d8
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_cortex_a8_bl.s
@@ -0,0 +1,30 @@
+ .syntax unified
+ .cpu cortex-a8
+
+ .text
+ .align 12
+
+_start:
+ .type _start,%function
+ bx lr
+ .size _start,.-_start
+
+ .align 8
+ .thumb
+ .global _func
+ .type _func,%function
+_func:
+ bx lr
+ .size _func,.-_func
+
+ .align 11
+ .space 2042
+
+ .align 1
+ .thumb
+ .global _test
+ .type _test,%function
+_test:
+ add.w r0, r0, 0
+ bl _func
+ .size _test,.-_test
diff --git a/binutils-2.25/gold/testsuite/arm_cortex_a8_blx.s b/binutils-2.25/gold/testsuite/arm_cortex_a8_blx.s
new file mode 100644
index 00000000..c323d250
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_cortex_a8_blx.s
@@ -0,0 +1,33 @@
+ .syntax unified
+ .cpu cortex-a8
+
+ .text
+ .align 12
+
+_start:
+ .type _start,%function
+ bx lr
+ .size _start,.-_start
+
+ .align 8
+ .global _func
+ .type _func,%function
+_func:
+ bx lr
+ .size _func,.-_func
+
+ .align 11
+ .space 2042
+
+ .align 1
+ .thumb
+ .global _test
+ .type _test,%function
+_test:
+ add.w r0, r0, 0
+ blx _func
+ .size _test,.-_test
+
+# We have no mapping symbols for stubs. This make the disassembler
+# list the stub correctly in ARM mode.
+ .arm
diff --git a/binutils-2.25/gold/testsuite/arm_cortex_a8_local.s b/binutils-2.25/gold/testsuite/arm_cortex_a8_local.s
new file mode 100644
index 00000000..462aa182
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_cortex_a8_local.s
@@ -0,0 +1,29 @@
+ .syntax unified
+ .cpu cortex-a8
+
+ .text
+ .align 12
+
+_start:
+ .type _start,%function
+ bx lr
+ .size _start,.-_start
+
+ .align 8
+ .thumb
+ .type .Lfunc,%function
+.Lfunc:
+ bx lr
+ .size .Lfunc,.-.Lfunc
+
+ .align 11
+ .space 2042
+
+ .align 1
+ .thumb
+ .global _test
+ .type _test,%function
+_test:
+ add.w r0, r0, 0
+ bpl.w .Lfunc
+ .size _test,.-_test
diff --git a/binutils-2.25/gold/testsuite/arm_cortex_a8_local_reloc.s b/binutils-2.25/gold/testsuite/arm_cortex_a8_local_reloc.s
new file mode 100644
index 00000000..2b49184c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_cortex_a8_local_reloc.s
@@ -0,0 +1,31 @@
+ .syntax unified
+ .cpu cortex-a8
+
+ .section .text.0, "x"
+ .align 12
+
+_start:
+ .type _start,%function
+ bx lr
+ .size _start,.-_start
+
+ .section .text.1, "x"
+ .align 11
+ .thumb
+ .type .Lfunc,%function
+.Lfunc:
+ bx lr
+ .size .Lfunc,.-.Lfunc
+
+ .section .text.2, "x"
+ .align 11
+ .space 2042
+
+ .align 1
+ .thumb
+ .global _test
+ .type _test,%function
+_test:
+ add.w r0, r0, 0
+ b.w .Lfunc
+ .size _test,.-_test
diff --git a/binutils-2.25/gold/testsuite/arm_exidx_test.s b/binutils-2.25/gold/testsuite/arm_exidx_test.s
new file mode 100644
index 00000000..8e550e4e
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_exidx_test.s
@@ -0,0 +1,31 @@
+ .syntax unified
+ .arch armv5te
+ .section .text.answer,"ax",%progbits
+ .align 2
+ .global answer
+ .type answer, %function
+answer:
+ .fnstart
+ .cantunwind
+ mov r0, #42
+ bx lr
+ .fnend
+ .size answer, .-answer
+
+# Check that we can handle an empty .text section
+ .section .text.empty,"ax",%progbits
+ .align 2
+ .global empty
+ .type empty, %function
+empty:
+ .fnstart
+ .cantunwind
+ .fnend
+ .size empty, .-empty
+
+# Check that no dynamic relocations for __exidx_start and __exidx_stop
+# generated.
+ .data
+ .align 12
+ .word __exidx_start(got)
+ .word __exidx_end(got)
diff --git a/binutils-2.25/gold/testsuite/arm_exidx_test.sh b/binutils-2.25/gold/testsuite/arm_exidx_test.sh
new file mode 100755
index 00000000..e196f122
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_exidx_test.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+# arm_exidx_test.sh -- a test case for .ARM.exidx section.
+
+# Copyright 2011 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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 goes with arm_exidx_test.s, an ARM assembly source file constructed
+# to test handling of .ARM.exidx and .ARM.extab sections.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check_not()
+{
+ if grep -q "$2" "$1"
+ then
+ echo "Found unexpected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+# Check that SHF_LINK_ORDER is set.
+check arm_exidx_test.stdout ".* .ARM.exidx .* ARM_EXIDX .* AL .*"
+check arm_exidx_test.stdout ".* .ARM.extab .* PROGBITS .* A .*"
+check_not arm_exidx_test.stdout ".* .* R_ARM_GLOB_DAT .* __exidx_start"
+check_not arm_exidx_test.stdout ".* .* R_ARM_GLOB_DAT .* __exidx_end"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/arm_farcall_arm_arm.s b/binutils-2.25/gold/testsuite/arm_farcall_arm_arm.s
new file mode 100644
index 00000000..00c1e48b
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_farcall_arm_arm.s
@@ -0,0 +1,20 @@
+@ Test to ensure that a ARM to ARM call exceeding 32Mb generates a stub.
+
+ .global _start
+ .syntax unified
+
+@ We will place the section .text at 0x1000.
+
+ .text
+
+_start:
+ bl bar
+
+@ We will place the section .foo at 0x2001020.
+
+ .section .foo, "xa"
+
+ .type bar, %function
+bar:
+ bx lr
+
diff --git a/binutils-2.25/gold/testsuite/arm_farcall_arm_arm.sh b/binutils-2.25/gold/testsuite/arm_farcall_arm_arm.sh
new file mode 100755
index 00000000..7d95528e
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_farcall_arm_arm.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# arm_farcall_arm_arm.sh -- a test case for ARM->ARM farcall veneers
+
+# Copyright 2010, 2011, Free Software Foundation, Inc.
+# Written by Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
+# Based upon arm_cortex_a8.sh
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected instruction in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual instructions below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+# Check for ARM->ARM default
+check arm_farcall_arm_arm.stdout "1004: .* ldr pc, \[pc, #-4\] .*"
+check arm_farcall_arm_arm.stdout "1008: 02001020"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/arm_farcall_arm_thumb.s b/binutils-2.25/gold/testsuite/arm_farcall_arm_thumb.s
new file mode 100644
index 00000000..c69f31cb
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_farcall_arm_thumb.s
@@ -0,0 +1,20 @@
+@ Test to ensure that a ARM to Thumb call exceeding 32Mb generates a stub.
+
+ .global _start
+ .global bar
+ .syntax unified
+
+@ We will place the section .text at 0x1000.
+
+ .text
+
+_start:
+ bl bar
+
+@ We will place the section .foo at 0x2001010.
+
+ .section .foo, "xa"
+ .thumb_func
+bar:
+ bx lr
+
diff --git a/binutils-2.25/gold/testsuite/arm_farcall_arm_thumb.sh b/binutils-2.25/gold/testsuite/arm_farcall_arm_thumb.sh
new file mode 100755
index 00000000..2df2d653
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_farcall_arm_thumb.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+# arm_farcall_arm_thumb.sh -- a test case for ARM->Thumb farcall veneers.
+
+# Copyright 2010, 2011, Free Software Foundation, Inc.
+# Written by Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
+# Based upon arm_cortex_a8.sh
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected instruction in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual instructions below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+# Check for ARM->Thumb default
+check arm_farcall_arm_thumb.stdout "1004: .* ldr ip, \[pc\]"
+check arm_farcall_arm_thumb.stdout "1008: .* bx ip"
+check arm_farcall_arm_thumb.stdout "100c: 02001015"
+
+# Check for ARM->Thumb with v5t interworking
+chck arm_farcall_arm_thumb_5t.stdout "1004: f004 e51f"
+chck arm_farcall_arm_thumb_5t.stdout "1008: 1015"
+chck arm_farcall_arm_thumb_5t.stdout "100a: 0200"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/arm_farcall_thumb_arm.s b/binutils-2.25/gold/testsuite/arm_farcall_thumb_arm.s
new file mode 100644
index 00000000..1fd6a078
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_farcall_thumb_arm.s
@@ -0,0 +1,27 @@
+@ Test to ensure that a Thumb to ARM call exceeding 4Mb generates a stub.
+@ Check that we can generate two types of stub in the same section.
+
+ .global _start
+ .syntax unified
+
+@ We will place the section .text at 0x1c01010.
+
+ .text
+ .thumb_func
+_start:
+ .global bar
+ bl bar
+@ This call is close enough to generate a "short branch" stub
+@ or no stub if blx is available.
+ .space 0x0300000
+ bl bar
+
+@ We will place the section .foo at 0x2001014.
+
+ .section .foo, "xa"
+
+ .arm
+ .type bar, %function
+bar:
+ bx lr
+
diff --git a/binutils-2.25/gold/testsuite/arm_farcall_thumb_arm.sh b/binutils-2.25/gold/testsuite/arm_farcall_thumb_arm.sh
new file mode 100755
index 00000000..e22da46a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_farcall_thumb_arm.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+# arm_farcall_thumb_arm.sh -- a test case for Thumb->ARM farcall veneers.
+
+# Copyright 2010, 2011, Free Software Foundation, Inc.
+# Written by Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
+# Based upon arm_cortex_a8.sh
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected instruction in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual instructions below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+# Thumb->ARM
+check arm_farcall_thumb_arm.stdout "1f01018: .* bx pc"
+check arm_farcall_thumb_arm.stdout "1f0101a: .* nop"
+check arm_farcall_thumb_arm.stdout "1f0101c: f004 e51f"
+check arm_farcall_thumb_arm.stdout "1f01020: 1014"
+check arm_farcall_thumb_arm.stdout "1f01022: 0200"
+
+check arm_farcall_thumb_arm.stdout "1f01024: .* bx pc"
+check arm_farcall_thumb_arm.stdout "1f01026: .* nop"
+check arm_farcall_thumb_arm.stdout "1f01028: fff9 ea03"
+
+# Thumb->ARM with v5T interworking
+check arm_farcall_thumb_arm_5t.stdout "1f01018: f004 e51f"
+check arm_farcall_thumb_arm_5t.stdout "1f0101c: 1014"
+check arm_farcall_thumb_arm_5t.stdout "1f0101e: 0200"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/arm_farcall_thumb_thumb.s b/binutils-2.25/gold/testsuite/arm_farcall_thumb_thumb.s
new file mode 100644
index 00000000..650b1a6b
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_farcall_thumb_thumb.s
@@ -0,0 +1,19 @@
+@ Test to ensure that a Thumb to Thumb call exceeding 4Mb generates a stub.
+
+ .global _start
+ .syntax unified
+
+@ We will place the section .text at 0x1000.
+
+ .text
+ .thumb_func
+_start:
+ bl bar
+
+@ We will place the section .foo at 0x02001014.
+
+ .section .foo, "xa"
+ .thumb_func
+bar:
+ bx lr
+
diff --git a/binutils-2.25/gold/testsuite/arm_farcall_thumb_thumb.sh b/binutils-2.25/gold/testsuite/arm_farcall_thumb_thumb.sh
new file mode 100755
index 00000000..23fb0cd7
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_farcall_thumb_thumb.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+
+# arm_farcall_thumb_thumb.sh -- a test case for Thumb->Thumb farcall veneers.
+
+# Copyright 2010, 2011, Free Software Foundation, Inc.
+# Written by Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
+# Based upon arm_cortex_a8.sh
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected instruction in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual instructions below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+# Thumb->Thumb default
+check arm_farcall_thumb_thumb.stdout "1004: .* bx pc"
+check arm_farcall_thumb_thumb.stdout "1006: .* nop"
+check arm_farcall_thumb_thumb.stdout "1008: c000"
+check arm_farcall_thumb_thumb.stdout "100a: e59f"
+check arm_farcall_thumb_thumb.stdout "100c: ff1c e12f"
+check arm_farcall_thumb_thumb.stdout "1010: 1015"
+check arm_farcall_thumb_thumb.stdout "1012: 0200"
+
+# Thumb->Thumb with v5T interworking
+check arm_farcall_thumb_thumb_5t.stdout "1004: f004 e51f"
+check arm_farcall_thumb_thumb_5t.stdout "1008: 1015"
+check arm_farcall_thumb_thumb_5t.stdout "100a: 0200"
+
+# Thumb->Thumb on v6-M
+check arm_farcall_thumb_thumb_6m.stdout "1004: .* push {r0}"
+check arm_farcall_thumb_thumb_6m.stdout "1006: .* ldr r0, \\[pc, #8\\]"
+check arm_farcall_thumb_thumb_6m.stdout "1008: .* mov ip, r0"
+check arm_farcall_thumb_thumb_6m.stdout "100a: .* pop {r0}"
+check arm_farcall_thumb_thumb_6m.stdout "100c: .* bx ip"
+check arm_farcall_thumb_thumb_6m.stdout "100e: .* nop"
+check arm_farcall_thumb_thumb_6m.stdout "1010: 1015"
+check arm_farcall_thumb_thumb_6m.stdout "1012: 0200"
+
+# Thumb->Thumb on v7-M
+check arm_farcall_thumb_thumb_6m.stdout "1004: .* push {r0}"
+check arm_farcall_thumb_thumb_6m.stdout "1006: .* ldr r0, \\[pc, #8\\]"
+check arm_farcall_thumb_thumb_6m.stdout "1008: .* mov ip, r0"
+check arm_farcall_thumb_thumb_6m.stdout "100a: .* pop {r0}"
+check arm_farcall_thumb_thumb_6m.stdout "100c: .* bx ip"
+check arm_farcall_thumb_thumb_6m.stdout "100e: .* nop"
+check arm_farcall_thumb_thumb_6m.stdout "1010: 1015"
+check arm_farcall_thumb_thumb_6m.stdout "1012: 0200"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/arm_fix_1176.s b/binutils-2.25/gold/testsuite/arm_fix_1176.s
new file mode 100644
index 00000000..96e03284
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_fix_1176.s
@@ -0,0 +1,15 @@
+ .syntax unified
+ .globl _start
+ .globl func_to_branch_to
+
+ .arm
+ .text
+func_to_branch_to:
+ bx lr
+
+ .thumb
+ .section .foo, "xa"
+ .thumb_func
+_start:
+ bl func_to_branch_to
+
diff --git a/binutils-2.25/gold/testsuite/arm_fix_1176.sh b/binutils-2.25/gold/testsuite/arm_fix_1176.sh
new file mode 100755
index 00000000..152b0a32
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_fix_1176.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+# arm_fix_1176.sh -- a test case for the ARM1176 workaround.
+
+# Copyright 2010, 2011, Free Software Foundation, Inc.
+# Written by Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
+# Based upon arm_cortex_a8.sh
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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 goes with arm_v4bx.s, an ARM assembly source file constructed to
+# have test the handling of R_ARM_V4BX relocation.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected instruction in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual instructions below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+# Check for fix default state on v6Z.
+check arm_fix_1176_default_v6z.stdout "2001014: .* bl 2001018 <.*>"
+
+# Check for fix explicitly on on v6Z.
+check arm_fix_1176_on_v6z.stdout "2001014: .* bl 2001018 <.*>"
+
+# Check for explicitly off on v6Z
+check arm_fix_1176_off_v6z.stdout "2001014: .* blx 2001018 <.*>"
+
+# Check for fix default state on v5TE
+check arm_fix_1176_default_v5te.stdout "2001014: .* bl 2001018 <.*>"
+
+# Check for fix default state on v7A
+check arm_fix_1176_default_v7a.stdout "2001014: .* blx 2001018 <.*>"
+
+# Check for fix default state on ARM1156T2F-S
+check arm_fix_1176_default_1156t2f_s.stdout "2001014: .* blx 2001018 <.*>"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/arm_fix_v4bx.s b/binutils-2.25/gold/testsuite/arm_fix_v4bx.s
new file mode 100644
index 00000000..fc3aa2a8
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_fix_v4bx.s
@@ -0,0 +1,15 @@
+ .syntax unified
+ .text
+
+# Align this to 256-byte boundary for easier address matching.
+ .align 8
+
+# We do not want to run this file. We define _start here to avoid missing
+# entry point.
+
+ .global _start
+ .type _start, %function
+_start:
+ bx r0
+ bx r15
+ .size _start, .-_start
diff --git a/binutils-2.25/gold/testsuite/arm_fix_v4bx.sh b/binutils-2.25/gold/testsuite/arm_fix_v4bx.sh
new file mode 100755
index 00000000..a331ff97
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_fix_v4bx.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+# arm_v4bx.sh -- a test case for --fix-v4bx and --fix-v4bx-interworking.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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 goes with arm_v4bx.s, an ARM assembly source file constructed to
+# have test the handling of R_ARM_V4BX relocation.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected instruction in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual instructions below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+# Test --fix-v4bx
+check arm_fix_v4bx.stdout ".*00: .* mov pc, r0"
+check arm_fix_v4bx.stdout ".*04: .* mov pc, pc"
+
+# Test --fix-v4bx-interworking
+check arm_fix_v4bx_interworking.stdout ".*00: .* b .*00 <.*>"
+check arm_fix_v4bx_interworking.stdout ".*04: .* mov pc, pc"
+check arm_fix_v4bx_interworking.stdout ".*00: .* tst r0, #1"
+check arm_fix_v4bx_interworking.stdout ".*04: .* moveq pc, r0"
+check arm_fix_v4bx_interworking.stdout ".*08: .* bx r0"
+
+# Test no fix.
+check arm_no_fix_v4bx.stdout ".*00: .* bx r0"
+check arm_no_fix_v4bx.stdout ".*04: .* bx pc"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/arm_thm_jump11.s b/binutils-2.25/gold/testsuite/arm_thm_jump11.s
new file mode 100644
index 00000000..41f1ce7f
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_thm_jump11.s
@@ -0,0 +1,57 @@
+# arm_thm_jump11.s
+# Test R_ARM_THM_JUMP11 relocations just within the branch range limits.
+ .syntax unified
+ .arch armv5te
+
+ .section .text.pre,"x"
+
+# Add padding so that target is just in branch range.
+ .space 8
+
+ .global _backward_target
+ .code 16
+ .thumb_func
+ .type _backword_target, %function
+_backward_target:
+ bx lr
+ .size _backward_target, .-_backward_target
+
+ .text
+
+# Define _start so that linker does not complain.
+ .global _start
+ .code 32
+ .align 2
+ .type _start, %function
+_start:
+ bx lr
+ .size _start, .-_start
+
+ .global _backward_test
+ .code 16
+ .thumb_func
+ .type _backward_test, %function
+_backward_test:
+ b.n _backward_target
+ .size _backward_test, .-_backward_test
+
+ .global _forward_test
+ .code 16
+ .thumb_func
+ .type _forward_test, %function
+_forward_test:
+ b.n _forward_target
+ .size _forward_test, .-_forward_test
+
+ .section .text.post,"x"
+
+# Add padding so that target is just in branch range.
+ .space 8
+
+ .global _forward_target
+ .code 16
+ .thumb_func
+ .type _forward_target, %function
+_forward_target:
+ bx lr
+ .size _forward_target, .-_forward_target
diff --git a/binutils-2.25/gold/testsuite/arm_thm_jump11.t b/binutils-2.25/gold/testsuite/arm_thm_jump11.t
new file mode 100644
index 00000000..2ec41436
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_thm_jump11.t
@@ -0,0 +1,36 @@
+/* arm_thm_jump11.t -- linker script to test R_ARM_THM_JUMP11 relocation.
+
+ Copyright 2011 Free Software Foundation, Inc.
+ Written by Doug Kwan <dougkwan@google.com>.
+
+ 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. */
+
+SECTIONS
+{
+ . = 0x8000;
+
+ .text.pre : { *(.text.pre) }
+ . = ALIGN(0x800);
+ .text : { *(.text) }
+ . = ALIGN(0x800);
+ .text.post : { *(.text.post) }
+ . += 0x1000;
+ .data : { *(.data) }
+ .bss : { *(.bss) }
+ .ARM.attributes : { *(.ARM.attributes) }
+}
diff --git a/binutils-2.25/gold/testsuite/arm_thm_jump8.s b/binutils-2.25/gold/testsuite/arm_thm_jump8.s
new file mode 100644
index 00000000..540a243f
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_thm_jump8.s
@@ -0,0 +1,57 @@
+# arm_thm_jump8.s
+# Test R_ARM_THM_JUMP8 relocations just within the branch range limits.
+ .syntax unified
+ .arch armv5te
+
+ .section .text.pre,"x"
+
+# Add padding so that target is just in branch range.
+ .space 8
+
+ .global _backward_target
+ .code 16
+ .thumb_func
+ .type _backword_target, %function
+_backward_target:
+ bx lr
+ .size _backward_target, .-_backward_target
+
+ .text
+
+# Define _start so that linker does not complain.
+ .global _start
+ .code 32
+ .align 2
+ .type _start, %function
+_start:
+ bx lr
+ .size _start, .-_start
+
+ .global _backward_test
+ .code 16
+ .thumb_func
+ .type _backward_test, %function
+_backward_test:
+ beq.n _backward_target
+ .size _backward_test, .-_backward_test
+
+ .global _forward_test
+ .code 16
+ .thumb_func
+ .type _forward_test, %function
+_forward_test:
+ beq.n _forward_target
+ .size _forward_test, .-_forward_test
+
+ .section .text.post,"x"
+
+# Add padding so that target is just in branch range.
+ .space 8
+
+ .global _forward_target
+ .code 16
+ .thumb_func
+ .type _forward_target, %function
+_forward_target:
+ bx lr
+ .size _forward_target, .-_forward_target
diff --git a/binutils-2.25/gold/testsuite/arm_thm_jump8.t b/binutils-2.25/gold/testsuite/arm_thm_jump8.t
new file mode 100644
index 00000000..fa674b44
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_thm_jump8.t
@@ -0,0 +1,36 @@
+/* arm_thm_jump8.t -- linker script to test R_ARM_THM_JUMP8 relocation.
+
+ Copyright 2011 Free Software Foundation, Inc.
+ Written by Doug Kwan <dougkwan@google.com>.
+
+ 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. */
+
+SECTIONS
+{
+ . = 0x8000;
+
+ .text.pre : { *(.text.pre) }
+ . = ALIGN(0x100);
+ .text : { *(.text) }
+ . = ALIGN(0x100);
+ .text.post : { *(.text.post) }
+ . += 0x1000;
+ .data : { *(.data) }
+ .bss : { *(.bss) }
+ .ARM.attributes : { *(.ARM.attributes) }
+}
diff --git a/binutils-2.25/gold/testsuite/arm_unaligned_reloc.s b/binutils-2.25/gold/testsuite/arm_unaligned_reloc.s
new file mode 100644
index 00000000..7677bff3
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_unaligned_reloc.s
@@ -0,0 +1,44 @@
+ .syntax unified
+
+ .global _start
+ .type _start, %function
+ .text
+_start:
+ bx lr
+ .size _start,.-_start
+
+ .section .data.0,"aw",%progbits
+ .align 12
+ .type x, %object
+ .size x, 4
+x:
+ .word 1
+
+ .section .data.1,"aw",%progbits
+ .align 2
+
+# This causes following relocations to be unaligned.
+ .global padding
+ .type padding, %object
+ .size padding, 1
+padding:
+ .byte 0
+
+ .global abs32
+ .type abs32, %object
+ .size abs32, 4
+abs32:
+ .word x
+
+ .global rel32
+ .type rel32, %object
+ .size rel32, 4
+rel32:
+ .word x - .
+
+ .global abs16
+ .type abs16, %object
+ .size abs16, 2
+abs16:
+ .short x
+ .short 0
diff --git a/binutils-2.25/gold/testsuite/arm_unaligned_reloc.sh b/binutils-2.25/gold/testsuite/arm_unaligned_reloc.sh
new file mode 100755
index 00000000..39a5a110
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/arm_unaligned_reloc.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+# arm_unaligned_reloc.sh -- test ARM unaligned static data relocations.
+
+# Copyright 2011 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>
+
+# 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 goes with the assembler source file arm_unaligned_reloc.s,
+# that is assembled and linked as a dummy executable. We want to check
+# it is okay to do unaligned static data relocations.
+
+check()
+{
+ if ! grep -q -e "$2" "$1"
+ then
+ echo "Did not find pattern \"$2\" in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual disassembly below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check arm_unaligned_reloc.stdout "^00009000 <x>:$"
+check arm_unaligned_reloc.stdout "^0000a001 <abs32>:$"
+check arm_unaligned_reloc.stdout "^ a001: 00009000 .*$"
+check arm_unaligned_reloc.stdout "^0000a005 <rel32>:"
+check arm_unaligned_reloc.stdout "^ a005: ffffeffb .*$"
+check arm_unaligned_reloc.stdout "^0000a009 <abs16>:"
+check arm_unaligned_reloc.stdout "^ a009: 00009000 .*$"
+
+check arm_unaligned_reloc_r.stdout "^ 1: 00000000 .*$"
+check arm_unaligned_reloc_r.stdout "^[ ]*1: R_ARM_ABS32 .data.0$"
+check arm_unaligned_reloc_r.stdout "^ 5: 00000000 .*$"
+check arm_unaligned_reloc_r.stdout "^[ ]*5: R_ARM_REL32 .data.0$"
+check arm_unaligned_reloc_r.stdout "^ 9: 00000000 .*$"
+check arm_unaligned_reloc_r.stdout "^[ ]*9: R_ARM_ABS16 .data.0$"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/basic_test.cc b/binutils-2.25/gold/testsuite/basic_test.cc
new file mode 100644
index 00000000..94910be8
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/basic_test.cc
@@ -0,0 +1,318 @@
+// basic_test.cc -- a test case for gold
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 goal of this program is to produce as many different types of
+// relocations as we can in a stand-alone program that does not use
+// TLS. This program is compiled without optimization.
+
+// 1 Code reference to global data.
+// 2 Code reference to static data.
+// 3 Code reference to BSS data.
+// 4 Code reference to offset within global data.
+// 5 Code reference to offset within static data.
+// 6 Code reference to offset within BSS data.
+// 7 Switch statement with a table of destinations.
+// 8 Taking the address of a label (a gcc extension).
+// 9 Taking the address of a nested function (a gcc extension).
+// 10 Data reference to global data.
+// 11 Data reference to static data.
+// 12 Data reference to BSS data.
+// 13 Data reference to offset within global data.
+// 14 Data reference to offset within static data.
+// 15 Data reference to offset within BSS data.
+// 16 Virtual table.
+// 17 Inline function.
+// 18 Call through pointer to method.
+// 19 Initialize variable to pointer to method.
+// 20 Global constructor and destructor.
+
+// 1 Code reference to global data.
+int t1 = 11;
+
+// 2 Code reference to static data.
+static int t2 = 22;
+
+// 3 Code reference to BSS data (initialized after program starts, to
+// 33).
+int t3;
+
+// 4 Code reference to offset within global data.
+char t4[] = "Hello, world";
+
+// 5 Code reference to offset within static data.
+static char t5[] = "Hello, world";
+
+// 6 Code reference to offset within BSS data (initialized after
+// program starts, to contents of t4).
+char t6[13];
+
+// Test cases 1 through 6.
+
+bool
+t1_6()
+{
+ return (t1 == 11
+ && t2 == 22
+ && t3 == 33
+ && t4[5] == ','
+ && t5[7] == 'w'
+ && t6[9] == 'r');
+}
+
+// 7 Switch statement with a table of destinations.
+
+int
+t7(int i)
+{
+ switch (i)
+ {
+ case 0:
+ return 12;
+ case 1:
+ return 34;
+ case 2:
+ return 56;
+ case 3:
+ return 78;
+ case 4:
+ return 90;
+ case 5:
+ return 13;
+ case 6:
+ return 0;
+ case 7:
+ return 57;
+ case 8:
+ return 79;
+ case 9:
+ return 81;
+ default:
+ return 144;
+ }
+}
+
+// 8 Taking the address of a label (a gcc extension).
+
+int
+t8(int i)
+{
+ for (int j = 0; j < 10; ++j)
+ {
+ void* p;
+ if (i + j > 6)
+ p = &&lab1;
+ else
+ p = &&lab2;
+ if (j == 7)
+ goto *p;
+ }
+ return 15;
+ lab1:
+ return 0;
+ lab2:
+ return 12;
+}
+
+// 9 Taking the address of a nested function (a gcc extension).
+// Disabled because this is only supported in C, not C++.
+
+int
+t9a(int (*pfn)(int))
+{
+ return (*pfn)(10) - 10;
+}
+
+int
+t9(int i)
+{
+#if 0
+ int
+ t9c(int j)
+ {
+ return i + j;
+ }
+ return t9a(&t9c);
+#else
+ return i;
+#endif
+}
+
+// 10 Data reference to global data.
+int* t10 = &t1;
+
+// 11 Data reference to static data.
+int* t11 = &t2;
+
+// 12 Data reference to BSS data.
+int* t12 = &t3;
+
+// 13 Data reference to offset within global data.
+char* t13 = &t4[6];
+
+// 14 Data reference to offset within static data.
+char* t14 = &t5[8];
+
+// 15 Data reference to offset within BSS data.
+char* t15 = &t6[10];
+
+// Test cases 10 through 15.
+
+bool
+t10_15()
+{
+ return (*t10 == 11
+ && *t11 == 22
+ && *t12 == 33
+ && *t13 == ' '
+ && *t14 == 'o'
+ && *t15 == 'l');
+}
+
+// 16 Virtual table.
+
+class t16a
+{
+ public:
+ virtual
+ ~t16a()
+ { }
+ virtual int
+ t()
+ { return 83; }
+};
+
+class t16b : public t16a
+{
+ public:
+ virtual int
+ t()
+ { return 92; }
+};
+
+t16b t16v;
+
+bool
+t16()
+{
+ return t16v.t() == 92;
+}
+
+// 17 Inline function.
+
+inline int
+t17a()
+{
+ return 74;
+}
+
+bool
+t17()
+{
+ return t17a() == 74;
+}
+
+// 18 Call through pointer to method.
+
+class t18a
+{
+ public:
+ int
+ ta()
+ { return 65; }
+
+ int
+ tb()
+ { return 90; }
+};
+
+t18a t18v;
+
+int
+t18f(int (t18a::* p)())
+{
+ return (t18v.*p)();
+}
+
+bool
+t18()
+{
+ return t18f(&t18a::ta) == 65;
+}
+
+// 19 Initialize variable to pointer to method.
+
+int (t18a::* t19v)() = &t18a::tb;
+
+bool
+t19()
+{
+ return (t18v.*t19v)() == 90;
+}
+
+// 20 Global constructor and destructor.
+
+class t20a
+{
+ public:
+ t20a()
+ : i(96)
+ { }
+ ~t20a()
+ { }
+ int
+ get() const
+ { return this->i; }
+ private:
+ int i;
+};
+
+t20a t20v;
+
+bool
+t20()
+{
+ return t20v.get() == 96;
+}
+
+// Main function. Initialize variables and call test functions.
+
+int
+main()
+{
+ t3 = 33;
+ for (int i = 0; i < 13; ++i)
+ t6[i] = t4[i];
+
+ if (t1_6()
+ && t7(6) == 0
+ && t8(0) == 0
+ && t9(5) == 5
+ && t10_15()
+ && t16()
+ && t17()
+ && t18()
+ && t19()
+ && t20())
+ return 0;
+ else
+ return 1;
+}
diff --git a/binutils-2.25/gold/testsuite/binary.in b/binutils-2.25/gold/testsuite/binary.in
new file mode 100644
index 00000000..cf5d6319
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/binary.in
@@ -0,0 +1 @@
+This file is used for the binary test.
diff --git a/binutils-2.25/gold/testsuite/binary_test.cc b/binutils-2.25/gold/testsuite/binary_test.cc
new file mode 100644
index 00000000..d645536f
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/binary_test.cc
@@ -0,0 +1,46 @@
+// binary_test.cc -- test --format binary for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 program is linked with a small text file named binary.txt
+// using --formatbinary.
+
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <stdint.h>
+
+extern char _binary_binary_txt_start[];
+extern char _binary_binary_txt_end[];
+extern char _binary_binary_txt_size[];
+
+int
+main(int, char**)
+{
+ int size = reinterpret_cast<uintptr_t>(_binary_binary_txt_size);
+ assert(size == _binary_binary_txt_end - _binary_binary_txt_start);
+
+ const char* const txt = "This file is used for the binary test.\n";
+ assert(strncmp(txt, _binary_binary_txt_start, size) == 0);
+ assert(static_cast<size_t>(size) == strlen(txt));
+
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/binary_unittest.cc b/binutils-2.25/gold/testsuite/binary_unittest.cc
new file mode 100644
index 00000000..fe109226
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/binary_unittest.cc
@@ -0,0 +1,184 @@
+// binary_unittest.cc -- test Binary_to_elf
+
+// Copyright 2008, 2012 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "elfcpp.h"
+#include "parameters.h"
+#include "errors.h"
+#include "options.h"
+#include "binary.h"
+#include "object.h"
+#include "descriptors.h"
+
+#include "test.h"
+#include "testfile.h"
+
+namespace
+{
+
+ssize_t
+read_all (int fd, unsigned char* buf, ssize_t size)
+{
+ ssize_t total_read = 0;
+ while (size > 0)
+ {
+ ssize_t nread = ::read(fd, buf, size);
+ if (nread < 0)
+ return nread;
+ if (nread == 0)
+ break;
+ buf += nread;
+ size -= nread;
+ total_read += nread;
+ }
+ return total_read;
+}
+
+} // End anonymous namespace.
+
+namespace gold_testsuite
+{
+
+using namespace gold;
+
+template<int size, bool big_endian>
+bool
+Sized_binary_test()
+{
+ parameters_clear_target();
+ // We need a pretend Task.
+ const Task* task = reinterpret_cast<const Task*>(-1);
+
+ // Use the executable itself as the binary data.
+ struct stat st;
+ CHECK(::stat(gold::program_name, &st) == 0);
+ int o = open_descriptor(-1, gold::program_name, O_RDONLY);
+ CHECK(o >= 0);
+ unsigned char* filedata = new unsigned char[st.st_size];
+ CHECK(read_all(o, filedata, st.st_size) == static_cast<ssize_t>(st.st_size));
+ CHECK(::close(o) == 0);
+
+ Binary_to_elf binary(static_cast<elfcpp::EM>(0xffff), size, big_endian,
+ gold::program_name);
+
+ CHECK(binary.convert(task));
+
+ Input_file input_file(task, "test.o", binary.converted_data(),
+ binary.converted_size());
+ Object* object = make_elf_object("test.o", &input_file, 0,
+ binary.converted_data(),
+ binary.converted_size(), NULL);
+ CHECK(object != NULL);
+ if (object == NULL)
+ return false;
+
+ CHECK(!object->is_dynamic());
+ CHECK(object->shnum() == 5);
+ CHECK(object->section_name(1) == ".data");
+ CHECK(object->section_flags(1) == (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE));
+ section_size_type len;
+ const unsigned char* contents = object->section_contents(1, &len, false);
+ CHECK(len == convert_to_section_size_type(st.st_size));
+ CHECK(memcmp(filedata, contents, len) == 0);
+
+ // Force the symbols to be read internally, so that
+ // symbol_section_and_value will work.
+ Read_symbols_data sd;
+ object->read_symbols(&sd);
+ delete sd.section_headers;
+ sd.section_headers = NULL;
+ delete sd.section_names;
+ sd.section_names = NULL;
+ delete sd.symbols;
+ sd.symbols = NULL;
+ delete sd.symbol_names;
+ sd.symbol_names = NULL;
+
+ Sized_relobj_file<size, big_endian>* relobj =
+ static_cast<Sized_relobj_file<size, big_endian>*>(object);
+ typename Sized_relobj_file<size, big_endian>::Address value;
+ bool is_ordinary;
+ CHECK(relobj->symbol_section_and_value(0, &value, &is_ordinary) == 0);
+ CHECK(is_ordinary);
+ CHECK(value == 0);
+ CHECK(relobj->symbol_section_and_value(1, &value, &is_ordinary) == 1);
+ CHECK(is_ordinary);
+ CHECK(value == 0);
+ CHECK(relobj->symbol_section_and_value(2, &value, &is_ordinary) == 1);
+ CHECK(is_ordinary);
+ CHECK(static_cast<off_t>(value) == st.st_size);
+ CHECK(relobj->symbol_section_and_value(3, &value, &is_ordinary)
+ == elfcpp::SHN_ABS);
+ CHECK(!is_ordinary);
+ CHECK(static_cast<off_t>(value) == st.st_size);
+
+ object->unlock(task);
+ return true;
+}
+
+bool
+Binary_test(Test_report*)
+{
+ Errors errors(gold::program_name);
+ set_parameters_errors(&errors);
+
+ General_options options;
+ set_parameters_options(&options);
+
+ int fail = 0;
+
+#ifdef HAVE_TARGET_32_LITTLE
+ if (!Sized_binary_test<32, false>())
+ ++fail;
+ CHECK(&parameters->target() == target_test_pointer_32_little);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+ if (!Sized_binary_test<32, true>())
+ ++fail;
+ CHECK(&parameters->target() == target_test_pointer_32_big);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+ if (!Sized_binary_test<64, false>())
+ ++fail;
+ CHECK(&parameters->target() == target_test_pointer_64_little);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+ if (!Sized_binary_test<64, true>())
+ ++fail;
+ CHECK(&parameters->target() == target_test_pointer_64_big);
+#endif
+
+ return fail == 0;
+}
+
+Register_test binary_register("Binary", Binary_test);
+
+} // End namespace gold_testsuite.
diff --git a/binutils-2.25/gold/testsuite/common_test_1.c b/binutils-2.25/gold/testsuite/common_test_1.c
new file mode 100644
index 00000000..f5a28f4d
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/common_test_1.c
@@ -0,0 +1,75 @@
+/* common_test_1.c -- test common symbol sorting
+
+ Copyright 2008 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>
+
+ 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 is a test of a common symbol in the main program and a
+ versioned symbol in a shared library. The common symbol in the
+ main program should override the shared library symbol. */
+
+#include <assert.h>
+
+/* Common symbols should be sorted by size, largest first, and then by
+ alignment, largest first. We mix up the names, because gas seems
+ to sort common symbols roughly by name. */
+
+int c9[90];
+int c8[80];
+int c7[70];
+int c6[60];
+int c5[10];
+int c4[20];
+int c3[30];
+int c2[40];
+int c1[50];
+
+int a1 __attribute__ ((aligned (1 << 9)));
+int a2 __attribute__ ((aligned (1 << 8)));
+int a3 __attribute__ ((aligned (1 << 7)));
+int a4 __attribute__ ((aligned (1 << 6)));
+int a5 __attribute__ ((aligned (1 << 1)));
+int a6 __attribute__ ((aligned (1 << 2)));
+int a7 __attribute__ ((aligned (1 << 3)));
+int a8 __attribute__ ((aligned (1 << 4)));
+int a9 __attribute__ ((aligned (1 << 5)));
+
+int
+main (int argc __attribute__ ((unused)), char** argv __attribute__ ((unused)))
+{
+ assert (c5 > c4);
+ assert (c4 > c3);
+ assert (c3 > c2);
+ assert (c2 > c1);
+ assert (c1 > c6);
+ assert (c6 > c7);
+ assert (c7 > c8);
+ assert (c8 > c9);
+
+ assert (&a1 < &a2);
+ assert (&a2 < &a3);
+ assert (&a3 < &a4);
+ assert (&a4 < &a9);
+ assert (&a9 < &a8);
+ assert (&a8 < &a7);
+ assert (&a7 < &a6);
+ assert (&a6 < &a5);
+
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/common_test_1_v1.c b/binutils-2.25/gold/testsuite/common_test_1_v1.c
new file mode 100644
index 00000000..86abc402
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/common_test_1_v1.c
@@ -0,0 +1,79 @@
+/* common_test_1_v1.c -- test common symbol sorting
+
+ Copyright 2008, 2011 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>
+
+ 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 is a test of a common symbol in the main program and a
+ versioned symbol in a shared library. The common symbol in the
+ main program should override the shared library symbol.
+
+ This file is a modified version of the real test case, to be used
+ while testing the --incremental option. */
+
+#include <assert.h>
+
+/* Common symbols should be sorted by size, largest first, and then by
+ alignment, largest first. We mix up the names, because gas seems
+ to sort common symbols roughly by name. */
+
+int c9[90];
+int c8[80];
+int c7[70];
+int c6[60];
+int c5[10];
+int c4[20];
+int c3[30];
+int c2[40];
+int c1[50];
+
+int a1 __attribute__ ((aligned (1 << 9)));
+int a2 __attribute__ ((aligned (1 << 8)));
+int a3 __attribute__ ((aligned (1 << 7)));
+int a4 __attribute__ ((aligned (1 << 6)));
+int a5 __attribute__ ((aligned (1 << 1)));
+int a6 __attribute__ ((aligned (1 << 2)));
+int a7 __attribute__ ((aligned (1 << 3)));
+int a8 __attribute__ ((aligned (1 << 4)));
+int a9 __attribute__ ((aligned (1 << 5)));
+
+int
+main (int argc __attribute__ ((unused)), char** argv __attribute__ ((unused)))
+{
+ /* These tests are deliberately incorrect. */
+ assert (c5 < c4);
+ assert (c4 < c3);
+ assert (c3 < c2);
+ assert (c2 < c1);
+ assert (c1 < c6);
+ assert (c6 < c7);
+ assert (c7 < c8);
+ assert (c8 < c9);
+
+ assert (&a1 > &a2);
+ assert (&a2 > &a3);
+ assert (&a3 > &a4);
+ assert (&a4 > &a9);
+ assert (&a9 > &a8);
+ assert (&a8 > &a7);
+ assert (&a7 > &a6);
+ assert (&a6 > &a5);
+
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/common_test_1_v2.c b/binutils-2.25/gold/testsuite/common_test_1_v2.c
new file mode 100644
index 00000000..c66a647b
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/common_test_1_v2.c
@@ -0,0 +1,77 @@
+/* common_test_1_v2.c -- test common symbol sorting
+
+ Copyright 2008 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>
+
+ 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 is a test of a common symbol in the main program and a
+ versioned symbol in a shared library. The common symbol in the
+ main program should override the shared library symbol. */
+
+#include <assert.h>
+
+/* Common symbols should be sorted by size, largest first, and then by
+ alignment, largest first. We mix up the names, because gas seems
+ to sort common symbols roughly by name. */
+
+int c9[90];
+int c8[80];
+int c7[70];
+int c6[60];
+int c5[10];
+int c4[20];
+int c3[30];
+int c2[40];
+int c1[50];
+
+int a1 __attribute__ ((aligned (1 << 9)));
+int a2 __attribute__ ((aligned (1 << 8)));
+int a3 __attribute__ ((aligned (1 << 7)));
+int a4 __attribute__ ((aligned (1 << 6)));
+int a5 __attribute__ ((aligned (1 << 1)));
+int a6 __attribute__ ((aligned (1 << 2)));
+int a7 __attribute__ ((aligned (1 << 3)));
+int a8 __attribute__ ((aligned (1 << 4)));
+int a9 __attribute__ ((aligned (1 << 5)));
+
+int
+main (int argc __attribute__ ((unused)), char** argv __attribute__ ((unused)))
+{
+ // After an incremental update, all guarantees about ordering
+ // are null.
+ assert (c5 != c4);
+ assert (c4 != c3);
+ assert (c3 != c2);
+ assert (c2 != c1);
+ assert (c1 != c6);
+ assert (c6 != c7);
+ assert (c7 != c8);
+ assert (c8 != c9);
+
+ assert (&a1 != &a2);
+ assert (&a2 != &a3);
+ assert (&a3 != &a4);
+ assert (&a4 != &a9);
+ assert (&a9 != &a8);
+ assert (&a8 != &a7);
+ assert (&a7 != &a6);
+ assert (&a6 != &a5);
+
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/common_test_2.c b/binutils-2.25/gold/testsuite/common_test_2.c
new file mode 100644
index 00000000..ef6d83dd
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/common_test_2.c
@@ -0,0 +1,33 @@
+/* common_test_2.c -- test common symbol name conflicts
+
+ Copyright 2009 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>
+
+ 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. */
+
+/* Call a function. The function will come from a shared library. */
+
+extern void c1 (void);
+
+void fn (void);
+
+void
+fn (void)
+{
+ c1 ();
+}
diff --git a/binutils-2.25/gold/testsuite/common_test_3.c b/binutils-2.25/gold/testsuite/common_test_3.c
new file mode 100644
index 00000000..ba8960cd
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/common_test_3.c
@@ -0,0 +1,32 @@
+/* common_test_3.c -- test common symbol name conflicts
+
+ Copyright 2009 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>
+
+ 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. */
+
+/* Define a function with a default version whose name is the same as
+ a common symbol. This file will wind up in a shared library. */
+
+void c1_v1 (void);
+
+void
+c1_v1 (void)
+{
+}
+__asm__ (".symver c1_v1,c1@@VER1");
diff --git a/binutils-2.25/gold/testsuite/constructor_test.cc b/binutils-2.25/gold/testsuite/constructor_test.cc
new file mode 100644
index 00000000..8889a835
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/constructor_test.cc
@@ -0,0 +1,90 @@
+// constructor_test.cc -- a test case for gold global constructors
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 just runs some global constructors and destructors. The
+// last global destructor verifies that the state is as expected, and
+// we assume that it runs correctly itself.
+
+#include <cassert>
+#include <cstdlib>
+
+// These counters let us verify the state.
+
+int c1_count;
+int c2_count;
+int atexit_count;
+
+// This class verifies that there are no objects left when it is
+// destroyed. Therefore, we can only have one instance of this
+// object.
+
+class c1
+{
+ public:
+ static int count;
+
+ c1()
+ { ++c1_count; }
+
+ ~c1()
+ {
+ --c1_count;
+ assert(c1_count == 0 && c2_count == 0 && atexit_count == 0);
+ }
+};
+
+c1 c1v;
+
+// A function called at atexit time.
+
+void
+atexit_function()
+{
+ --atexit_count;
+ assert(atexit_count == c2_count);
+}
+
+// A class which counts itself and also calls atexit.
+
+class c2
+{
+ public:
+ c2()
+ {
+ assert(atexit_count == c2_count);
+ ++c2_count;
+ atexit(atexit_function);
+ ++atexit_count;
+ }
+
+ ~c2()
+ { --c2_count; }
+};
+
+c2 c2v1;
+c2 c2v2;
+
+int
+main()
+{
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/copy_test.cc b/binutils-2.25/gold/testsuite/copy_test.cc
new file mode 100644
index 00000000..715529d6
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/copy_test.cc
@@ -0,0 +1,43 @@
+// copy_test.cc -- test copy relocs for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cassert>
+#include <stdint.h>
+
+// Misalign the BSS section.
+static char c;
+
+// From copy_test_1.cc.
+extern char b;
+
+// From copy_test_2.cc.
+extern long long l;
+
+int
+main()
+{
+ assert(c == 0);
+ assert(b == 1);
+ assert(l == 2);
+ assert((reinterpret_cast<uintptr_t>(&l) & 0x7) == 0);
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/copy_test_1.cc b/binutils-2.25/gold/testsuite/copy_test_1.cc
new file mode 100644
index 00000000..1471bb59
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/copy_test_1.cc
@@ -0,0 +1,23 @@
+// copy_test_1.cc -- test copy relocs for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+char b = 1;
diff --git a/binutils-2.25/gold/testsuite/copy_test_2.cc b/binutils-2.25/gold/testsuite/copy_test_2.cc
new file mode 100644
index 00000000..01051509
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/copy_test_2.cc
@@ -0,0 +1,23 @@
+// copy_test_2.cc -- test copy relocs variables for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+long long l = 2;
diff --git a/binutils-2.25/gold/testsuite/copy_test_v1.cc b/binutils-2.25/gold/testsuite/copy_test_v1.cc
new file mode 100644
index 00000000..63f7dfd5
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/copy_test_v1.cc
@@ -0,0 +1,47 @@
+// copy_test_v1.cc -- test copy relocs for gold
+
+// Copyright 2008, 2011 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 source file is used for testing the --incremental option.
+// The object built from this source will be incrementally updated
+// with the correct object built from copy_test.cc.
+
+#include <cassert>
+#include <stdint.h>
+
+// Misalign the BSS section.
+static char c;
+
+// From copy_test_1.cc.
+extern char b;
+
+// From copy_test_2.cc.
+extern long long l;
+
+int
+main()
+{
+ assert(c == 0);
+ assert(b == 1);
+ assert(l == 3); // Deliberately incorrect.
+ assert((reinterpret_cast<uintptr_t>(&l) & 0x7) == 0);
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/debug_msg.cc b/binutils-2.25/gold/testsuite/debug_msg.cc
new file mode 100644
index 00000000..09120020
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/debug_msg.cc
@@ -0,0 +1,96 @@
+// debug_msg.cc -- a test case for printing debug info for missing symbols.
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 constructed to have undefined references. In
+// debug_msg.sh, we will try to link this file, and analyze the
+// error messages that are produced.
+
+extern int undef_int;
+extern float undef_float;
+extern void undef_fn1();
+extern void undef_fn2();
+
+int* badref1 = &undef_int;
+static float* badref2 = &undef_float;
+void (*fn_array[])() =
+{
+ undef_fn1,
+ undef_fn2
+};
+
+template<class Foo>
+int testfn(Foo x)
+{
+ undef_fn1();
+ undef_fn2();
+ return undef_int;
+}
+
+class Base
+{
+ virtual void virtfn() { undef_fn1(); }
+};
+
+class Derived : public Base
+{
+ virtual void virtfn() { undef_fn2(); }
+};
+
+// This tests One Definition Rule (ODR) violations.
+void SortAscending(int array[], int size); // in odr_violation1.cc
+void SortDescending(int array[], int size); // in odr_violation2.cc
+// This tests One Definition Rule (ODR) non-violations.
+#include "odr_header2.h"
+OdrBase* CreateOdrDerived1(); // in odr_violation1.cc
+OdrBase* CreateOdrDerived2(); // in odr_violation2.cc
+
+extern "C" int OverriddenCFunction(int i); // in odr_violation*.cc
+
+inline int SometimesInlineFunction(int i) { // strong in odr_violation2.cc.
+ return i;
+}
+
+
+int main()
+{
+ testfn(5);
+ testfn(4.0);
+
+ Base b;
+ Derived d;
+
+ int kInput1[] = {1, 6, 9, 7, 3, 4, 2, 10, 5, 8};
+ int kSize1 = sizeof(kInput1) / sizeof(int);
+ SortAscending(kInput1, kSize1);
+
+ int kInput2[] = {1, 6, 9, 7, 3, 4, 2, 10, 5, 8};
+ int kSize2 = sizeof(kInput2) / sizeof(int);
+ SortDescending(kInput2, kSize2);
+
+ OverriddenCFunction(3);
+ SometimesInlineFunction(3);
+
+ delete CreateOdrDerived1();
+ delete CreateOdrDerived2();
+
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/debug_msg.sh b/binutils-2.25/gold/testsuite/debug_msg.sh
new file mode 100755
index 00000000..1227f3f0
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/debug_msg.sh
@@ -0,0 +1,145 @@
+#!/bin/sh
+
+# debug_msg.sh -- a test case for printing debug info for missing symbols.
+
+# Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2013
+# Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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 goes with debug_msg.cc, a C++ source file constructed to
+# have undefined references. We compile that file with debug
+# information and then try to link it, and make sure the proper errors
+# are displayed. The errors will be found in debug_msg.err.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected error in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual error output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check_missing()
+{
+ if grep -q "$2" "$1"
+ then
+ echo "Found unexpected error in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual error output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+# We don't know how the compiler might order these variables, so we
+# can't test for the actual offset from .data, hence the regexp.
+check debug_msg.err "debug_msg.o:debug_msg.cc:fn_array: error: undefined reference to 'undef_fn1()'"
+check debug_msg.err "debug_msg.o:debug_msg.cc:fn_array: error: undefined reference to 'undef_fn2()'"
+check debug_msg.err "debug_msg.o:debug_msg.cc:badref1: error: undefined reference to 'undef_int'"
+
+# These tests check only for the source file's file name (not the complete
+# path) because use of -fdebug-prefix-map may change the path to the source
+# file recorded in the objects.
+check debug_msg.err ".*/debug_msg.cc:50: error: undefined reference to 'undef_fn1()'"
+check debug_msg.err ".*/debug_msg.cc:55: error: undefined reference to 'undef_fn2()'"
+check debug_msg.err ".*/debug_msg.cc:43: error: undefined reference to 'undef_fn1()'"
+check debug_msg.err ".*/debug_msg.cc:44: error: undefined reference to 'undef_fn2()'"
+if test "$DEFAULT_TARGET" != "powerpc"
+then
+ check debug_msg.err ".*/debug_msg.cc:.*: error: undefined reference to 'undef_int'"
+fi
+
+# Check we detected the ODR (One Definition Rule) violation.
+check debug_msg.err ": symbol 'Ordering::operator()(int, int)' defined in multiple places (possible ODR violation):"
+check debug_msg.err "odr_violation1.cc:6"
+check debug_msg.err "odr_violation2.cc:12"
+
+# Check we don't have ODR false positives:
+check_missing debug_msg.err "OdrDerived::~OdrDerived()"
+check_missing debug_msg.err "__adjust_heap"
+# We block ODR detection for combinations of C weak and strong
+# symbols, to allow people to use the linker to override things. We
+# still flag it for C++ symbols since those are more likely to be
+# unintentional.
+check_missing debug_msg.err ": symbol 'OverriddenCFunction' defined in multiple places (possible ODR violation):"
+check_missing debug_msg.err "odr_violation1.cc:16"
+check_missing debug_msg.err "odr_violation2.cc:23"
+check debug_msg.err ": symbol 'SometimesInlineFunction(int)' defined in multiple places (possible ODR violation):"
+check debug_msg.err "debug_msg.cc:68"
+check debug_msg.err "odr_violation2.cc:27"
+
+# Check for the same error messages when using --compressed-debug-sections.
+if test -r debug_msg_cdebug.err
+then
+ check debug_msg_cdebug.err "debug_msg_cdebug.o:debug_msg.cc:fn_array: error: undefined reference to 'undef_fn1()'"
+ check debug_msg_cdebug.err "debug_msg_cdebug.o:debug_msg.cc:fn_array: error: undefined reference to 'undef_fn2()'"
+ check debug_msg_cdebug.err "debug_msg_cdebug.o:debug_msg.cc:badref1: error: undefined reference to 'undef_int'"
+ check debug_msg_cdebug.err ".*/debug_msg.cc:50: error: undefined reference to 'undef_fn1()'"
+ check debug_msg_cdebug.err ".*/debug_msg.cc:55: error: undefined reference to 'undef_fn2()'"
+ check debug_msg_cdebug.err ".*/debug_msg.cc:43: error: undefined reference to 'undef_fn1()'"
+ check debug_msg_cdebug.err ".*/debug_msg.cc:44: error: undefined reference to 'undef_fn2()'"
+ if test "$DEFAULT_TARGET" != "powerpc"
+ then
+ check debug_msg_cdebug.err ".*/debug_msg.cc:.*: error: undefined reference to 'undef_int'"
+ fi
+ check debug_msg_cdebug.err ": symbol 'Ordering::operator()(int, int)' defined in multiple places (possible ODR violation):"
+ check debug_msg_cdebug.err "odr_violation1.cc:6"
+ check debug_msg_cdebug.err "odr_violation2.cc:12"
+ check_missing debug_msg_cdebug.err "OdrDerived::~OdrDerived()"
+ check_missing debug_msg_cdebug.err "__adjust_heap"
+ check_missing debug_msg_cdebug.err ": symbol 'OverriddenCFunction' defined in multiple places (possible ODR violation):"
+ check_missing debug_msg_cdebug.err "odr_violation1.cc:16"
+ check_missing debug_msg_cdebug.err "odr_violation2.cc:23"
+ check debug_msg_cdebug.err ": symbol 'SometimesInlineFunction(int)' defined in multiple places (possible ODR violation):"
+ check debug_msg_cdebug.err "debug_msg.cc:68"
+ check debug_msg_cdebug.err "odr_violation2.cc:27"
+fi
+
+# When linking together .so's, we don't catch the line numbers, but we
+# still find all the undefined variables, and the ODR violation.
+check debug_msg_so.err "debug_msg.so: error: undefined reference to 'undef_fn1()'"
+check debug_msg_so.err "debug_msg.so: error: undefined reference to 'undef_fn2()'"
+check debug_msg_so.err "debug_msg.so: error: undefined reference to 'undef_int'"
+check debug_msg_so.err ": symbol 'Ordering::operator()(int, int)' defined in multiple places (possible ODR violation):"
+check debug_msg_so.err "odr_violation1.cc:6"
+check debug_msg_so.err "odr_violation2.cc:12"
+check_missing debug_msg_so.err "OdrDerived::~OdrDerived()"
+check_missing debug_msg_so.err "__adjust_heap"
+check_missing debug_msg_so.err ": symbol 'OverriddenCFunction' defined in multiple places (possible ODR violation):"
+check_missing debug_msg_so.err "odr_violation1.cc:16"
+check_missing debug_msg_so.err "odr_violation2.cc:23"
+check debug_msg_so.err ": symbol 'SometimesInlineFunction(int)' defined in multiple places (possible ODR violation):"
+check debug_msg_so.err "debug_msg.cc:68"
+check debug_msg_so.err "odr_violation2.cc:27"
+
+# These messages shouldn't need any debug info to detect:
+check debug_msg_ndebug.err "debug_msg_ndebug.so: error: undefined reference to 'undef_fn1()'"
+check debug_msg_ndebug.err "debug_msg_ndebug.so: error: undefined reference to 'undef_fn2()'"
+check debug_msg_ndebug.err "debug_msg_ndebug.so: error: undefined reference to 'undef_int'"
+# However, we shouldn't detect or declare any ODR violation
+check_missing debug_msg_ndebug.err "(possible ODR violation)"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/discard_locals_relocatable_test.c b/binutils-2.25/gold/testsuite/discard_locals_relocatable_test.c
new file mode 100644
index 00000000..f7f8b279
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/discard_locals_relocatable_test.c
@@ -0,0 +1,52 @@
+/* discard_locals_relocatable_test.c -- test --discard-locals/--discard-all -r
+
+ Copyright 2010 Free Software Foundation, Inc.
+ Viktor Kutuzov <vkutuzov@accesssoftek.com>.
+
+ 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 is a test of a common symbol in the main program and a
+ versioned symbol in a shared library. The common symbol in the
+ main program should override the shared library symbol. */
+
+/* Note: use GCC -fPIC option to compile this test. */
+
+/* Local symbol format for generic ELF target.
+ Use GCC -Wa,-L option to preserve this local symbol
+ in the output object file. */
+asm (".Lshould_be_discarded:");
+
+#ifdef __powerpc__
+/* Test wants to keep one local. Satisfy it. */
+#ifdef __powerpc64__
+asm (".reloc 0,R_PPC64_NONE,.LC0");
+#else
+asm (".reloc 0,R_PPC_NONE,.LC0");
+#endif
+#endif
+
+extern void print_func (const char* s);
+
+extern int func (void);
+
+int
+func (void)
+{
+ print_func ("local string");
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/discard_locals_test.c b/binutils-2.25/gold/testsuite/discard_locals_test.c
new file mode 100644
index 00000000..b7224471
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/discard_locals_test.c
@@ -0,0 +1,40 @@
+/* discard_locals_test.c -- test --discard-locals option.
+
+ Copyright 2009 Free Software Foundation, Inc.
+ Doug Kwan <dougkwan@google.com>.
+
+ 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 is a test of a common symbol in the main program and a
+ versioned symbol in a shared library. The common symbol in the
+ main program should override the shared library symbol. */
+
+/* Local symbol format for generic ELF target. */
+asm (".Lshould_be_discarded:");
+
+#ifdef __i386__
+/* Additional local symbol format for the i386 target. */
+asm (".Xshould_be_discarded:");
+#endif
+
+int
+main (void)
+{
+ return 0;
+}
+
diff --git a/binutils-2.25/gold/testsuite/discard_locals_test.sh b/binutils-2.25/gold/testsuite/discard_locals_test.sh
new file mode 100755
index 00000000..3fc679a4
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/discard_locals_test.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+# discard_locals_test.sh -- test that local symbols are discarded.
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>
+
+# 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 goes with exclude_libs_test.c, a C source file
+# linked with option -Wl,--exclude-libs. We run readelf on
+# the resulting executable and check that symbols from two test library
+# archives are correctly hidden or left unmodified.
+
+check_discarded()
+{
+ file=$1
+ sym=$2
+
+ found=`egrep $sym $file`
+ if test -n "$found"; then
+ echo "These local symbols are not discarded in $file:"
+ echo "$found"
+ exit 1
+ fi
+}
+
+check_non_discarded()
+{
+ file=$1
+ sym=$2
+
+ found=`egrep $sym $file`
+ if test -z "$found"; then
+ echo "This local symbol is discarded in $file:"
+ echo "$2"
+ exit 1
+ fi
+}
+
+check_discarded "discard_locals_test.syms" "should_be_discarded"
+
+check_non_discarded "discard_locals_relocatable_test1.syms" ".LC0"
+check_discarded "discard_locals_relocatable_test1.syms" "should_be_discarded"
+check_non_discarded "discard_locals_relocatable_test2.syms" ".LC0"
+check_discarded "discard_locals_relocatable_test2.syms" "should_be_discarded"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/dwp_test.h b/binutils-2.25/gold/testsuite/dwp_test.h
new file mode 100644
index 00000000..37256d34
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dwp_test.h
@@ -0,0 +1,87 @@
+// dwp_test.h -- a test case for dwp, header file -*- C++ -*-
+
+// Copyright 2012 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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.
+
+// Adapted from two_file_test.h.
+
+class C1
+{
+ public:
+ bool testcase1();
+ bool t1a();
+ int t1_2();
+ bool testcase2();
+ bool testcase3();
+ bool testcase4();
+ int member1;
+};
+
+class C2
+{
+ public:
+ bool testcase1();
+ bool testcase2();
+ bool testcase3();
+ bool testcase4();
+ int member1;
+};
+
+class C3
+{
+ public:
+ bool testcase1();
+ bool testcase2();
+ bool testcase3();
+ bool (*f4())();
+ int member1;
+};
+
+extern C3 c3;
+
+extern int v2;
+extern int v3;
+extern char v4[];
+extern char v5[];
+
+extern int f10();
+extern int f11a();
+extern int f11b(int (*)());
+extern bool t12();
+
+extern bool t13();
+inline void f13i() { }
+extern void (*f13())();
+
+#define TEST_STRING_CONSTANT "test string constant"
+extern const char* f14();
+
+#define TEST_WIDE_STRING_CONSTANT L"test wide string constant"
+extern const wchar_t* f15();
+
+extern bool t16();
+extern bool t16a();
+
+extern bool t17();
+extern const char* t17data[];
+#define T17_COUNT 5
+
+extern bool t18();
+extern const char* f18(int);
diff --git a/binutils-2.25/gold/testsuite/dwp_test_1.cc b/binutils-2.25/gold/testsuite/dwp_test_1.cc
new file mode 100644
index 00000000..71fbc5b3
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dwp_test_1.cc
@@ -0,0 +1,210 @@
+// dwp_test_1.cc -- a test case for dwp
+
+// Copyright 2012 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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.
+
+// Adapted from two_file_test_1.cc.
+
+#include "dwp_test.h"
+
+// 1 Code in file 1 calls code in file 2.
+
+bool
+C1::testcase1()
+{
+ return t1_2() == 123;
+}
+
+// 2 Code in file 1 refers to global data in file 2.
+
+bool
+C1::testcase2()
+{
+ return v2 == 456;
+}
+
+// 3 Code in file 1 referes to common symbol in file 2.
+
+bool
+C1::testcase3()
+{
+ return v3 == 789;
+}
+
+// 4 Code in file 1 refers to offset within global data in file 2.
+
+bool
+C1::testcase4()
+{
+ return v4[5] == ',';
+}
+
+// 5 Code in file 1 refers to offset within common symbol in file 2.
+
+bool
+C2::testcase1()
+{
+ return v5[7] == 'w';
+}
+
+// 6 Data in file 1 refers to global data in file 2.
+
+int* p6 = &v2;
+
+bool
+C2::testcase2()
+{
+ return *p6 == 456;
+}
+
+// 7 Data in file 1 refers to common symbol in file 2.
+
+int* p7 = &v3;
+
+bool
+C2::testcase3()
+{
+ return *p7 == 789;
+}
+
+// 8 Data in file 1 refers to offset within global data in file 2.
+
+char* p8 = &v4[6];
+
+bool
+C2::testcase4()
+{
+ return *p8 == ' ';
+}
+
+// 9 Data in file 1 refers to offset within common symbol in file 2.
+
+char* p9 = &v5[8];
+
+bool
+C3::testcase1()
+{
+ return *p9 == 'o';
+}
+
+// 10 Data in file 1 refers to function in file 2.
+
+int (*pfn)() = &f10;
+
+bool
+C3::testcase2()
+{
+ return (*pfn)() == 135;
+}
+
+// 11 Pass function pointer from file 1 to file 2.
+
+int
+f11a()
+{
+ return 246;
+}
+
+bool
+C3::testcase3()
+{
+ return f11b(&f11a) == 246;
+}
+
+// 12 Compare address of function for equality in both files.
+
+bool
+t12()
+{
+ return &t12 == c3.f4();
+}
+
+// 13 Compare address of inline function for equality in both files.
+
+bool
+t13()
+{
+ return &f13i == f13();
+}
+
+// 14 Compare string constants in file 1 and file 2.
+
+bool
+t14()
+{
+ const char* s1 = TEST_STRING_CONSTANT;
+ const char* s2 = f14();
+ while (*s1 != '\0')
+ if (*s1++ != *s2++)
+ return false;
+ return *s2 == '\0';
+}
+
+// 15 Compare wide string constants in file 1 and file 2.
+
+bool
+t15()
+{
+ const wchar_t* s1 = TEST_WIDE_STRING_CONSTANT;
+ const wchar_t* s2 = f15();
+ while (*s1 != '\0')
+ if (*s1++ != *s2++)
+ return false;
+ return *s2 == '\0';
+}
+
+// 16 Call a function directly after its address has been taken.
+
+bool
+t16()
+{
+ return f10() == 135;
+}
+
+// 17 File 1 checks array of string constants defined in file 2.
+
+bool
+t17()
+{
+ char c = 'a';
+ for (int i = 0; i < T17_COUNT; ++i)
+ {
+ if (t17data[i][0] != c || t17data[i][1] != '\0')
+ return false;
+ ++c;
+ }
+ return true;
+}
+
+// 18 File 1 checks string constants referenced in code in file 2.
+
+bool
+t18()
+{
+ char c = 'a';
+ for (int i = 0; i < T17_COUNT; ++i)
+ {
+ const char* s = f18(i);
+ if (s[0] != c || s[1] != '\0')
+ return false;
+ ++c;
+ }
+ return true;
+}
diff --git a/binutils-2.25/gold/testsuite/dwp_test_1.s b/binutils-2.25/gold/testsuite/dwp_test_1.s
new file mode 100644
index 00000000..d3a898dc
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dwp_test_1.s
@@ -0,0 +1,2660 @@
+ .file "dwp_test_1.cc"
+ .text
+.Ltext0:
+ .section .text._Z4f13iv,"axG",@progbits,_Z4f13iv,comdat
+ .weak _Z4f13iv
+ .type _Z4f13iv, @function
+_Z4f13iv:
+.LFB0:
+ .file 1 "dwp_test.h"
+ .loc 1 70 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ .loc 1 70 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE0:
+ .size _Z4f13iv, .-_Z4f13iv
+ .text
+ .align 2
+ .globl _ZN2C19testcase1Ev
+ .type _ZN2C19testcase1Ev, @function
+_ZN2C19testcase1Ev:
+.LFB1:
+ .file 2 "dwp_test_1.cc"
+ .loc 2 31 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ subq $16, %rsp
+ movq %rdi, -8(%rbp)
+ .loc 2 32 0
+ movq -8(%rbp), %rax
+ movq %rax, %rdi
+ call _ZN2C14t1_2Ev
+ cmpl $123, %eax
+ sete %al
+ .loc 2 33 0
+ leave
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE1:
+ .size _ZN2C19testcase1Ev, .-_ZN2C19testcase1Ev
+ .align 2
+ .globl _ZN2C19testcase2Ev
+ .type _ZN2C19testcase2Ev, @function
+_ZN2C19testcase2Ev:
+.LFB2:
+ .loc 2 39 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movq %rdi, -8(%rbp)
+ .loc 2 40 0
+ movl v2(%rip), %eax
+ cmpl $456, %eax
+ sete %al
+ .loc 2 41 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE2:
+ .size _ZN2C19testcase2Ev, .-_ZN2C19testcase2Ev
+ .align 2
+ .globl _ZN2C19testcase3Ev
+ .type _ZN2C19testcase3Ev, @function
+_ZN2C19testcase3Ev:
+.LFB3:
+ .loc 2 47 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movq %rdi, -8(%rbp)
+ .loc 2 48 0
+ movl v3(%rip), %eax
+ cmpl $789, %eax
+ sete %al
+ .loc 2 49 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE3:
+ .size _ZN2C19testcase3Ev, .-_ZN2C19testcase3Ev
+ .align 2
+ .globl _ZN2C19testcase4Ev
+ .type _ZN2C19testcase4Ev, @function
+_ZN2C19testcase4Ev:
+.LFB4:
+ .loc 2 55 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movq %rdi, -8(%rbp)
+ .loc 2 56 0
+ movzbl v4+5(%rip), %eax
+ cmpb $44, %al
+ sete %al
+ .loc 2 57 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE4:
+ .size _ZN2C19testcase4Ev, .-_ZN2C19testcase4Ev
+ .align 2
+ .globl _ZN2C29testcase1Ev
+ .type _ZN2C29testcase1Ev, @function
+_ZN2C29testcase1Ev:
+.LFB5:
+ .loc 2 63 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movq %rdi, -8(%rbp)
+ .loc 2 64 0
+ movzbl v5+7(%rip), %eax
+ cmpb $119, %al
+ sete %al
+ .loc 2 65 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE5:
+ .size _ZN2C29testcase1Ev, .-_ZN2C29testcase1Ev
+ .globl p6
+ .data
+ .align 8
+ .type p6, @object
+ .size p6, 8
+p6:
+ .quad v2
+ .text
+ .align 2
+ .globl _ZN2C29testcase2Ev
+ .type _ZN2C29testcase2Ev, @function
+_ZN2C29testcase2Ev:
+.LFB6:
+ .loc 2 73 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movq %rdi, -8(%rbp)
+ .loc 2 74 0
+ movq p6(%rip), %rax
+ movl (%rax), %eax
+ cmpl $456, %eax
+ sete %al
+ .loc 2 75 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE6:
+ .size _ZN2C29testcase2Ev, .-_ZN2C29testcase2Ev
+ .globl p7
+ .data
+ .align 8
+ .type p7, @object
+ .size p7, 8
+p7:
+ .quad v3
+ .text
+ .align 2
+ .globl _ZN2C29testcase3Ev
+ .type _ZN2C29testcase3Ev, @function
+_ZN2C29testcase3Ev:
+.LFB7:
+ .loc 2 83 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movq %rdi, -8(%rbp)
+ .loc 2 84 0
+ movq p7(%rip), %rax
+ movl (%rax), %eax
+ cmpl $789, %eax
+ sete %al
+ .loc 2 85 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE7:
+ .size _ZN2C29testcase3Ev, .-_ZN2C29testcase3Ev
+ .globl p8
+ .data
+ .align 8
+ .type p8, @object
+ .size p8, 8
+p8:
+ .quad v4+6
+ .text
+ .align 2
+ .globl _ZN2C29testcase4Ev
+ .type _ZN2C29testcase4Ev, @function
+_ZN2C29testcase4Ev:
+.LFB8:
+ .loc 2 93 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movq %rdi, -8(%rbp)
+ .loc 2 94 0
+ movq p8(%rip), %rax
+ movzbl (%rax), %eax
+ cmpb $32, %al
+ sete %al
+ .loc 2 95 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE8:
+ .size _ZN2C29testcase4Ev, .-_ZN2C29testcase4Ev
+ .globl p9
+ .data
+ .align 8
+ .type p9, @object
+ .size p9, 8
+p9:
+ .quad v5+8
+ .text
+ .align 2
+ .globl _ZN2C39testcase1Ev
+ .type _ZN2C39testcase1Ev, @function
+_ZN2C39testcase1Ev:
+.LFB9:
+ .loc 2 103 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movq %rdi, -8(%rbp)
+ .loc 2 104 0
+ movq p9(%rip), %rax
+ movzbl (%rax), %eax
+ cmpb $111, %al
+ sete %al
+ .loc 2 105 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE9:
+ .size _ZN2C39testcase1Ev, .-_ZN2C39testcase1Ev
+ .globl pfn
+ .data
+ .align 8
+ .type pfn, @object
+ .size pfn, 8
+pfn:
+ .quad _Z3f10v
+ .text
+ .align 2
+ .globl _ZN2C39testcase2Ev
+ .type _ZN2C39testcase2Ev, @function
+_ZN2C39testcase2Ev:
+.LFB10:
+ .loc 2 113 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ subq $16, %rsp
+ movq %rdi, -8(%rbp)
+ .loc 2 114 0
+ movq pfn(%rip), %rax
+ call *%rax
+ cmpl $135, %eax
+ sete %al
+ .loc 2 115 0
+ leave
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE10:
+ .size _ZN2C39testcase2Ev, .-_ZN2C39testcase2Ev
+ .globl _Z4f11av
+ .type _Z4f11av, @function
+_Z4f11av:
+.LFB11:
+ .loc 2 121 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ .loc 2 122 0
+ movl $246, %eax
+ .loc 2 123 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE11:
+ .size _Z4f11av, .-_Z4f11av
+ .align 2
+ .globl _ZN2C39testcase3Ev
+ .type _ZN2C39testcase3Ev, @function
+_ZN2C39testcase3Ev:
+.LFB12:
+ .loc 2 127 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ subq $16, %rsp
+ movq %rdi, -8(%rbp)
+ .loc 2 128 0
+ movl $_Z4f11av, %edi
+ call _Z4f11bPFivE
+ cmpl $246, %eax
+ sete %al
+ .loc 2 129 0
+ leave
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE12:
+ .size _ZN2C39testcase3Ev, .-_ZN2C39testcase3Ev
+ .globl _Z3t12v
+ .type _Z3t12v, @function
+_Z3t12v:
+.LFB13:
+ .loc 2 135 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ .loc 2 136 0
+ movl $c3, %edi
+ call _ZN2C32f4Ev
+ cmpq $_Z3t12v, %rax
+ sete %al
+ .loc 2 137 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE13:
+ .size _Z3t12v, .-_Z3t12v
+ .globl _Z3t13v
+ .type _Z3t13v, @function
+_Z3t13v:
+.LFB14:
+ .loc 2 143 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ .loc 2 144 0
+ call _Z3f13v
+ cmpq $_Z4f13iv, %rax
+ sete %al
+ .loc 2 145 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE14:
+ .size _Z3t13v, .-_Z3t13v
+ .section .rodata
+.LC0:
+ .string "test string constant"
+ .text
+ .globl _Z3t14v
+ .type _Z3t14v, @function
+_Z3t14v:
+.LFB15:
+ .loc 2 151 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ subq $16, %rsp
+.LBB2:
+ .loc 2 152 0
+ movq $.LC0, -8(%rbp)
+ .loc 2 153 0
+ call _Z3f14v
+ movq %rax, -16(%rbp)
+ .loc 2 154 0
+ jmp .L31
+.L33:
+ .loc 2 155 0
+ movq -8(%rbp), %rax
+ movzbl (%rax), %edx
+ movq -16(%rbp), %rax
+ movzbl (%rax), %eax
+ cmpb %al, %dl
+ setne %al
+ addq $1, -8(%rbp)
+ addq $1, -16(%rbp)
+ testb %al, %al
+ je .L31
+ .loc 2 156 0
+ movl $0, %eax
+ jmp .L32
+.L31:
+ .loc 2 154 0 discriminator 1
+ movq -8(%rbp), %rax
+ movzbl (%rax), %eax
+ testb %al, %al
+ setne %al
+ testb %al, %al
+ jne .L33
+ .loc 2 157 0
+ movq -16(%rbp), %rax
+ movzbl (%rax), %eax
+ testb %al, %al
+ sete %al
+.L32:
+.LBE2:
+ .loc 2 158 0
+ leave
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE15:
+ .size _Z3t14v, .-_Z3t14v
+ .section .rodata
+ .align 8
+.LC1:
+ .string "t"
+ .string ""
+ .string ""
+ .string "e"
+ .string ""
+ .string ""
+ .string "s"
+ .string ""
+ .string ""
+ .string "t"
+ .string ""
+ .string ""
+ .string " "
+ .string ""
+ .string ""
+ .string "w"
+ .string ""
+ .string ""
+ .string "i"
+ .string ""
+ .string ""
+ .string "d"
+ .string ""
+ .string ""
+ .string "e"
+ .string ""
+ .string ""
+ .string " "
+ .string ""
+ .string ""
+ .string "s"
+ .string ""
+ .string ""
+ .string "t"
+ .string ""
+ .string ""
+ .string "r"
+ .string ""
+ .string ""
+ .string "i"
+ .string ""
+ .string ""
+ .string "n"
+ .string ""
+ .string ""
+ .string "g"
+ .string ""
+ .string ""
+ .string " "
+ .string ""
+ .string ""
+ .string "c"
+ .string ""
+ .string ""
+ .string "o"
+ .string ""
+ .string ""
+ .string "n"
+ .string ""
+ .string ""
+ .string "s"
+ .string ""
+ .string ""
+ .string "t"
+ .string ""
+ .string ""
+ .string "a"
+ .string ""
+ .string ""
+ .string "n"
+ .string ""
+ .string ""
+ .string "t"
+ .string ""
+ .string ""
+ .string ""
+ .string ""
+ .string ""
+ .string ""
+ .text
+ .globl _Z3t15v
+ .type _Z3t15v, @function
+_Z3t15v:
+.LFB16:
+ .loc 2 164 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ subq $16, %rsp
+.LBB3:
+ .loc 2 165 0
+ movq $.LC1, -8(%rbp)
+ .loc 2 166 0
+ call _Z3f15v
+ movq %rax, -16(%rbp)
+ .loc 2 167 0
+ jmp .L35
+.L37:
+ .loc 2 168 0
+ movq -8(%rbp), %rax
+ movl (%rax), %edx
+ movq -16(%rbp), %rax
+ movl (%rax), %eax
+ cmpl %eax, %edx
+ setne %al
+ addq $4, -8(%rbp)
+ addq $4, -16(%rbp)
+ testb %al, %al
+ je .L35
+ .loc 2 169 0
+ movl $0, %eax
+ jmp .L36
+.L35:
+ .loc 2 167 0 discriminator 1
+ movq -8(%rbp), %rax
+ movl (%rax), %eax
+ testl %eax, %eax
+ setne %al
+ testb %al, %al
+ jne .L37
+ .loc 2 170 0
+ movq -16(%rbp), %rax
+ movl (%rax), %eax
+ testl %eax, %eax
+ sete %al
+.L36:
+.LBE3:
+ .loc 2 171 0
+ leave
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE16:
+ .size _Z3t15v, .-_Z3t15v
+ .globl _Z3t16v
+ .type _Z3t16v, @function
+_Z3t16v:
+.LFB17:
+ .loc 2 177 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ .loc 2 178 0
+ call _Z3f10v
+ cmpl $135, %eax
+ sete %al
+ .loc 2 179 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE17:
+ .size _Z3t16v, .-_Z3t16v
+ .globl _Z3t17v
+ .type _Z3t17v, @function
+_Z3t17v:
+.LFB18:
+ .loc 2 185 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+.LBB4:
+ .loc 2 186 0
+ movb $97, -1(%rbp)
+.LBB5:
+ .loc 2 187 0
+ movl $0, -8(%rbp)
+ jmp .L41
+.L45:
+ .loc 2 189 0
+ movl -8(%rbp), %eax
+ cltq
+ movq t17data(,%rax,8), %rax
+ movzbl (%rax), %eax
+ cmpb -1(%rbp), %al
+ jne .L42
+ .loc 2 189 0 is_stmt 0 discriminator 1
+ movl -8(%rbp), %eax
+ cltq
+ movq t17data(,%rax,8), %rax
+ addq $1, %rax
+ movzbl (%rax), %eax
+ testb %al, %al
+ je .L43
+.L42:
+ .loc 2 190 0 is_stmt 1
+ movl $0, %eax
+ jmp .L44
+.L43:
+ .loc 2 191 0
+ addb $1, -1(%rbp)
+ .loc 2 187 0
+ addl $1, -8(%rbp)
+.L41:
+ .loc 2 187 0 is_stmt 0 discriminator 1
+ cmpl $4, -8(%rbp)
+ setle %al
+ testb %al, %al
+ jne .L45
+.LBE5:
+ .loc 2 193 0 is_stmt 1
+ movl $1, %eax
+.L44:
+.LBE4:
+ .loc 2 194 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE18:
+ .size _Z3t17v, .-_Z3t17v
+ .globl _Z3t18v
+ .type _Z3t18v, @function
+_Z3t18v:
+.LFB19:
+ .loc 2 200 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ subq $16, %rsp
+.LBB6:
+ .loc 2 201 0
+ movb $97, -1(%rbp)
+.LBB7:
+ .loc 2 202 0
+ movl $0, -8(%rbp)
+ jmp .L47
+.L51:
+.LBB8:
+ .loc 2 204 0
+ movl -8(%rbp), %eax
+ movl %eax, %edi
+ call _Z3f18i
+ movq %rax, -16(%rbp)
+ .loc 2 205 0
+ movq -16(%rbp), %rax
+ movzbl (%rax), %eax
+ cmpb -1(%rbp), %al
+ jne .L48
+ .loc 2 205 0 is_stmt 0 discriminator 1
+ movq -16(%rbp), %rax
+ addq $1, %rax
+ movzbl (%rax), %eax
+ testb %al, %al
+ je .L49
+.L48:
+ .loc 2 206 0 is_stmt 1
+ movl $0, %eax
+ jmp .L50
+.L49:
+ .loc 2 207 0
+ addb $1, -1(%rbp)
+.LBE8:
+ .loc 2 202 0
+ addl $1, -8(%rbp)
+.L47:
+ .loc 2 202 0 is_stmt 0 discriminator 1
+ cmpl $4, -8(%rbp)
+ setle %al
+ testb %al, %al
+ jne .L51
+.LBE7:
+ .loc 2 209 0 is_stmt 1
+ movl $1, %eax
+.L50:
+.LBE6:
+ .loc 2 210 0
+ leave
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE19:
+ .size _Z3t18v, .-_Z3t18v
+.Letext0:
+ .section .debug_types.dwo,"G",@progbits,wt.bb2916f0c1bd34b5,comdat
+ .long 0xc1
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .long 0x25
+ .uleb128 0x1
+ .byte 0x4
+ .byte 0x8a
+ .byte 0xda
+ .byte 0x59
+ .byte 0x6e
+ .byte 0x4d
+ .byte 0x5c
+ .byte 0xa
+ .byte 0x88
+ .long .Lskeleton_debug_line0
+ .uleb128 0x2
+ .string "C3"
+ .byte 0x4
+ .byte 0x1
+ .byte 0x2f
+ .long 0xa4
+ .uleb128 0x3
+ .uleb128 0x6
+ .byte 0x1
+ .byte 0x36
+ .long 0xa4
+ .byte 0
+ .byte 0x1
+ .uleb128 0x4
+ .uleb128 0
+ .byte 0x1
+ .byte 0x32
+ .uleb128 0x2
+ .long 0xab
+ .byte 0x1
+ .long 0x4c
+ .long 0x52
+ .uleb128 0x5
+ .long 0xb3
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x1
+ .byte 0x1
+ .byte 0x33
+ .uleb128 0x3
+ .long 0xab
+ .byte 0x1
+ .long 0x64
+ .long 0x6a
+ .uleb128 0x5
+ .long 0xb3
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x4
+ .byte 0x1
+ .byte 0x34
+ .uleb128 0x5
+ .long 0xab
+ .byte 0x1
+ .long 0x7c
+ .long 0x82
+ .uleb128 0x5
+ .long 0xb3
+ .byte 0
+ .uleb128 0x6
+ .string "f4"
+ .byte 0x1
+ .byte 0x35
+ .string "_ZN2C32f4Ev"
+ .long 0xb9
+ .byte 0x1
+ .long 0x9d
+ .uleb128 0x5
+ .long 0xb3
+ .byte 0
+ .byte 0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x2
+ .string "bool"
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x25
+ .uleb128 0x8
+ .byte 0x8
+ .long 0xbf
+ .uleb128 0x9
+ .long 0xab
+ .byte 0
+ .section .debug_types,"G",@progbits,wt.bb2916f0c1bd34b5,comdat
+ .long 0x6e
+ .value 0x4
+ .long .Lskeleton_debug_abbrev0
+ .byte 0x8
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .long 0
+ .uleb128 0x2
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .string "dwp_test_1.dwo"
+ .long .Ldebug_pubnames0
+ .long .Ldebug_pubtypes0
+ .long .Ldebug_addr0
+ .section .debug_types.dwo,"G",@progbits,wt.66526f88bcc798ab,comdat
+ .long 0xa9
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .byte 0x66
+ .byte 0x52
+ .byte 0x6f
+ .byte 0x88
+ .byte 0xbc
+ .byte 0xc7
+ .byte 0x98
+ .byte 0xab
+ .long 0x25
+ .uleb128 0x1
+ .byte 0x4
+ .byte 0x4b
+ .byte 0xf9
+ .byte 0xce
+ .byte 0xbf
+ .byte 0xd8
+ .byte 0xf0
+ .byte 0x4a
+ .byte 0xae
+ .long .Lskeleton_debug_line0
+ .uleb128 0x2
+ .string "C2"
+ .byte 0x4
+ .byte 0x1
+ .byte 0x25
+ .long 0x97
+ .uleb128 0x3
+ .uleb128 0x6
+ .byte 0x1
+ .byte 0x2c
+ .long 0x97
+ .byte 0
+ .byte 0x1
+ .uleb128 0x4
+ .uleb128 0
+ .byte 0x1
+ .byte 0x28
+ .uleb128 0x7
+ .long 0x9e
+ .byte 0x1
+ .long 0x4c
+ .long 0x52
+ .uleb128 0x5
+ .long 0xa6
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x1
+ .byte 0x1
+ .byte 0x29
+ .uleb128 0x8
+ .long 0x9e
+ .byte 0x1
+ .long 0x64
+ .long 0x6a
+ .uleb128 0x5
+ .long 0xa6
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x4
+ .byte 0x1
+ .byte 0x2a
+ .uleb128 0x9
+ .long 0x9e
+ .byte 0x1
+ .long 0x7c
+ .long 0x82
+ .uleb128 0x5
+ .long 0xa6
+ .byte 0
+ .uleb128 0xa
+ .uleb128 0xa
+ .byte 0x1
+ .byte 0x2b
+ .uleb128 0xb
+ .long 0x9e
+ .byte 0x1
+ .long 0x90
+ .uleb128 0x5
+ .long 0xa6
+ .byte 0
+ .byte 0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x2
+ .string "bool"
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x25
+ .byte 0
+ .section .debug_types,"G",@progbits,wt.66526f88bcc798ab,comdat
+ .long 0x6e
+ .value 0x4
+ .long .Lskeleton_debug_abbrev0
+ .byte 0x8
+ .byte 0x66
+ .byte 0x52
+ .byte 0x6f
+ .byte 0x88
+ .byte 0xbc
+ .byte 0xc7
+ .byte 0x98
+ .byte 0xab
+ .long 0
+ .uleb128 0x2
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .string "dwp_test_1.dwo"
+ .long .Ldebug_pubnames0
+ .long .Ldebug_pubtypes0
+ .long .Ldebug_addr0
+ .section .debug_types.dwo,"G",@progbits,wt.c419a9b7a4a2fab5,comdat
+ .long 0xf9
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .byte 0xc4
+ .byte 0x19
+ .byte 0xa9
+ .byte 0xb7
+ .byte 0xa4
+ .byte 0xa2
+ .byte 0xfa
+ .byte 0xb5
+ .long 0x25
+ .uleb128 0x1
+ .byte 0x4
+ .byte 0xe3
+ .byte 0xad
+ .byte 0x5
+ .byte 0x3b
+ .byte 0x75
+ .byte 0xeb
+ .byte 0xfb
+ .byte 0xc7
+ .long .Lskeleton_debug_line0
+ .uleb128 0x2
+ .string "C1"
+ .byte 0x4
+ .byte 0x1
+ .byte 0x19
+ .long 0xe7
+ .uleb128 0x3
+ .uleb128 0x6
+ .byte 0x1
+ .byte 0x22
+ .long 0xe7
+ .byte 0
+ .byte 0x1
+ .uleb128 0x4
+ .uleb128 0
+ .byte 0x1
+ .byte 0x1c
+ .uleb128 0xc
+ .long 0xee
+ .byte 0x1
+ .long 0x4c
+ .long 0x52
+ .uleb128 0x5
+ .long 0xf6
+ .byte 0
+ .uleb128 0xb
+ .string "t1a"
+ .byte 0x1
+ .byte 0x1d
+ .string "_ZN2C13t1aEv"
+ .long 0xee
+ .byte 0x1
+ .long 0x73
+ .long 0x79
+ .uleb128 0x5
+ .long 0xf6
+ .byte 0
+ .uleb128 0xb
+ .string "t1_2"
+ .byte 0x1
+ .byte 0x1e
+ .string "_ZN2C14t1_2Ev"
+ .long 0xe7
+ .byte 0x1
+ .long 0x9c
+ .long 0xa2
+ .uleb128 0x5
+ .long 0xf6
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x1
+ .byte 0x1
+ .byte 0x1f
+ .uleb128 0xd
+ .long 0xee
+ .byte 0x1
+ .long 0xb4
+ .long 0xba
+ .uleb128 0x5
+ .long 0xf6
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x4
+ .byte 0x1
+ .byte 0x20
+ .uleb128 0xe
+ .long 0xee
+ .byte 0x1
+ .long 0xcc
+ .long 0xd2
+ .uleb128 0x5
+ .long 0xf6
+ .byte 0
+ .uleb128 0xa
+ .uleb128 0xa
+ .byte 0x1
+ .byte 0x21
+ .uleb128 0xf
+ .long 0xee
+ .byte 0x1
+ .long 0xe0
+ .uleb128 0x5
+ .long 0xf6
+ .byte 0
+ .byte 0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x2
+ .string "bool"
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x25
+ .byte 0
+ .section .debug_types,"G",@progbits,wt.c419a9b7a4a2fab5,comdat
+ .long 0x6e
+ .value 0x4
+ .long .Lskeleton_debug_abbrev0
+ .byte 0x8
+ .byte 0xc4
+ .byte 0x19
+ .byte 0xa9
+ .byte 0xb7
+ .byte 0xa4
+ .byte 0xa2
+ .byte 0xfa
+ .byte 0xb5
+ .long 0
+ .uleb128 0x2
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .string "dwp_test_1.dwo"
+ .long .Ldebug_pubnames0
+ .long .Ldebug_pubtypes0
+ .long .Ldebug_addr0
+ .section .debug_info.dwo,"e",@progbits
+.Ldebug_info0:
+ .long 0x5af
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .uleb128 0xc
+ .string "GNU C++ 4.7.x-google 20120720 (prerelease)"
+ .byte 0x4
+ .string "dwp_test_1.cc"
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .byte 0x27
+ .byte 0x37
+ .byte 0xdc
+ .byte 0x2f
+ .byte 0x9
+ .byte 0xc6
+ .byte 0xf9
+ .byte 0x52
+ .uleb128 0xd
+ .string "C1"
+ .byte 0xc4
+ .byte 0x19
+ .byte 0xa9
+ .byte 0xb7
+ .byte 0xa4
+ .byte 0xa2
+ .byte 0xfa
+ .byte 0xb5
+ .long 0xc6
+ .uleb128 0xe
+ .uleb128 0
+ .byte 0x1
+ .byte 0x1c
+ .uleb128 0xc
+ .long 0xcd
+ .byte 0x1
+ .uleb128 0xe
+ .uleb128 0x1
+ .byte 0x1
+ .byte 0x1f
+ .uleb128 0xd
+ .long 0xcd
+ .byte 0x1
+ .uleb128 0xe
+ .uleb128 0x4
+ .byte 0x1
+ .byte 0x20
+ .uleb128 0xe
+ .long 0xcd
+ .byte 0x1
+ .uleb128 0xe
+ .uleb128 0xa
+ .byte 0x1
+ .byte 0x21
+ .uleb128 0xf
+ .long 0xcd
+ .byte 0x1
+ .byte 0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x2
+ .string "bool"
+ .uleb128 0xf
+ .byte 0x8
+ .byte 0xc4
+ .byte 0x19
+ .byte 0xa9
+ .byte 0xb7
+ .byte 0xa4
+ .byte 0xa2
+ .byte 0xfa
+ .byte 0xb5
+ .uleb128 0xd
+ .string "C2"
+ .byte 0x66
+ .byte 0x52
+ .byte 0x6f
+ .byte 0x88
+ .byte 0xbc
+ .byte 0xc7
+ .byte 0x98
+ .byte 0xab
+ .long 0x118
+ .uleb128 0xe
+ .uleb128 0
+ .byte 0x1
+ .byte 0x28
+ .uleb128 0x7
+ .long 0xcd
+ .byte 0x1
+ .uleb128 0xe
+ .uleb128 0x1
+ .byte 0x1
+ .byte 0x29
+ .uleb128 0x8
+ .long 0xcd
+ .byte 0x1
+ .uleb128 0xe
+ .uleb128 0x4
+ .byte 0x1
+ .byte 0x2a
+ .uleb128 0x9
+ .long 0xcd
+ .byte 0x1
+ .uleb128 0xe
+ .uleb128 0xa
+ .byte 0x1
+ .byte 0x2b
+ .uleb128 0xb
+ .long 0xcd
+ .byte 0x1
+ .byte 0
+ .uleb128 0xf
+ .byte 0x8
+ .byte 0x66
+ .byte 0x52
+ .byte 0x6f
+ .byte 0x88
+ .byte 0xbc
+ .byte 0xc7
+ .byte 0x98
+ .byte 0xab
+ .uleb128 0xd
+ .string "C3"
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .long 0x151
+ .uleb128 0xe
+ .uleb128 0
+ .byte 0x1
+ .byte 0x32
+ .uleb128 0x2
+ .long 0xcd
+ .byte 0x1
+ .uleb128 0xe
+ .uleb128 0x1
+ .byte 0x1
+ .byte 0x33
+ .uleb128 0x3
+ .long 0xcd
+ .byte 0x1
+ .uleb128 0xe
+ .uleb128 0x4
+ .byte 0x1
+ .byte 0x34
+ .uleb128 0x5
+ .long 0xcd
+ .byte 0x1
+ .byte 0
+ .uleb128 0xf
+ .byte 0x8
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .uleb128 0x10
+ .string "f13i"
+ .byte 0x1
+ .byte 0x46
+ .string "_Z4f13iv"
+ .uleb128 0
+ .quad .LFE0-.LFB0
+ .uleb128 0x1
+ .byte 0x9c
+ .uleb128 0x11
+ .long 0x9d
+ .byte 0x2
+ .byte 0x1e
+ .uleb128 0x1
+ .quad .LFE1-.LFB1
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x191
+ .long 0x19b
+ .uleb128 0x12
+ .uleb128 0x10
+ .long 0x19b
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x13
+ .long 0xd5
+ .uleb128 0x14
+ .long 0xa7
+ .byte 0x2
+ .byte 0x26
+ .uleb128 0x2
+ .quad .LFE2-.LFB2
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x1ba
+ .long 0x1c4
+ .uleb128 0x12
+ .uleb128 0x10
+ .long 0x19b
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x14
+ .long 0xb1
+ .byte 0x2
+ .byte 0x2e
+ .uleb128 0x3
+ .quad .LFE3-.LFB3
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x1de
+ .long 0x1e8
+ .uleb128 0x12
+ .uleb128 0x10
+ .long 0x19b
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x14
+ .long 0xbb
+ .byte 0x2
+ .byte 0x36
+ .uleb128 0x4
+ .quad .LFE4-.LFB4
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x202
+ .long 0x20c
+ .uleb128 0x12
+ .uleb128 0x10
+ .long 0x19b
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x14
+ .long 0xef
+ .byte 0x2
+ .byte 0x3e
+ .uleb128 0x5
+ .quad .LFE5-.LFB5
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x226
+ .long 0x230
+ .uleb128 0x12
+ .uleb128 0x10
+ .long 0x230
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x13
+ .long 0x118
+ .uleb128 0x14
+ .long 0xf9
+ .byte 0x2
+ .byte 0x48
+ .uleb128 0x6
+ .quad .LFE6-.LFB6
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x24f
+ .long 0x259
+ .uleb128 0x12
+ .uleb128 0x10
+ .long 0x230
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x14
+ .long 0x103
+ .byte 0x2
+ .byte 0x52
+ .uleb128 0x7
+ .quad .LFE7-.LFB7
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x273
+ .long 0x27d
+ .uleb128 0x12
+ .uleb128 0x10
+ .long 0x230
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x14
+ .long 0x10d
+ .byte 0x2
+ .byte 0x5c
+ .uleb128 0x8
+ .quad .LFE8-.LFB8
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x297
+ .long 0x2a1
+ .uleb128 0x12
+ .uleb128 0x10
+ .long 0x230
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x14
+ .long 0x132
+ .byte 0x2
+ .byte 0x66
+ .uleb128 0x9
+ .quad .LFE9-.LFB9
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x2bb
+ .long 0x2c5
+ .uleb128 0x12
+ .uleb128 0x10
+ .long 0x2c5
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x13
+ .long 0x151
+ .uleb128 0x11
+ .long 0x13c
+ .byte 0x2
+ .byte 0x70
+ .uleb128 0xa
+ .quad .LFE10-.LFB10
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x2e4
+ .long 0x2ee
+ .uleb128 0x12
+ .uleb128 0x10
+ .long 0x2c5
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x15
+ .string "f11a"
+ .byte 0x2
+ .byte 0x78
+ .string "_Z4f11av"
+ .long 0xc6
+ .uleb128 0xb
+ .quad .LFE11-.LFB11
+ .uleb128 0x1
+ .byte 0x9c
+ .uleb128 0x11
+ .long 0x146
+ .byte 0x2
+ .byte 0x7e
+ .uleb128 0xc
+ .quad .LFE12-.LFB12
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x328
+ .long 0x332
+ .uleb128 0x12
+ .uleb128 0x10
+ .long 0x2c5
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x16
+ .string "t12"
+ .byte 0x2
+ .byte 0x86
+ .string "_Z3t12v"
+ .long 0xcd
+ .uleb128 0xd
+ .quad .LFE13-.LFB13
+ .uleb128 0x1
+ .byte 0x9c
+ .uleb128 0x16
+ .string "t13"
+ .byte 0x2
+ .byte 0x8e
+ .string "_Z3t13v"
+ .long 0xcd
+ .uleb128 0xe
+ .quad .LFE14-.LFB14
+ .uleb128 0x1
+ .byte 0x9c
+ .uleb128 0x17
+ .string "t14"
+ .byte 0x2
+ .byte 0x96
+ .string "_Z3t14v"
+ .long 0xcd
+ .uleb128 0xf
+ .quad .LFE15-.LFB15
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x3b6
+ .uleb128 0x18
+ .uleb128 0x10
+ .quad .LBE2-.LBB2
+ .uleb128 0x19
+ .string "s1"
+ .byte 0x2
+ .byte 0x98
+ .long 0x3b6
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .uleb128 0x19
+ .string "s2"
+ .byte 0x2
+ .byte 0x99
+ .long 0x3b6
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -32
+ .byte 0
+ .byte 0
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x3bc
+ .uleb128 0x13
+ .long 0x3c1
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x6
+ .string "char"
+ .uleb128 0x17
+ .string "t15"
+ .byte 0x2
+ .byte 0xa3
+ .string "_Z3t15v"
+ .long 0xcd
+ .uleb128 0x11
+ .quad .LFE16-.LFB16
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x411
+ .uleb128 0x18
+ .uleb128 0x12
+ .quad .LBE3-.LBB3
+ .uleb128 0x19
+ .string "s1"
+ .byte 0x2
+ .byte 0xa5
+ .long 0x411
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .uleb128 0x19
+ .string "s2"
+ .byte 0x2
+ .byte 0xa6
+ .long 0x411
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -32
+ .byte 0
+ .byte 0
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x417
+ .uleb128 0x13
+ .long 0x41c
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "wchar_t"
+ .uleb128 0x16
+ .string "t16"
+ .byte 0x2
+ .byte 0xb0
+ .string "_Z3t16v"
+ .long 0xcd
+ .uleb128 0x13
+ .quad .LFE17-.LFB17
+ .uleb128 0x1
+ .byte 0x9c
+ .uleb128 0x1a
+ .string "t17"
+ .byte 0x2
+ .byte 0xb8
+ .string "_Z3t17v"
+ .long 0xcd
+ .uleb128 0x14
+ .quad .LFE18-.LFB18
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x496
+ .uleb128 0x18
+ .uleb128 0x15
+ .quad .LBE4-.LBB4
+ .uleb128 0x19
+ .string "c"
+ .byte 0x2
+ .byte 0xba
+ .long 0x3c1
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -17
+ .uleb128 0x18
+ .uleb128 0x16
+ .quad .LBE5-.LBB5
+ .uleb128 0x19
+ .string "i"
+ .byte 0x2
+ .byte 0xbb
+ .long 0xc6
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .byte 0
+ .byte 0
+ .uleb128 0x17
+ .string "t18"
+ .byte 0x2
+ .byte 0xc7
+ .string "_Z3t18v"
+ .long 0xcd
+ .uleb128 0x17
+ .quad .LFE19-.LFB19
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x4fe
+ .uleb128 0x18
+ .uleb128 0x18
+ .quad .LBE6-.LBB6
+ .uleb128 0x19
+ .string "c"
+ .byte 0x2
+ .byte 0xc9
+ .long 0x3c1
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -17
+ .uleb128 0x18
+ .uleb128 0x19
+ .quad .LBE7-.LBB7
+ .uleb128 0x19
+ .string "i"
+ .byte 0x2
+ .byte 0xca
+ .long 0xc6
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .uleb128 0x18
+ .uleb128 0x1a
+ .quad .LBE8-.LBB8
+ .uleb128 0x19
+ .string "s"
+ .byte 0x2
+ .byte 0xcc
+ .long 0x3b6
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -32
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 0
+ .uleb128 0x1b
+ .string "c3"
+ .byte 0x1
+ .byte 0x39
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .uleb128 0x1c
+ .string "v2"
+ .byte 0x1
+ .byte 0x3b
+ .long 0xc6
+ .uleb128 0x1c
+ .string "v3"
+ .byte 0x1
+ .byte 0x3c
+ .long 0xc6
+ .uleb128 0x1d
+ .long 0x3c1
+ .long 0x52b
+ .uleb128 0x1e
+ .byte 0
+ .uleb128 0x1c
+ .string "v4"
+ .byte 0x1
+ .byte 0x3d
+ .long 0x520
+ .uleb128 0x1c
+ .string "v5"
+ .byte 0x1
+ .byte 0x3e
+ .long 0x520
+ .uleb128 0x1d
+ .long 0x3b6
+ .long 0x54a
+ .uleb128 0x1e
+ .byte 0
+ .uleb128 0x1c
+ .string "t17data"
+ .byte 0x1
+ .byte 0x53
+ .long 0x53f
+ .uleb128 0x1f
+ .string "p6"
+ .byte 0x2
+ .byte 0x45
+ .long 0x566
+ .uleb128 0x2
+ .byte 0xfb
+ .uleb128 0x1b
+ .uleb128 0x8
+ .byte 0x8
+ .long 0xc6
+ .uleb128 0x1f
+ .string "p7"
+ .byte 0x2
+ .byte 0x4f
+ .long 0x566
+ .uleb128 0x2
+ .byte 0xfb
+ .uleb128 0x1c
+ .uleb128 0x1f
+ .string "p8"
+ .byte 0x2
+ .byte 0x59
+ .long 0x586
+ .uleb128 0x2
+ .byte 0xfb
+ .uleb128 0x1d
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x3c1
+ .uleb128 0x1f
+ .string "p9"
+ .byte 0x2
+ .byte 0x63
+ .long 0x586
+ .uleb128 0x2
+ .byte 0xfb
+ .uleb128 0x1e
+ .uleb128 0x9
+ .long 0xc6
+ .uleb128 0x1f
+ .string "pfn"
+ .byte 0x2
+ .byte 0x6d
+ .long 0x5ac
+ .uleb128 0x2
+ .byte 0xfb
+ .uleb128 0x1f
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x599
+ .byte 0
+ .section .debug_info,"",@progbits
+.Lskeleton_debug_info0:
+ .long 0x7e
+ .value 0x4
+ .long .Lskeleton_debug_abbrev0
+ .byte 0x8
+ .uleb128 0x1
+ .long .Ldebug_ranges0+0
+ .quad 0
+ .long .Ldebug_line0
+ .byte 0x27
+ .byte 0x37
+ .byte 0xdc
+ .byte 0x2f
+ .byte 0x9
+ .byte 0xc6
+ .byte 0xf9
+ .byte 0x52
+ .long .Ldebug_ranges0
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .string "dwp_test_1.dwo"
+ .long .Ldebug_pubnames0
+ .long .Ldebug_pubtypes0
+ .long .Ldebug_addr0
+ .section .debug_abbrev,"",@progbits
+.Lskeleton_debug_abbrev0:
+ .uleb128 0x1
+ .uleb128 0x11
+ .byte 0
+ .uleb128 0x55
+ .uleb128 0x17
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x10
+ .uleb128 0x17
+ .uleb128 0x2131
+ .uleb128 0x7
+ .uleb128 0x2132
+ .uleb128 0x17
+ .uleb128 0x1b
+ .uleb128 0x8
+ .uleb128 0x2130
+ .uleb128 0x8
+ .uleb128 0x2134
+ .uleb128 0x17
+ .uleb128 0x2135
+ .uleb128 0x17
+ .uleb128 0x2133
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+ .uleb128 0x2
+ .uleb128 0x41
+ .byte 0
+ .uleb128 0x1b
+ .uleb128 0x8
+ .uleb128 0x2130
+ .uleb128 0x8
+ .uleb128 0x2134
+ .uleb128 0x17
+ .uleb128 0x2135
+ .uleb128 0x17
+ .uleb128 0x2133
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+ .byte 0
+ .section .debug_abbrev.dwo,"e",@progbits
+.Ldebug_abbrev0:
+ .uleb128 0x1
+ .uleb128 0x41
+ .byte 0x1
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x210f
+ .uleb128 0x7
+ .uleb128 0x10
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+ .uleb128 0x2
+ .uleb128 0x2
+ .byte 0x1
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0xd
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x1f02
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x38
+ .uleb128 0xb
+ .uleb128 0x32
+ .uleb128 0xb
+ .byte 0
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x1f02
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x1f02
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x5
+ .uleb128 0x5
+ .byte 0
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x34
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x6
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x7
+ .uleb128 0x24
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .byte 0
+ .byte 0
+ .uleb128 0x8
+ .uleb128 0xf
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x9
+ .uleb128 0x15
+ .byte 0
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0xa
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x1f02
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x1f02
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0xc
+ .uleb128 0x11
+ .byte 0x1
+ .uleb128 0x25
+ .uleb128 0x8
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x1b
+ .uleb128 0x8
+ .uleb128 0x2131
+ .uleb128 0x7
+ .byte 0
+ .byte 0
+ .uleb128 0xd
+ .uleb128 0x2
+ .byte 0x1
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x69
+ .uleb128 0x20
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0xe
+ .uleb128 0x2e
+ .byte 0
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x1f02
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x1f02
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0xf
+ .uleb128 0xf
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x20
+ .byte 0
+ .byte 0
+ .uleb128 0x10
+ .uleb128 0x2e
+ .byte 0
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x2117
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x11
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x47
+ .uleb128 0x13
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x64
+ .uleb128 0x13
+ .uleb128 0x2116
+ .uleb128 0x19
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x12
+ .uleb128 0x5
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x1f02
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x34
+ .uleb128 0x19
+ .uleb128 0x2
+ .uleb128 0x18
+ .byte 0
+ .byte 0
+ .uleb128 0x13
+ .uleb128 0x26
+ .byte 0
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x14
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x47
+ .uleb128 0x13
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x64
+ .uleb128 0x13
+ .uleb128 0x2117
+ .uleb128 0x19
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x15
+ .uleb128 0x2e
+ .byte 0
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x2117
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x16
+ .uleb128 0x2e
+ .byte 0
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x2116
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x17
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x2116
+ .uleb128 0x19
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x18
+ .uleb128 0xb
+ .byte 0x1
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .byte 0
+ .byte 0
+ .uleb128 0x19
+ .uleb128 0x34
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0x18
+ .byte 0
+ .byte 0
+ .uleb128 0x1a
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x2117
+ .uleb128 0x19
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x1b
+ .uleb128 0x34
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x20
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3c
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x1c
+ .uleb128 0x34
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3c
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x1d
+ .uleb128 0x1
+ .byte 0x1
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x1e
+ .uleb128 0x21
+ .byte 0
+ .byte 0
+ .byte 0
+ .uleb128 0x1f
+ .uleb128 0x34
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x2
+ .uleb128 0x18
+ .byte 0
+ .byte 0
+ .byte 0
+ .section .debug_gnu_pubnames,"",@progbits
+.Ldebug_pubnames0:
+ .long 0x15b
+ .value 0x2
+ .long .Lskeleton_debug_info0
+ .long 0x5b3
+ .long 0x15b
+ .byte 0x30
+ .string "f13i"
+ .long 0x177
+ .byte 0x30
+ .string "C1::testcase1"
+ .long 0x1a0
+ .byte 0x30
+ .string "C1::testcase2"
+ .long 0x1c4
+ .byte 0x30
+ .string "C1::testcase3"
+ .long 0x1e8
+ .byte 0x30
+ .string "C1::testcase4"
+ .long 0x20c
+ .byte 0x30
+ .string "C2::testcase1"
+ .long 0x235
+ .byte 0x30
+ .string "C2::testcase2"
+ .long 0x259
+ .byte 0x30
+ .string "C2::testcase3"
+ .long 0x27d
+ .byte 0x30
+ .string "C2::testcase4"
+ .long 0x2a1
+ .byte 0x30
+ .string "C3::testcase1"
+ .long 0x2ca
+ .byte 0x30
+ .string "C3::testcase2"
+ .long 0x2ee
+ .byte 0x30
+ .string "f11a"
+ .long 0x30e
+ .byte 0x30
+ .string "C3::testcase3"
+ .long 0x332
+ .byte 0x30
+ .string "t12"
+ .long 0x350
+ .byte 0x30
+ .string "t13"
+ .long 0x36e
+ .byte 0x30
+ .string "t14"
+ .long 0x3c9
+ .byte 0x30
+ .string "t15"
+ .long 0x427
+ .byte 0x30
+ .string "t16"
+ .long 0x445
+ .byte 0x30
+ .string "t17"
+ .long 0x496
+ .byte 0x30
+ .string "t18"
+ .long 0x559
+ .byte 0x20
+ .string "p6"
+ .long 0x56c
+ .byte 0x20
+ .string "p7"
+ .long 0x579
+ .byte 0x20
+ .string "p8"
+ .long 0x58c
+ .byte 0x20
+ .string "p9"
+ .long 0x59e
+ .byte 0x20
+ .string "pfn"
+ .long 0
+ .section .debug_gnu_pubtypes,"",@progbits
+.Ldebug_pubtypes0:
+ .long 0x50
+ .value 0x2
+ .long .Lskeleton_debug_info0
+ .long 0x5b3
+ .long 0xc6
+ .byte 0x90
+ .string "int"
+ .long 0xcd
+ .byte 0x90
+ .string "bool"
+ .long 0x8d
+ .byte 0x10
+ .string "C1"
+ .long 0xdf
+ .byte 0x10
+ .string "C2"
+ .long 0x122
+ .byte 0x10
+ .string "C3"
+ .long 0x3c1
+ .byte 0x90
+ .string "char"
+ .long 0x41c
+ .byte 0x90
+ .string "wchar_t"
+ .long 0
+ .section .debug_aranges,"",@progbits
+ .long 0x3c
+ .value 0x2
+ .long .Lskeleton_debug_info0
+ .byte 0x8
+ .byte 0
+ .value 0
+ .value 0
+ .quad .Ltext0
+ .quad .Letext0-.Ltext0
+ .quad .LFB0
+ .quad .LFE0-.LFB0
+ .quad 0
+ .quad 0
+ .section .debug_ranges,"",@progbits
+.Ldebug_ranges0:
+ .quad .Ltext0
+ .quad .Letext0
+ .quad .LFB0
+ .quad .LFE0
+ .quad 0
+ .quad 0
+ .section .debug_line,"",@progbits
+.Ldebug_line0:
+ .section .debug_line.dwo,"e",@progbits
+.Lskeleton_debug_line0:
+ .long .LELT0-.LSLT0
+.LSLT0:
+ .value 0x4
+ .long .LELTP0-.LASLTP0
+.LASLTP0:
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .byte 0xf6
+ .byte 0xf2
+ .byte 0xd
+ .byte 0
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 0x1
+ .byte 0
+ .byte 0
+ .byte 0x1
+ .byte 0
+ .string "dwp_test.h"
+ .uleb128 0
+ .uleb128 0
+ .uleb128 0
+ .string "dwp_test_1.cc"
+ .uleb128 0
+ .uleb128 0
+ .uleb128 0
+ .byte 0
+.LELTP0:
+.LELT0:
+ .section .debug_str_offsets.dwo,"e",@progbits
+ .long 0
+ .long 0xa
+ .long 0x14
+ .long 0x27
+ .long 0x3a
+ .long 0x44
+ .long 0x57
+ .long 0x5f
+ .long 0x72
+ .long 0x85
+ .long 0x98
+ .long 0xa2
+ .long 0xb5
+ .long 0xc8
+ .long 0xdb
+ .long 0xee
+ .long 0x101
+ .section .debug_str.dwo,"e",@progbits
+.LASF0:
+ .string "testcase1"
+.LASF1:
+ .string "testcase2"
+.LASF2:
+ .string "_ZN2C39testcase1Ev"
+.LASF3:
+ .string "_ZN2C39testcase2Ev"
+.LASF4:
+ .string "testcase3"
+.LASF5:
+ .string "_ZN2C39testcase3Ev"
+.LASF6:
+ .string "member1"
+.LASF7:
+ .string "_ZN2C29testcase1Ev"
+.LASF8:
+ .string "_ZN2C29testcase2Ev"
+.LASF9:
+ .string "_ZN2C29testcase3Ev"
+.LASF10:
+ .string "testcase4"
+.LASF11:
+ .string "_ZN2C29testcase4Ev"
+.LASF12:
+ .string "_ZN2C19testcase1Ev"
+.LASF13:
+ .string "_ZN2C19testcase2Ev"
+.LASF14:
+ .string "_ZN2C19testcase3Ev"
+.LASF15:
+ .string "_ZN2C19testcase4Ev"
+.LASF16:
+ .string "this"
+ .section .debug_addr,"",@progbits
+.Ldebug_addr0:
+ .quad .LFB0
+ .quad .LFB1
+ .quad .LFB2
+ .quad .LFB3
+ .quad .LFB4
+ .quad .LFB5
+ .quad .LFB6
+ .quad .LFB7
+ .quad .LFB8
+ .quad .LFB9
+ .quad .LFB10
+ .quad .LFB11
+ .quad .LFB12
+ .quad .LFB13
+ .quad .LFB14
+ .quad .LFB15
+ .quad .LBB2
+ .quad .LFB16
+ .quad .LBB3
+ .quad .LFB17
+ .quad .LFB18
+ .quad .LBB4
+ .quad .LBB5
+ .quad .LFB19
+ .quad .LBB6
+ .quad .LBB7
+ .quad .LBB8
+ .quad p6
+ .quad p7
+ .quad p8
+ .quad p9
+ .quad pfn
+ .ident "GCC: (Google_crosstoolv16-gcc-4.7.x-grtev3) 4.7.x-google 20120720 (prerelease)"
+ .section .note.GNU-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/dwp_test_1.sh b/binutils-2.25/gold/testsuite/dwp_test_1.sh
new file mode 100755
index 00000000..7831a499
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dwp_test_1.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+# dwp_test_1.sh -- Test the dwp tool.
+
+# Copyright 2012 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output:"
+ echo " $2"
+ echo ""
+ echo "Actual error output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check_num()
+{
+ n=$(grep -c "$2" "$1")
+ if test "$n" -ne "$3"
+ then
+ echo "Found $n occurrences (should find $3):"
+ echo " $2"
+ echo ""
+ echo "Actual error output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+STDOUT="dwp_test_1.stdout"
+
+check $STDOUT "^Contents of the .debug_info.dwo section"
+check_num $STDOUT "DW_TAG_compile_unit" 4
+check_num $STDOUT "DW_TAG_type_unit" 3
+check_num $STDOUT "DW_AT_name.*: C1" 3
+check_num $STDOUT "DW_AT_name.*: C2" 2
+check_num $STDOUT "DW_AT_name.*: C3" 3
+check_num $STDOUT "DW_AT_name.*: testcase1" 6
+check_num $STDOUT "DW_AT_name.*: testcase2" 6
+check_num $STDOUT "DW_AT_name.*: testcase3" 6
+check_num $STDOUT "DW_AT_name.*: testcase4" 4
diff --git a/binutils-2.25/gold/testsuite/dwp_test_1b.cc b/binutils-2.25/gold/testsuite/dwp_test_1b.cc
new file mode 100644
index 00000000..c75376b5
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dwp_test_1b.cc
@@ -0,0 +1,35 @@
+// dwp_test_1b.cc -- a test case for dwp
+
+// Copyright 2012 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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.
+
+// Adapted from two_file_test_1b.cc.
+
+#include "dwp_test.h"
+
+// 16 Call a function directly after its address has been taken.
+
+C3 c3;
+
+bool
+t16a()
+{
+ return f10() == 135;
+}
diff --git a/binutils-2.25/gold/testsuite/dwp_test_1b.s b/binutils-2.25/gold/testsuite/dwp_test_1b.s
new file mode 100644
index 00000000..9c9891d7
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dwp_test_1b.s
@@ -0,0 +1,549 @@
+ .file "dwp_test_1b.cc"
+ .text
+.Ltext0:
+ .globl c3
+ .bss
+ .align 4
+ .type c3, @object
+ .size c3, 4
+c3:
+ .zero 4
+ .text
+ .globl _Z4t16av
+ .type _Z4t16av, @function
+_Z4t16av:
+.LFB1:
+ .file 1 "dwp_test_1b.cc"
+ .loc 1 33 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ .loc 1 34 0
+ call _Z3f10v
+ cmpl $135, %eax
+ sete %al
+ .loc 1 35 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE1:
+ .size _Z4t16av, .-_Z4t16av
+.Letext0:
+ .file 2 "dwp_test.h"
+ .section .debug_types.dwo,"G",@progbits,wt.bb2916f0c1bd34b5,comdat
+ .long 0x119
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .long 0x25
+ .uleb128 0x1
+ .byte 0x4
+ .byte 0x8a
+ .byte 0xda
+ .byte 0x59
+ .byte 0x6e
+ .byte 0x4d
+ .byte 0x5c
+ .byte 0xa
+ .byte 0x88
+ .long .Lskeleton_debug_line0
+ .uleb128 0x2
+ .string "C3"
+ .byte 0x4
+ .byte 0x2
+ .byte 0x2f
+ .long 0xfc
+ .uleb128 0x3
+ .string "member1"
+ .byte 0x2
+ .byte 0x36
+ .long 0xfc
+ .byte 0
+ .byte 0x1
+ .uleb128 0x4
+ .string "testcase1"
+ .byte 0x2
+ .byte 0x32
+ .string "_ZN2C39testcase1Ev"
+ .long 0x103
+ .byte 0x1
+ .long 0x6e
+ .long 0x74
+ .uleb128 0x5
+ .long 0x10b
+ .byte 0
+ .uleb128 0x4
+ .string "testcase2"
+ .byte 0x2
+ .byte 0x33
+ .string "_ZN2C39testcase2Ev"
+ .long 0x103
+ .byte 0x1
+ .long 0xa1
+ .long 0xa7
+ .uleb128 0x5
+ .long 0x10b
+ .byte 0
+ .uleb128 0x4
+ .string "testcase3"
+ .byte 0x2
+ .byte 0x34
+ .string "_ZN2C39testcase3Ev"
+ .long 0x103
+ .byte 0x1
+ .long 0xd4
+ .long 0xda
+ .uleb128 0x5
+ .long 0x10b
+ .byte 0
+ .uleb128 0x6
+ .string "f4"
+ .byte 0x2
+ .byte 0x35
+ .string "_ZN2C32f4Ev"
+ .long 0x111
+ .byte 0x1
+ .long 0xf5
+ .uleb128 0x5
+ .long 0x10b
+ .byte 0
+ .byte 0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x2
+ .string "bool"
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x25
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x117
+ .uleb128 0x9
+ .long 0x103
+ .byte 0
+ .section .debug_types,"G",@progbits,wt.bb2916f0c1bd34b5,comdat
+ .long 0x6f
+ .value 0x4
+ .long .Lskeleton_debug_abbrev0
+ .byte 0x8
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .long 0
+ .uleb128 0x2
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .string "dwp_test_1b.dwo"
+ .long .Ldebug_pubnames0
+ .long .Ldebug_pubtypes0
+ .long .Ldebug_addr0
+ .section .debug_info.dwo,"e",@progbits
+.Ldebug_info0:
+ .long 0xcb
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .uleb128 0xa
+ .string "GNU C++ 4.7.x-google 20120720 (prerelease)"
+ .byte 0x4
+ .string "dwp_test_1b.cc"
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .byte 0xf6
+ .byte 0xef
+ .byte 0x47
+ .byte 0xa2
+ .byte 0x3e
+ .byte 0xc1
+ .byte 0x6e
+ .byte 0xbd
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x2
+ .string "bool"
+ .uleb128 0xb
+ .string "t16a"
+ .byte 0x1
+ .byte 0x20
+ .string "_Z4t16av"
+ .long 0x95
+ .uleb128 0
+ .quad .LFE1-.LFB1
+ .uleb128 0x1
+ .byte 0x9c
+ .uleb128 0xc
+ .string "c3"
+ .byte 0x1
+ .byte 0x1d
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .uleb128 0x2
+ .byte 0xfb
+ .uleb128 0x1
+ .byte 0
+ .section .debug_info,"",@progbits
+.Lskeleton_debug_info0:
+ .long 0x7f
+ .value 0x4
+ .long .Lskeleton_debug_abbrev0
+ .byte 0x8
+ .uleb128 0x1
+ .quad .Ltext0
+ .quad .Letext0-.Ltext0
+ .long .Ldebug_line0
+ .byte 0xf6
+ .byte 0xef
+ .byte 0x47
+ .byte 0xa2
+ .byte 0x3e
+ .byte 0xc1
+ .byte 0x6e
+ .byte 0xbd
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .string "dwp_test_1b.dwo"
+ .long .Ldebug_pubnames0
+ .long .Ldebug_pubtypes0
+ .long .Ldebug_addr0
+ .section .debug_abbrev,"",@progbits
+.Lskeleton_debug_abbrev0:
+ .uleb128 0x1
+ .uleb128 0x11
+ .byte 0
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x10
+ .uleb128 0x17
+ .uleb128 0x2131
+ .uleb128 0x7
+ .uleb128 0x1b
+ .uleb128 0x8
+ .uleb128 0x2130
+ .uleb128 0x8
+ .uleb128 0x2134
+ .uleb128 0x17
+ .uleb128 0x2135
+ .uleb128 0x17
+ .uleb128 0x2133
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+ .uleb128 0x2
+ .uleb128 0x41
+ .byte 0
+ .uleb128 0x1b
+ .uleb128 0x8
+ .uleb128 0x2130
+ .uleb128 0x8
+ .uleb128 0x2134
+ .uleb128 0x17
+ .uleb128 0x2135
+ .uleb128 0x17
+ .uleb128 0x2133
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+ .byte 0
+ .section .debug_abbrev.dwo,"e",@progbits
+.Ldebug_abbrev0:
+ .uleb128 0x1
+ .uleb128 0x41
+ .byte 0x1
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x210f
+ .uleb128 0x7
+ .uleb128 0x10
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+ .uleb128 0x2
+ .uleb128 0x2
+ .byte 0x1
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0xd
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x38
+ .uleb128 0xb
+ .uleb128 0x32
+ .uleb128 0xb
+ .byte 0
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x5
+ .uleb128 0x5
+ .byte 0
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x34
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x6
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x7
+ .uleb128 0x24
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .byte 0
+ .byte 0
+ .uleb128 0x8
+ .uleb128 0xf
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x9
+ .uleb128 0x15
+ .byte 0
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0xa
+ .uleb128 0x11
+ .byte 0x1
+ .uleb128 0x25
+ .uleb128 0x8
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x1b
+ .uleb128 0x8
+ .uleb128 0x2131
+ .uleb128 0x7
+ .byte 0
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0x2e
+ .byte 0
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x2116
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0xc
+ .uleb128 0x34
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x20
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x2
+ .uleb128 0x18
+ .byte 0
+ .byte 0
+ .byte 0
+ .section .debug_gnu_pubnames,"",@progbits
+.Ldebug_pubnames0:
+ .long 0x20
+ .value 0x2
+ .long .Lskeleton_debug_info0
+ .long 0xcf
+ .long 0x9d
+ .byte 0x30
+ .string "t16a"
+ .long 0xbd
+ .byte 0x20
+ .string "c3"
+ .long 0
+ .section .debug_gnu_pubtypes,"",@progbits
+.Ldebug_pubtypes0:
+ .long 0x29
+ .value 0x2
+ .long .Lskeleton_debug_info0
+ .long 0xcf
+ .long 0x8e
+ .byte 0x90
+ .string "int"
+ .long 0x95
+ .byte 0x90
+ .string "bool"
+ .long 0
+ .byte 0x10
+ .string "C3"
+ .long 0
+ .section .debug_aranges,"",@progbits
+ .long 0x2c
+ .value 0x2
+ .long .Lskeleton_debug_info0
+ .byte 0x8
+ .byte 0
+ .value 0
+ .value 0
+ .quad .Ltext0
+ .quad .Letext0-.Ltext0
+ .quad 0
+ .quad 0
+ .section .debug_line,"",@progbits
+.Ldebug_line0:
+ .section .debug_line.dwo,"e",@progbits
+.Lskeleton_debug_line0:
+ .long .LELT0-.LSLT0
+.LSLT0:
+ .value 0x4
+ .long .LELTP0-.LASLTP0
+.LASLTP0:
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .byte 0xf6
+ .byte 0xf2
+ .byte 0xd
+ .byte 0
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 0x1
+ .byte 0
+ .byte 0
+ .byte 0x1
+ .byte 0
+ .string "dwp_test_1b.cc"
+ .uleb128 0
+ .uleb128 0
+ .uleb128 0
+ .string "dwp_test.h"
+ .uleb128 0
+ .uleb128 0
+ .uleb128 0
+ .byte 0
+.LELTP0:
+.LELT0:
+ .section .debug_addr,"",@progbits
+.Ldebug_addr0:
+ .quad .LFB1
+ .quad c3
+ .ident "GCC: (Google_crosstoolv16-gcc-4.7.x-grtev3) 4.7.x-google 20120720 (prerelease)"
+ .section .note.GNU-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/dwp_test_2.cc b/binutils-2.25/gold/testsuite/dwp_test_2.cc
new file mode 100644
index 00000000..a1172b31
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dwp_test_2.cc
@@ -0,0 +1,144 @@
+// dwp_test_2.cc -- a test case for dwp
+
+// Copyright 2012 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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.
+
+// Adapted from two_file_test_2.cc.
+
+#include "dwp_test.h"
+
+// 1 Code in file 1 calls code in file 2.
+
+int
+C1::t1_2()
+{
+ return 123;
+}
+
+bool
+C1::t1a()
+{
+ return t1_2() == 123;
+}
+
+// 2 Code in file 1 refers to global data in file 2.
+
+int v2 = 456;
+
+// 3 Code in file 1 referes to common symbol in file 2. This is
+// initialized at runtime to 789.
+
+int v3;
+
+// 4 Code in file 1 refers to offset within global data in file 2.
+
+char v4[] = "Hello, world";
+
+// 5 Code in file 1 refers to offset within common symbol in file 2.
+// This is initialized at runtime to a copy of v4.
+
+char v5[13];
+
+// 6 Data in file 1 refers to global data in file 2. This reuses v2.
+
+// 7 Data in file 1 refers to common symbol in file 2. This reuses v3.
+
+// 8 Data in file 1 refers to offset within global data in file 2.
+// This reuses v4.
+
+// 9 Data in file 1 refers to offset within common symbol in file 2.
+// This reuses v5.
+
+// 10 Data in file 1 refers to function in file 2.
+
+int
+f10()
+{
+ return 135;
+}
+
+// 11 Pass function pointer from file 1 to file 2.
+
+int
+f11b(int (*pfn)())
+{
+ return (*pfn)();
+}
+
+// 12 Compare address of function for equality in both files.
+
+bool
+(*C3::f4())()
+{
+ return &t12;
+}
+
+// 13 Compare address of inline function for equality in both files.
+
+void
+(*f13())()
+{
+ return &f13i;
+}
+
+// 14 Compare string constants in file 1 and file 2.
+
+const char*
+f14()
+{
+ return TEST_STRING_CONSTANT;
+}
+
+// 15 Compare wide string constants in file 1 and file 2.
+
+const wchar_t*
+f15()
+{
+ return TEST_WIDE_STRING_CONSTANT;
+}
+
+// 17 File 1 checks array of string constants defined in file 2.
+
+const char* t17data[T17_COUNT] =
+{
+ "a", "b", "c", "d", "e"
+};
+
+// 18 File 1 checks string constants referenced directly in file 2.
+
+const char*
+f18(int i)
+{
+ switch (i)
+ {
+ case 0:
+ return "a";
+ case 1:
+ return "b";
+ case 2:
+ return "c";
+ case 3:
+ return "d";
+ case 4:
+ return "e";
+ default:
+ return 0;
+ }
+}
diff --git a/binutils-2.25/gold/testsuite/dwp_test_2.s b/binutils-2.25/gold/testsuite/dwp_test_2.s
new file mode 100644
index 00000000..fa807714
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dwp_test_2.s
@@ -0,0 +1,1714 @@
+ .file "dwp_test_2.cc"
+ .text
+.Ltext0:
+ .section .text._Z4f13iv,"axG",@progbits,_Z4f13iv,comdat
+ .weak _Z4f13iv
+ .type _Z4f13iv, @function
+_Z4f13iv:
+.LFB0:
+ .file 1 "dwp_test.h"
+ .loc 1 70 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ .loc 1 70 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE0:
+ .size _Z4f13iv, .-_Z4f13iv
+ .text
+ .align 2
+ .globl _ZN2C14t1_2Ev
+ .type _ZN2C14t1_2Ev, @function
+_ZN2C14t1_2Ev:
+.LFB1:
+ .file 2 "dwp_test_2.cc"
+ .loc 2 31 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movq %rdi, -8(%rbp)
+ .loc 2 32 0
+ movl $123, %eax
+ .loc 2 33 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE1:
+ .size _ZN2C14t1_2Ev, .-_ZN2C14t1_2Ev
+ .align 2
+ .globl _ZN2C13t1aEv
+ .type _ZN2C13t1aEv, @function
+_ZN2C13t1aEv:
+.LFB2:
+ .loc 2 37 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ subq $8, %rsp
+ movq %rdi, -8(%rbp)
+ .loc 2 38 0
+ movq -8(%rbp), %rax
+ movq %rax, %rdi
+ call _ZN2C14t1_2Ev
+ cmpl $123, %eax
+ sete %al
+ .loc 2 39 0
+ leave
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE2:
+ .size _ZN2C13t1aEv, .-_ZN2C13t1aEv
+ .globl v2
+ .data
+ .align 4
+ .type v2, @object
+ .size v2, 4
+v2:
+ .long 456
+ .globl v3
+ .bss
+ .align 4
+ .type v3, @object
+ .size v3, 4
+v3:
+ .zero 4
+ .globl v4
+ .data
+ .type v4, @object
+ .size v4, 13
+v4:
+ .string "Hello, world"
+ .globl v5
+ .bss
+ .type v5, @object
+ .size v5, 13
+v5:
+ .zero 13
+ .text
+ .globl _Z3f10v
+ .type _Z3f10v, @function
+_Z3f10v:
+.LFB3:
+ .loc 2 73 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ .loc 2 74 0
+ movl $135, %eax
+ .loc 2 75 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE3:
+ .size _Z3f10v, .-_Z3f10v
+ .globl _Z4f11bPFivE
+ .type _Z4f11bPFivE, @function
+_Z4f11bPFivE:
+.LFB4:
+ .loc 2 81 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ subq $16, %rsp
+ movq %rdi, -8(%rbp)
+ .loc 2 82 0
+ movq -8(%rbp), %rax
+ call *%rax
+ .loc 2 83 0
+ leave
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE4:
+ .size _Z4f11bPFivE, .-_Z4f11bPFivE
+ .align 2
+ .globl _ZN2C32f4Ev
+ .type _ZN2C32f4Ev, @function
+_ZN2C32f4Ev:
+.LFB5:
+ .loc 2 89 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movq %rdi, -8(%rbp)
+ .loc 2 90 0
+ movl $_Z3t12v, %eax
+ .loc 2 91 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE5:
+ .size _ZN2C32f4Ev, .-_ZN2C32f4Ev
+ .globl _Z3f13v
+ .type _Z3f13v, @function
+_Z3f13v:
+.LFB6:
+ .loc 2 97 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ .loc 2 98 0
+ movl $_Z4f13iv, %eax
+ .loc 2 99 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE6:
+ .size _Z3f13v, .-_Z3f13v
+ .section .rodata
+.LC0:
+ .string "test string constant"
+ .text
+ .globl _Z3f14v
+ .type _Z3f14v, @function
+_Z3f14v:
+.LFB7:
+ .loc 2 105 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ .loc 2 106 0
+ movl $.LC0, %eax
+ .loc 2 107 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE7:
+ .size _Z3f14v, .-_Z3f14v
+ .section .rodata
+ .align 8
+.LC1:
+ .string "t"
+ .string ""
+ .string ""
+ .string "e"
+ .string ""
+ .string ""
+ .string "s"
+ .string ""
+ .string ""
+ .string "t"
+ .string ""
+ .string ""
+ .string " "
+ .string ""
+ .string ""
+ .string "w"
+ .string ""
+ .string ""
+ .string "i"
+ .string ""
+ .string ""
+ .string "d"
+ .string ""
+ .string ""
+ .string "e"
+ .string ""
+ .string ""
+ .string " "
+ .string ""
+ .string ""
+ .string "s"
+ .string ""
+ .string ""
+ .string "t"
+ .string ""
+ .string ""
+ .string "r"
+ .string ""
+ .string ""
+ .string "i"
+ .string ""
+ .string ""
+ .string "n"
+ .string ""
+ .string ""
+ .string "g"
+ .string ""
+ .string ""
+ .string " "
+ .string ""
+ .string ""
+ .string "c"
+ .string ""
+ .string ""
+ .string "o"
+ .string ""
+ .string ""
+ .string "n"
+ .string ""
+ .string ""
+ .string "s"
+ .string ""
+ .string ""
+ .string "t"
+ .string ""
+ .string ""
+ .string "a"
+ .string ""
+ .string ""
+ .string "n"
+ .string ""
+ .string ""
+ .string "t"
+ .string ""
+ .string ""
+ .string ""
+ .string ""
+ .string ""
+ .string ""
+ .text
+ .globl _Z3f15v
+ .type _Z3f15v, @function
+_Z3f15v:
+.LFB8:
+ .loc 2 113 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ .loc 2 114 0
+ movl $.LC1, %eax
+ .loc 2 115 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE8:
+ .size _Z3f15v, .-_Z3f15v
+ .globl t17data
+ .section .rodata
+.LC2:
+ .string "a"
+.LC3:
+ .string "b"
+.LC4:
+ .string "c"
+.LC5:
+ .string "d"
+.LC6:
+ .string "e"
+ .data
+ .align 32
+ .type t17data, @object
+ .size t17data, 40
+t17data:
+ .quad .LC2
+ .quad .LC3
+ .quad .LC4
+ .quad .LC5
+ .quad .LC6
+ .text
+ .globl _Z3f18i
+ .type _Z3f18i, @function
+_Z3f18i:
+.LFB9:
+ .loc 2 128 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movl %edi, -4(%rbp)
+ .loc 2 129 0
+ cmpl $4, -4(%rbp)
+ ja .L19
+ movl -4(%rbp), %eax
+ movq .L25(,%rax,8), %rax
+ jmp *%rax
+ .section .rodata
+ .align 8
+ .align 4
+.L25:
+ .quad .L20
+ .quad .L21
+ .quad .L22
+ .quad .L23
+ .quad .L24
+ .text
+.L20:
+ .loc 2 132 0
+ movl $.LC2, %eax
+ jmp .L26
+.L21:
+ .loc 2 134 0
+ movl $.LC3, %eax
+ jmp .L26
+.L22:
+ .loc 2 136 0
+ movl $.LC4, %eax
+ jmp .L26
+.L23:
+ .loc 2 138 0
+ movl $.LC5, %eax
+ jmp .L26
+.L24:
+ .loc 2 140 0
+ movl $.LC6, %eax
+ jmp .L26
+.L19:
+ .loc 2 142 0
+ movl $0, %eax
+.L26:
+ .loc 2 144 0
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE9:
+ .size _Z3f18i, .-_Z3f18i
+.Letext0:
+ .section .debug_types.dwo,"G",@progbits,wt.bb2916f0c1bd34b5,comdat
+ .long 0xf3
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .long 0x25
+ .uleb128 0x1
+ .byte 0x4
+ .byte 0x8a
+ .byte 0xda
+ .byte 0x59
+ .byte 0x6e
+ .byte 0x4d
+ .byte 0x5c
+ .byte 0xa
+ .byte 0x88
+ .long .Lskeleton_debug_line0
+ .uleb128 0x2
+ .string "C3"
+ .byte 0x4
+ .byte 0x1
+ .byte 0x2f
+ .long 0xd6
+ .uleb128 0x3
+ .string "member1"
+ .byte 0x1
+ .byte 0x36
+ .long 0xd6
+ .byte 0
+ .byte 0x1
+ .uleb128 0x4
+ .uleb128 0
+ .byte 0x1
+ .byte 0x32
+ .string "_ZN2C39testcase1Ev"
+ .long 0xdd
+ .byte 0x1
+ .long 0x65
+ .long 0x6b
+ .uleb128 0x5
+ .long 0xe5
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x1
+ .byte 0x1
+ .byte 0x33
+ .string "_ZN2C39testcase2Ev"
+ .long 0xdd
+ .byte 0x1
+ .long 0x8f
+ .long 0x95
+ .uleb128 0x5
+ .long 0xe5
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x2
+ .byte 0x1
+ .byte 0x34
+ .string "_ZN2C39testcase3Ev"
+ .long 0xdd
+ .byte 0x1
+ .long 0xb9
+ .long 0xbf
+ .uleb128 0x5
+ .long 0xe5
+ .byte 0
+ .uleb128 0x6
+ .string "f4"
+ .byte 0x1
+ .byte 0x35
+ .uleb128 0x3
+ .long 0xeb
+ .byte 0x1
+ .long 0xcf
+ .uleb128 0x5
+ .long 0xe5
+ .byte 0
+ .byte 0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x2
+ .string "bool"
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x25
+ .uleb128 0x8
+ .byte 0x8
+ .long 0xf1
+ .uleb128 0x9
+ .long 0xdd
+ .byte 0
+ .section .debug_types,"G",@progbits,wt.bb2916f0c1bd34b5,comdat
+ .long 0x6e
+ .value 0x4
+ .long .Lskeleton_debug_abbrev0
+ .byte 0x8
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .long 0
+ .uleb128 0x2
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .string "dwp_test_2.dwo"
+ .long .Ldebug_pubnames0
+ .long .Ldebug_pubtypes0
+ .long .Ldebug_addr0
+ .section .debug_types.dwo,"G",@progbits,wt.c419a9b7a4a2fab5,comdat
+ .long 0x138
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .byte 0xc4
+ .byte 0x19
+ .byte 0xa9
+ .byte 0xb7
+ .byte 0xa4
+ .byte 0xa2
+ .byte 0xfa
+ .byte 0xb5
+ .long 0x25
+ .uleb128 0x1
+ .byte 0x4
+ .byte 0xe3
+ .byte 0xad
+ .byte 0x5
+ .byte 0x3b
+ .byte 0x75
+ .byte 0xeb
+ .byte 0xfb
+ .byte 0xc7
+ .long .Lskeleton_debug_line0
+ .uleb128 0x2
+ .string "C1"
+ .byte 0x4
+ .byte 0x1
+ .byte 0x19
+ .long 0x126
+ .uleb128 0x3
+ .string "member1"
+ .byte 0x1
+ .byte 0x22
+ .long 0x126
+ .byte 0
+ .byte 0x1
+ .uleb128 0x4
+ .uleb128 0
+ .byte 0x1
+ .byte 0x1c
+ .string "_ZN2C19testcase1Ev"
+ .long 0x12d
+ .byte 0x1
+ .long 0x65
+ .long 0x6b
+ .uleb128 0x5
+ .long 0x135
+ .byte 0
+ .uleb128 0xa
+ .string "t1a"
+ .byte 0x1
+ .byte 0x1d
+ .uleb128 0x4
+ .long 0x12d
+ .byte 0x1
+ .long 0x80
+ .long 0x86
+ .uleb128 0x5
+ .long 0x135
+ .byte 0
+ .uleb128 0xa
+ .string "t1_2"
+ .byte 0x1
+ .byte 0x1e
+ .uleb128 0x5
+ .long 0x126
+ .byte 0x1
+ .long 0x9c
+ .long 0xa2
+ .uleb128 0x5
+ .long 0x135
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x1
+ .byte 0x1
+ .byte 0x1f
+ .string "_ZN2C19testcase2Ev"
+ .long 0x12d
+ .byte 0x1
+ .long 0xc6
+ .long 0xcc
+ .uleb128 0x5
+ .long 0x135
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x2
+ .byte 0x1
+ .byte 0x20
+ .string "_ZN2C19testcase3Ev"
+ .long 0x12d
+ .byte 0x1
+ .long 0xf0
+ .long 0xf6
+ .uleb128 0x5
+ .long 0x135
+ .byte 0
+ .uleb128 0xb
+ .string "testcase4"
+ .byte 0x1
+ .byte 0x21
+ .string "_ZN2C19testcase4Ev"
+ .long 0x12d
+ .byte 0x1
+ .long 0x11f
+ .uleb128 0x5
+ .long 0x135
+ .byte 0
+ .byte 0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x2
+ .string "bool"
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x25
+ .byte 0
+ .section .debug_types,"G",@progbits,wt.c419a9b7a4a2fab5,comdat
+ .long 0x6e
+ .value 0x4
+ .long .Lskeleton_debug_abbrev0
+ .byte 0x8
+ .byte 0xc4
+ .byte 0x19
+ .byte 0xa9
+ .byte 0xb7
+ .byte 0xa4
+ .byte 0xa2
+ .byte 0xfa
+ .byte 0xb5
+ .long 0
+ .uleb128 0x2
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .string "dwp_test_2.dwo"
+ .long .Ldebug_pubnames0
+ .long .Ldebug_pubtypes0
+ .long .Ldebug_addr0
+ .section .debug_info.dwo,"e",@progbits
+.Ldebug_info0:
+ .long 0x329
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .uleb128 0xc
+ .string "GNU C++ 4.7.x-google 20120720 (prerelease)"
+ .byte 0x4
+ .string "dwp_test_2.cc"
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .byte 0xb9
+ .byte 0xf8
+ .byte 0xe0
+ .byte 0x8c
+ .byte 0x71
+ .byte 0xab
+ .byte 0xc
+ .byte 0xcf
+ .uleb128 0xd
+ .string "C1"
+ .byte 0xc4
+ .byte 0x19
+ .byte 0xa9
+ .byte 0xb7
+ .byte 0xa4
+ .byte 0xa2
+ .byte 0xfa
+ .byte 0xb5
+ .long 0xb9
+ .uleb128 0xe
+ .string "t1a"
+ .byte 0x1
+ .byte 0x1d
+ .uleb128 0x4
+ .long 0xc0
+ .byte 0x1
+ .uleb128 0xe
+ .string "t1_2"
+ .byte 0x1
+ .byte 0x1e
+ .uleb128 0x5
+ .long 0xb9
+ .byte 0x1
+ .byte 0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x2
+ .string "bool"
+ .uleb128 0xf
+ .byte 0x8
+ .byte 0xc4
+ .byte 0x19
+ .byte 0xa9
+ .byte 0xb7
+ .byte 0xa4
+ .byte 0xa2
+ .byte 0xfa
+ .byte 0xb5
+ .uleb128 0xd
+ .string "C3"
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .long 0xef
+ .uleb128 0xe
+ .string "f4"
+ .byte 0x1
+ .byte 0x35
+ .uleb128 0x3
+ .long 0xfe
+ .byte 0x1
+ .byte 0
+ .uleb128 0xf
+ .byte 0x8
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .uleb128 0x9
+ .long 0xc0
+ .uleb128 0x8
+ .byte 0x8
+ .long 0xf9
+ .uleb128 0x10
+ .string "f13i"
+ .byte 0x1
+ .byte 0x46
+ .string "_Z4f13iv"
+ .uleb128 0
+ .quad .LFE0-.LFB0
+ .uleb128 0x1
+ .byte 0x9c
+ .uleb128 0x11
+ .long 0xaa
+ .byte 0x2
+ .uleb128 0x1
+ .quad .LFE1-.LFB1
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x139
+ .long 0x147
+ .uleb128 0x12
+ .string "this"
+ .long 0x147
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x13
+ .long 0xc8
+ .uleb128 0x14
+ .long 0x9d
+ .byte 0x2
+ .byte 0x24
+ .uleb128 0x2
+ .quad .LFE2-.LFB2
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x166
+ .long 0x174
+ .uleb128 0x12
+ .string "this"
+ .long 0x147
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x15
+ .string "f10"
+ .byte 0x2
+ .byte 0x48
+ .string "_Z3f10v"
+ .long 0xb9
+ .uleb128 0x3
+ .quad .LFE3-.LFB3
+ .uleb128 0x1
+ .byte 0x9c
+ .uleb128 0x16
+ .string "f11b"
+ .byte 0x2
+ .byte 0x50
+ .string "_Z4f11bPFivE"
+ .long 0xb9
+ .uleb128 0x4
+ .quad .LFE4-.LFB4
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x1c9
+ .uleb128 0x17
+ .string "pfn"
+ .byte 0x2
+ .byte 0x50
+ .long 0x1ce
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x9
+ .long 0xb9
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x1c9
+ .uleb128 0x18
+ .long 0xe2
+ .byte 0x2
+ .byte 0x58
+ .uleb128 0x5
+ .quad .LFE5-.LFB5
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x1ee
+ .long 0x1fc
+ .uleb128 0x12
+ .string "this"
+ .long 0x1fc
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -24
+ .byte 0
+ .uleb128 0x13
+ .long 0xef
+ .uleb128 0x19
+ .uleb128 0x15
+ .string "f13"
+ .byte 0x2
+ .byte 0x60
+ .string "_Z3f13v"
+ .long 0x220
+ .uleb128 0x6
+ .quad .LFE6-.LFB6
+ .uleb128 0x1
+ .byte 0x9c
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x201
+ .uleb128 0x15
+ .string "f14"
+ .byte 0x2
+ .byte 0x68
+ .string "_Z3f14v"
+ .long 0x244
+ .uleb128 0x7
+ .quad .LFE7-.LFB7
+ .uleb128 0x1
+ .byte 0x9c
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x24a
+ .uleb128 0x13
+ .long 0x24f
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x6
+ .string "char"
+ .uleb128 0x15
+ .string "f15"
+ .byte 0x2
+ .byte 0x70
+ .string "_Z3f15v"
+ .long 0x275
+ .uleb128 0x8
+ .quad .LFE8-.LFB8
+ .uleb128 0x1
+ .byte 0x9c
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x27b
+ .uleb128 0x13
+ .long 0x280
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "wchar_t"
+ .uleb128 0x1a
+ .string "f18"
+ .byte 0x2
+ .byte 0x7f
+ .string "_Z3f18i"
+ .long 0x244
+ .uleb128 0x9
+ .quad .LFE9-.LFB9
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x2ba
+ .uleb128 0x17
+ .string "i"
+ .byte 0x2
+ .byte 0x7f
+ .long 0xb9
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -20
+ .byte 0
+ .uleb128 0x1b
+ .string "v2"
+ .byte 0x2
+ .byte 0x2b
+ .long 0xb9
+ .uleb128 0x2
+ .byte 0xfb
+ .uleb128 0xa
+ .uleb128 0x1b
+ .string "v3"
+ .byte 0x2
+ .byte 0x30
+ .long 0xb9
+ .uleb128 0x2
+ .byte 0xfb
+ .uleb128 0xb
+ .uleb128 0x1c
+ .long 0x24f
+ .long 0x2e4
+ .uleb128 0x1d
+ .long 0x2e4
+ .byte 0xc
+ .byte 0
+ .uleb128 0x7
+ .byte 0x8
+ .byte 0x7
+ .string "sizetype"
+ .uleb128 0x1b
+ .string "v4"
+ .byte 0x2
+ .byte 0x34
+ .long 0x2d4
+ .uleb128 0x2
+ .byte 0xfb
+ .uleb128 0xc
+ .uleb128 0x1b
+ .string "v5"
+ .byte 0x2
+ .byte 0x39
+ .long 0x2d4
+ .uleb128 0x2
+ .byte 0xfb
+ .uleb128 0xd
+ .uleb128 0x1c
+ .long 0x244
+ .long 0x31a
+ .uleb128 0x1d
+ .long 0x2e4
+ .byte 0x4
+ .byte 0
+ .uleb128 0x1b
+ .string "t17data"
+ .byte 0x2
+ .byte 0x77
+ .long 0x30a
+ .uleb128 0x2
+ .byte 0xfb
+ .uleb128 0xe
+ .byte 0
+ .section .debug_info,"",@progbits
+.Lskeleton_debug_info0:
+ .long 0x7e
+ .value 0x4
+ .long .Lskeleton_debug_abbrev0
+ .byte 0x8
+ .uleb128 0x1
+ .long .Ldebug_ranges0+0
+ .quad 0
+ .long .Ldebug_line0
+ .byte 0xb9
+ .byte 0xf8
+ .byte 0xe0
+ .byte 0x8c
+ .byte 0x71
+ .byte 0xab
+ .byte 0xc
+ .byte 0xcf
+ .long .Ldebug_ranges0
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .string "dwp_test_2.dwo"
+ .long .Ldebug_pubnames0
+ .long .Ldebug_pubtypes0
+ .long .Ldebug_addr0
+ .section .debug_abbrev,"",@progbits
+.Lskeleton_debug_abbrev0:
+ .uleb128 0x1
+ .uleb128 0x11
+ .byte 0
+ .uleb128 0x55
+ .uleb128 0x17
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x10
+ .uleb128 0x17
+ .uleb128 0x2131
+ .uleb128 0x7
+ .uleb128 0x2132
+ .uleb128 0x17
+ .uleb128 0x1b
+ .uleb128 0x8
+ .uleb128 0x2130
+ .uleb128 0x8
+ .uleb128 0x2134
+ .uleb128 0x17
+ .uleb128 0x2135
+ .uleb128 0x17
+ .uleb128 0x2133
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+ .uleb128 0x2
+ .uleb128 0x41
+ .byte 0
+ .uleb128 0x1b
+ .uleb128 0x8
+ .uleb128 0x2130
+ .uleb128 0x8
+ .uleb128 0x2134
+ .uleb128 0x17
+ .uleb128 0x2135
+ .uleb128 0x17
+ .uleb128 0x2133
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+ .byte 0
+ .section .debug_abbrev.dwo,"e",@progbits
+.Ldebug_abbrev0:
+ .uleb128 0x1
+ .uleb128 0x41
+ .byte 0x1
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x210f
+ .uleb128 0x7
+ .uleb128 0x10
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+ .uleb128 0x2
+ .uleb128 0x2
+ .byte 0x1
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0xd
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x38
+ .uleb128 0xb
+ .uleb128 0x32
+ .uleb128 0xb
+ .byte 0
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x1f02
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x5
+ .uleb128 0x5
+ .byte 0
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x34
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x6
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x1f02
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x7
+ .uleb128 0x24
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .byte 0
+ .byte 0
+ .uleb128 0x8
+ .uleb128 0xf
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x9
+ .uleb128 0x15
+ .byte 0
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0xa
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x1f02
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0xc
+ .uleb128 0x11
+ .byte 0x1
+ .uleb128 0x25
+ .uleb128 0x8
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x1b
+ .uleb128 0x8
+ .uleb128 0x2131
+ .uleb128 0x7
+ .byte 0
+ .byte 0
+ .uleb128 0xd
+ .uleb128 0x2
+ .byte 0x1
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x69
+ .uleb128 0x20
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0xe
+ .uleb128 0x2e
+ .byte 0
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x1f02
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0xf
+ .uleb128 0xf
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x20
+ .byte 0
+ .byte 0
+ .uleb128 0x10
+ .uleb128 0x2e
+ .byte 0
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x2117
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x11
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x47
+ .uleb128 0x13
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x64
+ .uleb128 0x13
+ .uleb128 0x2117
+ .uleb128 0x19
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x12
+ .uleb128 0x5
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x34
+ .uleb128 0x19
+ .uleb128 0x2
+ .uleb128 0x18
+ .byte 0
+ .byte 0
+ .uleb128 0x13
+ .uleb128 0x26
+ .byte 0
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x14
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x47
+ .uleb128 0x13
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x64
+ .uleb128 0x13
+ .uleb128 0x2116
+ .uleb128 0x19
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x15
+ .uleb128 0x2e
+ .byte 0
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x2117
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x16
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x2116
+ .uleb128 0x19
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x17
+ .uleb128 0x5
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0x18
+ .byte 0
+ .byte 0
+ .uleb128 0x18
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x47
+ .uleb128 0x13
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x64
+ .uleb128 0x13
+ .uleb128 0x2117
+ .uleb128 0x19
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x19
+ .uleb128 0x15
+ .byte 0
+ .byte 0
+ .byte 0
+ .uleb128 0x1a
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x2117
+ .uleb128 0x19
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x1b
+ .uleb128 0x34
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x2
+ .uleb128 0x18
+ .byte 0
+ .byte 0
+ .uleb128 0x1c
+ .uleb128 0x1
+ .byte 0x1
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x1d
+ .uleb128 0x21
+ .byte 0
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2f
+ .uleb128 0xb
+ .byte 0
+ .byte 0
+ .byte 0
+ .section .debug_gnu_pubnames,"",@progbits
+.Ldebug_pubnames0:
+ .long 0xa3
+ .value 0x2
+ .long .Lskeleton_debug_info0
+ .long 0x32d
+ .long 0x104
+ .byte 0x30
+ .string "f13i"
+ .long 0x120
+ .byte 0x30
+ .string "C1::t1_2"
+ .long 0x14c
+ .byte 0x30
+ .string "C1::t1a"
+ .long 0x174
+ .byte 0x30
+ .string "f10"
+ .long 0x192
+ .byte 0x30
+ .string "f11b"
+ .long 0x1d4
+ .byte 0x30
+ .string "C3::f4"
+ .long 0x202
+ .byte 0x30
+ .string "f13"
+ .long 0x226
+ .byte 0x30
+ .string "f14"
+ .long 0x257
+ .byte 0x30
+ .string "f15"
+ .long 0x28b
+ .byte 0x30
+ .string "f18"
+ .long 0x2ba
+ .byte 0x20
+ .string "v2"
+ .long 0x2c7
+ .byte 0x20
+ .string "v3"
+ .long 0x2f0
+ .byte 0x20
+ .string "v4"
+ .long 0x2fd
+ .byte 0x20
+ .string "v5"
+ .long 0x31a
+ .byte 0x20
+ .string "t17data"
+ .long 0
+ .section .debug_gnu_pubtypes,"",@progbits
+.Ldebug_pubtypes0:
+ .long 0x56
+ .value 0x2
+ .long .Lskeleton_debug_info0
+ .long 0x32d
+ .long 0xb9
+ .byte 0x90
+ .string "int"
+ .long 0xc0
+ .byte 0x90
+ .string "bool"
+ .long 0x8d
+ .byte 0x10
+ .string "C1"
+ .long 0xd2
+ .byte 0x10
+ .string "C3"
+ .long 0x24f
+ .byte 0x90
+ .string "char"
+ .long 0x280
+ .byte 0x90
+ .string "wchar_t"
+ .long 0x2e4
+ .byte 0x90
+ .string "sizetype"
+ .long 0
+ .section .debug_aranges,"",@progbits
+ .long 0x3c
+ .value 0x2
+ .long .Lskeleton_debug_info0
+ .byte 0x8
+ .byte 0
+ .value 0
+ .value 0
+ .quad .Ltext0
+ .quad .Letext0-.Ltext0
+ .quad .LFB0
+ .quad .LFE0-.LFB0
+ .quad 0
+ .quad 0
+ .section .debug_ranges,"",@progbits
+.Ldebug_ranges0:
+ .quad .Ltext0
+ .quad .Letext0
+ .quad .LFB0
+ .quad .LFE0
+ .quad 0
+ .quad 0
+ .section .debug_line,"",@progbits
+.Ldebug_line0:
+ .section .debug_line.dwo,"e",@progbits
+.Lskeleton_debug_line0:
+ .long .LELT0-.LSLT0
+.LSLT0:
+ .value 0x4
+ .long .LELTP0-.LASLTP0
+.LASLTP0:
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .byte 0xf6
+ .byte 0xf2
+ .byte 0xd
+ .byte 0
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 0x1
+ .byte 0
+ .byte 0
+ .byte 0x1
+ .byte 0
+ .string "dwp_test.h"
+ .uleb128 0
+ .uleb128 0
+ .uleb128 0
+ .string "dwp_test_2.cc"
+ .uleb128 0
+ .uleb128 0
+ .uleb128 0
+ .byte 0
+.LELTP0:
+.LELT0:
+ .section .debug_str_offsets.dwo,"e",@progbits
+ .long 0
+ .long 0xa
+ .long 0x14
+ .long 0x1e
+ .long 0x2a
+ .long 0x37
+ .section .debug_str.dwo,"e",@progbits
+.LASF0:
+ .string "testcase1"
+.LASF1:
+ .string "testcase2"
+.LASF2:
+ .string "testcase3"
+.LASF3:
+ .string "_ZN2C32f4Ev"
+.LASF4:
+ .string "_ZN2C13t1aEv"
+.LASF5:
+ .string "_ZN2C14t1_2Ev"
+ .section .debug_addr,"",@progbits
+.Ldebug_addr0:
+ .quad .LFB0
+ .quad .LFB1
+ .quad .LFB2
+ .quad .LFB3
+ .quad .LFB4
+ .quad .LFB5
+ .quad .LFB6
+ .quad .LFB7
+ .quad .LFB8
+ .quad .LFB9
+ .quad v2
+ .quad v3
+ .quad v4
+ .quad v5
+ .quad t17data
+ .ident "GCC: (Google_crosstoolv16-gcc-4.7.x-grtev3) 4.7.x-google 20120720 (prerelease)"
+ .section .note.GNU-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/dwp_test_2.sh b/binutils-2.25/gold/testsuite/dwp_test_2.sh
new file mode 100755
index 00000000..619d73b9
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dwp_test_2.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+# dwp_test_2.sh -- Test the dwp tool.
+
+# Copyright 2012 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output:"
+ echo " $2"
+ echo ""
+ echo "Actual error output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check_num()
+{
+ n=$(grep -c "$2" "$1")
+ if test "$n" -ne "$3"
+ then
+ echo "Found $n occurrences (should find $3):"
+ echo " $2"
+ echo ""
+ echo "Actual error output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+STDOUT="dwp_test_2.stdout"
+
+check $STDOUT "^Contents of the .debug_info.dwo section"
+check_num $STDOUT "DW_TAG_compile_unit" 4
+check_num $STDOUT "DW_TAG_type_unit" 3
+check_num $STDOUT "DW_AT_name.*: C1" 3
+check_num $STDOUT "DW_AT_name.*: C2" 2
+check_num $STDOUT "DW_AT_name.*: C3" 3
+check_num $STDOUT "DW_AT_name.*: testcase1" 6
+check_num $STDOUT "DW_AT_name.*: testcase2" 6
+check_num $STDOUT "DW_AT_name.*: testcase3" 6
+check_num $STDOUT "DW_AT_name.*: testcase4" 4
diff --git a/binutils-2.25/gold/testsuite/dwp_test_main.cc b/binutils-2.25/gold/testsuite/dwp_test_main.cc
new file mode 100644
index 00000000..abddc0fa
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dwp_test_main.cc
@@ -0,0 +1,59 @@
+// dwp_test_main.cc -- a test case for dwp
+
+// Copyright 2012 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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.
+
+// Adapted from two_file_test_main.cc.
+
+#include <cassert>
+
+#include "dwp_test.h"
+
+int
+main()
+{
+ C1 c1;
+ C2 c2;
+
+ // Initialize common data.
+ v3 = 789;
+ for (int i = 0; i < 13; ++i)
+ v5[i] = v4[i];
+
+ assert(c1.testcase1());
+ assert(c1.t1a());
+ assert(c1.testcase2());
+ assert(c1.testcase3());
+ assert(c1.testcase4());
+ assert(c2.testcase1());
+ assert(c2.testcase2());
+ assert(c2.testcase3());
+ assert(c2.testcase4());
+ assert(c3.testcase1());
+ assert(c3.testcase2());
+ assert(c3.testcase3());
+ assert(t12());
+ assert(t13());
+ assert(t16());
+ assert(t16a());
+ assert(t17());
+ assert(t18());
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/dwp_test_main.s b/binutils-2.25/gold/testsuite/dwp_test_main.s
new file mode 100644
index 00000000..f8643658
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dwp_test_main.s
@@ -0,0 +1,1399 @@
+ .file "dwp_test_main.cc"
+ .text
+.Ltext0:
+ .section .rodata
+.LC0:
+ .string "dwp_test_main.cc"
+.LC1:
+ .string "c1.testcase1()"
+.LC2:
+ .string "c1.t1a()"
+.LC3:
+ .string "c1.testcase2()"
+.LC4:
+ .string "c1.testcase3()"
+.LC5:
+ .string "c1.testcase4()"
+.LC6:
+ .string "c2.testcase1()"
+.LC7:
+ .string "c2.testcase2()"
+.LC8:
+ .string "c2.testcase3()"
+.LC9:
+ .string "c2.testcase4()"
+.LC10:
+ .string "c3.testcase1()"
+.LC11:
+ .string "c3.testcase2()"
+.LC12:
+ .string "c3.testcase3()"
+.LC13:
+ .string "t12()"
+.LC14:
+ .string "t13()"
+.LC15:
+ .string "t16()"
+.LC16:
+ .string "t16a()"
+.LC17:
+ .string "t17()"
+.LC18:
+ .string "t18()"
+ .text
+ .globl main
+ .type main, @function
+main:
+.LFB1:
+ .file 1 "dwp_test_main.cc"
+ .loc 1 31 0
+ .cfi_startproc
+ .cfi_personality 0x3,__gxx_personality_v0
+ .cfi_lsda 0x3,.LLSDA1
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ subq $32, %rsp
+.LBB2:
+ .loc 1 36 0
+ movl $789, v3(%rip)
+.LBB3:
+ .loc 1 37 0
+ movl $0, -4(%rbp)
+ jmp .L2
+.L3:
+ .loc 1 38 0
+ movl -4(%rbp), %eax
+ cltq
+ movzbl v4(%rax), %edx
+ movl -4(%rbp), %eax
+ cltq
+ movb %dl, v5(%rax)
+ .loc 1 37 0 discriminator 2
+ addl $1, -4(%rbp)
+.L2:
+ .loc 1 37 0 is_stmt 0 discriminator 1
+ cmpl $12, -4(%rbp)
+ setle %al
+ testb %al, %al
+ jne .L3
+.LBE3:
+ .loc 1 40 0 is_stmt 1
+ leaq -16(%rbp), %rax
+ movq %rax, %rdi
+.LEHB0:
+ call _ZN2C19testcase1Ev
+ .loc 1 40 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L4
+ .loc 1 40 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $40, %edx
+ movl $.LC0, %esi
+ movl $.LC1, %edi
+ call __assert_fail
+.L4:
+ .loc 1 41 0 is_stmt 1
+ leaq -16(%rbp), %rax
+ movq %rax, %rdi
+ call _ZN2C13t1aEv
+ .loc 1 41 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L5
+ .loc 1 41 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $41, %edx
+ movl $.LC0, %esi
+ movl $.LC2, %edi
+ call __assert_fail
+.L5:
+ .loc 1 42 0 is_stmt 1
+ leaq -16(%rbp), %rax
+ movq %rax, %rdi
+ call _ZN2C19testcase2Ev
+ .loc 1 42 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L6
+ .loc 1 42 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $42, %edx
+ movl $.LC0, %esi
+ movl $.LC3, %edi
+ call __assert_fail
+.L6:
+ .loc 1 43 0 is_stmt 1
+ leaq -16(%rbp), %rax
+ movq %rax, %rdi
+ call _ZN2C19testcase3Ev
+ .loc 1 43 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L7
+ .loc 1 43 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $43, %edx
+ movl $.LC0, %esi
+ movl $.LC4, %edi
+ call __assert_fail
+.L7:
+ .loc 1 44 0 is_stmt 1
+ leaq -16(%rbp), %rax
+ movq %rax, %rdi
+ call _ZN2C19testcase4Ev
+ .loc 1 44 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L8
+ .loc 1 44 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $44, %edx
+ movl $.LC0, %esi
+ movl $.LC5, %edi
+ call __assert_fail
+.L8:
+ .loc 1 45 0 is_stmt 1
+ leaq -32(%rbp), %rax
+ movq %rax, %rdi
+ call _ZN2C29testcase1Ev
+ .loc 1 45 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L9
+ .loc 1 45 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $45, %edx
+ movl $.LC0, %esi
+ movl $.LC6, %edi
+ call __assert_fail
+.L9:
+ .loc 1 46 0 is_stmt 1
+ leaq -32(%rbp), %rax
+ movq %rax, %rdi
+ call _ZN2C29testcase2Ev
+ .loc 1 46 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L10
+ .loc 1 46 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $46, %edx
+ movl $.LC0, %esi
+ movl $.LC7, %edi
+ call __assert_fail
+.L10:
+ .loc 1 47 0 is_stmt 1
+ leaq -32(%rbp), %rax
+ movq %rax, %rdi
+ call _ZN2C29testcase3Ev
+ .loc 1 47 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L11
+ .loc 1 47 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $47, %edx
+ movl $.LC0, %esi
+ movl $.LC8, %edi
+ call __assert_fail
+.L11:
+ .loc 1 48 0 is_stmt 1
+ leaq -32(%rbp), %rax
+ movq %rax, %rdi
+ call _ZN2C29testcase4Ev
+ .loc 1 48 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L12
+ .loc 1 48 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $48, %edx
+ movl $.LC0, %esi
+ movl $.LC9, %edi
+ call __assert_fail
+.L12:
+ .loc 1 49 0 is_stmt 1
+ movl $c3, %edi
+ call _ZN2C39testcase1Ev
+ .loc 1 49 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L13
+ .loc 1 49 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $49, %edx
+ movl $.LC0, %esi
+ movl $.LC10, %edi
+ call __assert_fail
+.L13:
+ .loc 1 50 0 is_stmt 1
+ movl $c3, %edi
+ call _ZN2C39testcase2Ev
+ .loc 1 50 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L14
+ .loc 1 50 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $50, %edx
+ movl $.LC0, %esi
+ movl $.LC11, %edi
+ call __assert_fail
+.L14:
+ .loc 1 51 0 is_stmt 1
+ movl $c3, %edi
+ call _ZN2C39testcase3Ev
+ .loc 1 51 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L15
+ .loc 1 51 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $51, %edx
+ movl $.LC0, %esi
+ movl $.LC12, %edi
+ call __assert_fail
+.L15:
+ .loc 1 52 0 is_stmt 1
+ call _Z3t12v
+ .loc 1 52 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L16
+ .loc 1 52 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $52, %edx
+ movl $.LC0, %esi
+ movl $.LC13, %edi
+ call __assert_fail
+.L16:
+ .loc 1 53 0 is_stmt 1
+ call _Z3t13v
+ .loc 1 53 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L17
+ .loc 1 53 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $53, %edx
+ movl $.LC0, %esi
+ movl $.LC14, %edi
+ call __assert_fail
+.L17:
+ .loc 1 54 0 is_stmt 1
+ call _Z3t16v
+ .loc 1 54 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L18
+ .loc 1 54 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $54, %edx
+ movl $.LC0, %esi
+ movl $.LC15, %edi
+ call __assert_fail
+.L18:
+ .loc 1 55 0 is_stmt 1
+ call _Z4t16av
+ .loc 1 55 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L19
+ .loc 1 55 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $55, %edx
+ movl $.LC0, %esi
+ movl $.LC16, %edi
+ call __assert_fail
+.L19:
+ .loc 1 56 0 is_stmt 1
+ call _Z3t17v
+ .loc 1 56 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L20
+ .loc 1 56 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $56, %edx
+ movl $.LC0, %esi
+ movl $.LC17, %edi
+ call __assert_fail
+.L20:
+ .loc 1 57 0 is_stmt 1
+ call _Z3t18v
+.LEHE0:
+ .loc 1 57 0 is_stmt 0 discriminator 1
+ testb %al, %al
+ jne .L21
+ .loc 1 57 0 discriminator 2
+ movl $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
+ movl $57, %edx
+ movl $.LC0, %esi
+ movl $.LC18, %edi
+ call __assert_fail
+.L21:
+ .loc 1 58 0 is_stmt 1
+ movl $0, %eax
+ jmp .L25
+.L24:
+ movq %rax, %rdi
+.LEHB1:
+ call _Unwind_Resume
+.LEHE1:
+.L25:
+.LBE2:
+ .loc 1 59 0
+ leave
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE1:
+ .globl __gxx_personality_v0
+ .section .gcc_except_table,"a",@progbits
+.LLSDA1:
+ .byte 0xff
+ .byte 0xff
+ .byte 0x1
+ .uleb128 .LLSDACSE1-.LLSDACSB1
+.LLSDACSB1:
+ .uleb128 .LEHB0-.LFB1
+ .uleb128 .LEHE0-.LEHB0
+ .uleb128 .L24-.LFB1
+ .uleb128 0
+ .uleb128 .LEHB1-.LFB1
+ .uleb128 .LEHE1-.LEHB1
+ .uleb128 0
+ .uleb128 0
+.LLSDACSE1:
+ .text
+ .size main, .-main
+ .section .rodata
+ .type _ZZ4mainE19__PRETTY_FUNCTION__, @object
+ .size _ZZ4mainE19__PRETTY_FUNCTION__, 11
+_ZZ4mainE19__PRETTY_FUNCTION__:
+ .string "int main()"
+ .text
+.Letext0:
+ .file 2 "dwp_test.h"
+ .section .debug_types.dwo,"G",@progbits,wt.bb2916f0c1bd34b5,comdat
+ .long 0xf7
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .long 0x25
+ .uleb128 0x1
+ .byte 0x4
+ .byte 0x8a
+ .byte 0xda
+ .byte 0x59
+ .byte 0x6e
+ .byte 0x4d
+ .byte 0x5c
+ .byte 0xa
+ .byte 0x88
+ .long .Lskeleton_debug_line0
+ .uleb128 0x2
+ .string "C3"
+ .byte 0x4
+ .byte 0x2
+ .byte 0x2f
+ .long 0xda
+ .uleb128 0x3
+ .uleb128 0x3
+ .byte 0x2
+ .byte 0x36
+ .long 0xda
+ .byte 0
+ .byte 0x1
+ .uleb128 0x4
+ .uleb128 0
+ .byte 0x2
+ .byte 0x32
+ .string "_ZN2C39testcase1Ev"
+ .long 0xe1
+ .byte 0x1
+ .long 0x5e
+ .long 0x64
+ .uleb128 0x5
+ .long 0xe9
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x1
+ .byte 0x2
+ .byte 0x33
+ .string "_ZN2C39testcase2Ev"
+ .long 0xe1
+ .byte 0x1
+ .long 0x88
+ .long 0x8e
+ .uleb128 0x5
+ .long 0xe9
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x2
+ .byte 0x2
+ .byte 0x34
+ .string "_ZN2C39testcase3Ev"
+ .long 0xe1
+ .byte 0x1
+ .long 0xb2
+ .long 0xb8
+ .uleb128 0x5
+ .long 0xe9
+ .byte 0
+ .uleb128 0x6
+ .string "f4"
+ .byte 0x2
+ .byte 0x35
+ .string "_ZN2C32f4Ev"
+ .long 0xef
+ .byte 0x1
+ .long 0xd3
+ .uleb128 0x5
+ .long 0xe9
+ .byte 0
+ .byte 0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x2
+ .string "bool"
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x25
+ .uleb128 0x8
+ .byte 0x8
+ .long 0xf5
+ .uleb128 0x9
+ .long 0xe1
+ .byte 0
+ .section .debug_types,"G",@progbits,wt.bb2916f0c1bd34b5,comdat
+ .long 0x71
+ .value 0x4
+ .long .Lskeleton_debug_abbrev0
+ .byte 0x8
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .long 0
+ .uleb128 0x2
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .string "dwp_test_main.dwo"
+ .long .Ldebug_pubnames0
+ .long .Ldebug_pubtypes0
+ .long .Ldebug_addr0
+ .section .debug_types.dwo,"G",@progbits,wt.66526f88bcc798ab,comdat
+ .long 0xf1
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .byte 0x66
+ .byte 0x52
+ .byte 0x6f
+ .byte 0x88
+ .byte 0xbc
+ .byte 0xc7
+ .byte 0x98
+ .byte 0xab
+ .long 0x25
+ .uleb128 0x1
+ .byte 0x4
+ .byte 0x4b
+ .byte 0xf9
+ .byte 0xce
+ .byte 0xbf
+ .byte 0xd8
+ .byte 0xf0
+ .byte 0x4a
+ .byte 0xae
+ .long .Lskeleton_debug_line0
+ .uleb128 0x2
+ .string "C2"
+ .byte 0x4
+ .byte 0x2
+ .byte 0x25
+ .long 0xdf
+ .uleb128 0x3
+ .uleb128 0x3
+ .byte 0x2
+ .byte 0x2c
+ .long 0xdf
+ .byte 0
+ .byte 0x1
+ .uleb128 0x4
+ .uleb128 0
+ .byte 0x2
+ .byte 0x28
+ .string "_ZN2C29testcase1Ev"
+ .long 0xe6
+ .byte 0x1
+ .long 0x5e
+ .long 0x64
+ .uleb128 0x5
+ .long 0xee
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x1
+ .byte 0x2
+ .byte 0x29
+ .string "_ZN2C29testcase2Ev"
+ .long 0xe6
+ .byte 0x1
+ .long 0x88
+ .long 0x8e
+ .uleb128 0x5
+ .long 0xee
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x2
+ .byte 0x2
+ .byte 0x2a
+ .string "_ZN2C29testcase3Ev"
+ .long 0xe6
+ .byte 0x1
+ .long 0xb2
+ .long 0xb8
+ .uleb128 0x5
+ .long 0xee
+ .byte 0
+ .uleb128 0xa
+ .uleb128 0x4
+ .byte 0x2
+ .byte 0x2b
+ .string "_ZN2C29testcase4Ev"
+ .long 0xe6
+ .byte 0x1
+ .long 0xd8
+ .uleb128 0x5
+ .long 0xee
+ .byte 0
+ .byte 0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x2
+ .string "bool"
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x25
+ .byte 0
+ .section .debug_types,"G",@progbits,wt.66526f88bcc798ab,comdat
+ .long 0x71
+ .value 0x4
+ .long .Lskeleton_debug_abbrev0
+ .byte 0x8
+ .byte 0x66
+ .byte 0x52
+ .byte 0x6f
+ .byte 0x88
+ .byte 0xbc
+ .byte 0xc7
+ .byte 0x98
+ .byte 0xab
+ .long 0
+ .uleb128 0x2
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .string "dwp_test_main.dwo"
+ .long .Ldebug_pubnames0
+ .long .Ldebug_pubtypes0
+ .long .Ldebug_addr0
+ .section .debug_types.dwo,"G",@progbits,wt.c419a9b7a4a2fab5,comdat
+ .long 0x141
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .byte 0xc4
+ .byte 0x19
+ .byte 0xa9
+ .byte 0xb7
+ .byte 0xa4
+ .byte 0xa2
+ .byte 0xfa
+ .byte 0xb5
+ .long 0x25
+ .uleb128 0x1
+ .byte 0x4
+ .byte 0xe3
+ .byte 0xad
+ .byte 0x5
+ .byte 0x3b
+ .byte 0x75
+ .byte 0xeb
+ .byte 0xfb
+ .byte 0xc7
+ .long .Lskeleton_debug_line0
+ .uleb128 0x2
+ .string "C1"
+ .byte 0x4
+ .byte 0x2
+ .byte 0x19
+ .long 0x12f
+ .uleb128 0x3
+ .uleb128 0x3
+ .byte 0x2
+ .byte 0x22
+ .long 0x12f
+ .byte 0
+ .byte 0x1
+ .uleb128 0x4
+ .uleb128 0
+ .byte 0x2
+ .byte 0x1c
+ .string "_ZN2C19testcase1Ev"
+ .long 0x136
+ .byte 0x1
+ .long 0x5e
+ .long 0x64
+ .uleb128 0x5
+ .long 0x13e
+ .byte 0
+ .uleb128 0xb
+ .string "t1a"
+ .byte 0x2
+ .byte 0x1d
+ .string "_ZN2C13t1aEv"
+ .long 0x136
+ .byte 0x1
+ .long 0x85
+ .long 0x8b
+ .uleb128 0x5
+ .long 0x13e
+ .byte 0
+ .uleb128 0xb
+ .string "t1_2"
+ .byte 0x2
+ .byte 0x1e
+ .string "_ZN2C14t1_2Ev"
+ .long 0x12f
+ .byte 0x1
+ .long 0xae
+ .long 0xb4
+ .uleb128 0x5
+ .long 0x13e
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x1
+ .byte 0x2
+ .byte 0x1f
+ .string "_ZN2C19testcase2Ev"
+ .long 0x136
+ .byte 0x1
+ .long 0xd8
+ .long 0xde
+ .uleb128 0x5
+ .long 0x13e
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x2
+ .byte 0x2
+ .byte 0x20
+ .string "_ZN2C19testcase3Ev"
+ .long 0x136
+ .byte 0x1
+ .long 0x102
+ .long 0x108
+ .uleb128 0x5
+ .long 0x13e
+ .byte 0
+ .uleb128 0xa
+ .uleb128 0x4
+ .byte 0x2
+ .byte 0x21
+ .string "_ZN2C19testcase4Ev"
+ .long 0x136
+ .byte 0x1
+ .long 0x128
+ .uleb128 0x5
+ .long 0x13e
+ .byte 0
+ .byte 0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x2
+ .string "bool"
+ .uleb128 0x8
+ .byte 0x8
+ .long 0x25
+ .byte 0
+ .section .debug_types,"G",@progbits,wt.c419a9b7a4a2fab5,comdat
+ .long 0x71
+ .value 0x4
+ .long .Lskeleton_debug_abbrev0
+ .byte 0x8
+ .byte 0xc4
+ .byte 0x19
+ .byte 0xa9
+ .byte 0xb7
+ .byte 0xa4
+ .byte 0xa2
+ .byte 0xfa
+ .byte 0xb5
+ .long 0
+ .uleb128 0x2
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .string "dwp_test_main.dwo"
+ .long .Ldebug_pubnames0
+ .long .Ldebug_pubtypes0
+ .long .Ldebug_addr0
+ .section .debug_info.dwo,"e",@progbits
+.Ldebug_info0:
+ .long 0x178
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .uleb128 0xc
+ .string "GNU C++ 4.7.x-google 20120720 (prerelease)"
+ .byte 0x4
+ .string "dwp_test_main.cc"
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .byte 0xc8
+ .byte 0xeb
+ .byte 0x9a
+ .byte 0x5c
+ .byte 0xd9
+ .byte 0x51
+ .byte 0xba
+ .byte 0xe5
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x2
+ .string "bool"
+ .uleb128 0xd
+ .string "main"
+ .byte 0x1
+ .byte 0x1e
+ .long 0x90
+ .uleb128 0
+ .quad .LFE1-.LFB1
+ .uleb128 0x1
+ .byte 0x9c
+ .long 0x11b
+ .uleb128 0xe
+ .uleb128 0x1
+ .quad .LBE2-.LBB2
+ .uleb128 0xf
+ .string "c1"
+ .byte 0x1
+ .byte 0x20
+ .byte 0xc4
+ .byte 0x19
+ .byte 0xa9
+ .byte 0xb7
+ .byte 0xa4
+ .byte 0xa2
+ .byte 0xfa
+ .byte 0xb5
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -32
+ .uleb128 0xf
+ .string "c2"
+ .byte 0x1
+ .byte 0x21
+ .byte 0x66
+ .byte 0x52
+ .byte 0x6f
+ .byte 0x88
+ .byte 0xbc
+ .byte 0xc7
+ .byte 0x98
+ .byte 0xab
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -48
+ .uleb128 0x10
+ .string "__PRETTY_FUNCTION__"
+ .long 0x13f
+ .uleb128 0x2
+ .byte 0xfb
+ .uleb128 0x2
+ .uleb128 0xe
+ .uleb128 0x3
+ .quad .LBE3-.LBB3
+ .uleb128 0x11
+ .string "i"
+ .byte 0x1
+ .byte 0x25
+ .long 0x90
+ .uleb128 0x2
+ .byte 0x91
+ .sleb128 -20
+ .byte 0
+ .byte 0
+ .byte 0
+ .uleb128 0x12
+ .long 0x137
+ .long 0x12b
+ .uleb128 0x13
+ .long 0x12b
+ .byte 0xa
+ .byte 0
+ .uleb128 0x7
+ .byte 0x8
+ .byte 0x7
+ .string "sizetype"
+ .uleb128 0x7
+ .byte 0x1
+ .byte 0x6
+ .string "char"
+ .uleb128 0x14
+ .long 0x11b
+ .uleb128 0x15
+ .string "c3"
+ .byte 0x2
+ .byte 0x39
+ .byte 0xbb
+ .byte 0x29
+ .byte 0x16
+ .byte 0xf0
+ .byte 0xc1
+ .byte 0xbd
+ .byte 0x34
+ .byte 0xb5
+ .uleb128 0x16
+ .string "v3"
+ .byte 0x2
+ .byte 0x3c
+ .long 0x90
+ .uleb128 0x12
+ .long 0x137
+ .long 0x167
+ .uleb128 0x17
+ .byte 0
+ .uleb128 0x16
+ .string "v4"
+ .byte 0x2
+ .byte 0x3d
+ .long 0x15c
+ .uleb128 0x16
+ .string "v5"
+ .byte 0x2
+ .byte 0x3e
+ .long 0x15c
+ .byte 0
+ .section .debug_info,"",@progbits
+.Lskeleton_debug_info0:
+ .long 0x81
+ .value 0x4
+ .long .Lskeleton_debug_abbrev0
+ .byte 0x8
+ .uleb128 0x1
+ .quad .Ltext0
+ .quad .Letext0-.Ltext0
+ .long .Ldebug_line0
+ .byte 0xc8
+ .byte 0xeb
+ .byte 0x9a
+ .byte 0x5c
+ .byte 0xd9
+ .byte 0x51
+ .byte 0xba
+ .byte 0xe5
+ .string "/home/ccoutant/opensource/binutils-git/binutils/gold/testsuite"
+ .string "dwp_test_main.dwo"
+ .long .Ldebug_pubnames0
+ .long .Ldebug_pubtypes0
+ .long .Ldebug_addr0
+ .section .debug_abbrev,"",@progbits
+.Lskeleton_debug_abbrev0:
+ .uleb128 0x1
+ .uleb128 0x11
+ .byte 0
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x10
+ .uleb128 0x17
+ .uleb128 0x2131
+ .uleb128 0x7
+ .uleb128 0x1b
+ .uleb128 0x8
+ .uleb128 0x2130
+ .uleb128 0x8
+ .uleb128 0x2134
+ .uleb128 0x17
+ .uleb128 0x2135
+ .uleb128 0x17
+ .uleb128 0x2133
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+ .uleb128 0x2
+ .uleb128 0x41
+ .byte 0
+ .uleb128 0x1b
+ .uleb128 0x8
+ .uleb128 0x2130
+ .uleb128 0x8
+ .uleb128 0x2134
+ .uleb128 0x17
+ .uleb128 0x2135
+ .uleb128 0x17
+ .uleb128 0x2133
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+ .byte 0
+ .section .debug_abbrev.dwo,"e",@progbits
+.Ldebug_abbrev0:
+ .uleb128 0x1
+ .uleb128 0x41
+ .byte 0x1
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x210f
+ .uleb128 0x7
+ .uleb128 0x10
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+ .uleb128 0x2
+ .uleb128 0x2
+ .byte 0x1
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0xd
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x1f02
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x38
+ .uleb128 0xb
+ .uleb128 0x32
+ .uleb128 0xb
+ .byte 0
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x1f02
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x5
+ .uleb128 0x5
+ .byte 0
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x34
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x6
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x7
+ .uleb128 0x24
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .byte 0
+ .byte 0
+ .uleb128 0x8
+ .uleb128 0xf
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x9
+ .uleb128 0x15
+ .byte 0
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0xa
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x1f02
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x6e
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x32
+ .uleb128 0xb
+ .uleb128 0x3c
+ .uleb128 0x19
+ .uleb128 0x64
+ .uleb128 0x13
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0xc
+ .uleb128 0x11
+ .byte 0x1
+ .uleb128 0x25
+ .uleb128 0x8
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x1b
+ .uleb128 0x8
+ .uleb128 0x2131
+ .uleb128 0x7
+ .byte 0
+ .byte 0
+ .uleb128 0xd
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x2116
+ .uleb128 0x19
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0xe
+ .uleb128 0xb
+ .byte 0x1
+ .uleb128 0x11
+ .uleb128 0x1f01
+ .uleb128 0x12
+ .uleb128 0x7
+ .byte 0
+ .byte 0
+ .uleb128 0xf
+ .uleb128 0x34
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x20
+ .uleb128 0x2
+ .uleb128 0x18
+ .byte 0
+ .byte 0
+ .uleb128 0x10
+ .uleb128 0x34
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x34
+ .uleb128 0x19
+ .uleb128 0x2
+ .uleb128 0x18
+ .byte 0
+ .byte 0
+ .uleb128 0x11
+ .uleb128 0x34
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0x18
+ .byte 0
+ .byte 0
+ .uleb128 0x12
+ .uleb128 0x1
+ .byte 0x1
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x13
+ .uleb128 0x21
+ .byte 0
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2f
+ .uleb128 0xb
+ .byte 0
+ .byte 0
+ .uleb128 0x14
+ .uleb128 0x26
+ .byte 0
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0
+ .byte 0
+ .uleb128 0x15
+ .uleb128 0x34
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x20
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3c
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x16
+ .uleb128 0x34
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3c
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x17
+ .uleb128 0x21
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 0
+ .section .debug_gnu_pubnames,"",@progbits
+.Ldebug_pubnames0:
+ .long 0x18
+ .value 0x2
+ .long .Lskeleton_debug_info0
+ .long 0x17c
+ .long 0x9f
+ .byte 0x30
+ .string "main"
+ .long 0
+ .section .debug_gnu_pubtypes,"",@progbits
+.Ldebug_pubtypes0:
+ .long 0x51
+ .value 0x2
+ .long .Lskeleton_debug_info0
+ .long 0x17c
+ .long 0x90
+ .byte 0x90
+ .string "int"
+ .long 0x97
+ .byte 0x90
+ .string "bool"
+ .long 0
+ .byte 0x10
+ .string "C1"
+ .long 0
+ .byte 0x10
+ .string "C2"
+ .long 0
+ .byte 0x10
+ .string "C3"
+ .long 0x12b
+ .byte 0x90
+ .string "sizetype"
+ .long 0x137
+ .byte 0x90
+ .string "char"
+ .long 0
+ .section .debug_aranges,"",@progbits
+ .long 0x2c
+ .value 0x2
+ .long .Lskeleton_debug_info0
+ .byte 0x8
+ .byte 0
+ .value 0
+ .value 0
+ .quad .Ltext0
+ .quad .Letext0-.Ltext0
+ .quad 0
+ .quad 0
+ .section .debug_line,"",@progbits
+.Ldebug_line0:
+ .section .debug_line.dwo,"e",@progbits
+.Lskeleton_debug_line0:
+ .long .LELT0-.LSLT0
+.LSLT0:
+ .value 0x4
+ .long .LELTP0-.LASLTP0
+.LASLTP0:
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .byte 0xf6
+ .byte 0xf2
+ .byte 0xd
+ .byte 0
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 0x1
+ .byte 0
+ .byte 0
+ .byte 0x1
+ .byte 0
+ .string "dwp_test_main.cc"
+ .uleb128 0
+ .uleb128 0
+ .uleb128 0
+ .string "dwp_test.h"
+ .uleb128 0
+ .uleb128 0
+ .uleb128 0
+ .byte 0
+.LELTP0:
+.LELT0:
+ .section .debug_str_offsets.dwo,"e",@progbits
+ .long 0
+ .long 0xa
+ .long 0x14
+ .long 0x1e
+ .long 0x26
+ .section .debug_str.dwo,"e",@progbits
+.LASF0:
+ .string "testcase1"
+.LASF1:
+ .string "testcase2"
+.LASF2:
+ .string "testcase3"
+.LASF3:
+ .string "member1"
+.LASF4:
+ .string "testcase4"
+ .section .debug_addr,"",@progbits
+.Ldebug_addr0:
+ .quad .LFB1
+ .quad .LBB2
+ .quad _ZZ4mainE19__PRETTY_FUNCTION__
+ .quad .LBB3
+ .ident "GCC: (Google_crosstoolv16-gcc-4.7.x-grtev3) 4.7.x-google 20120720 (prerelease)"
+ .section .note.GNU-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/dyn_weak_ref.sh b/binutils-2.25/gold/testsuite/dyn_weak_ref.sh
new file mode 100755
index 00000000..b52efaca
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dyn_weak_ref.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# dyn_weak_ref.sh -- test weak reference remains weak in output even if
+# gold sees a dynamic weak reference before a static one.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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 checks that the reference to 'weak_ref' have WEAK binding.
+
+check()
+{
+ file=$1
+ pattern=$2
+ found=`grep "$pattern" $file`
+ if test -z "$found"; then
+ echo "pattern \"$pattern\" not found in file $file."
+ echo $found
+ exit 1
+ fi
+}
+
+check dyn_weak_ref.stdout ".* WEAK .* UND.* weak_ref"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/dyn_weak_ref_1.c b/binutils-2.25/gold/testsuite/dyn_weak_ref_1.c
new file mode 100644
index 00000000..fdd78dd4
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dyn_weak_ref_1.c
@@ -0,0 +1,39 @@
+// dyn_weak_ref_1.c -- test that a weak ref remains weak in output when
+// there is a DSO with the same weak ref.
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Doug Kwan <dougkwan@google.com>.
+
+// 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 test that we correctly deal with a weak reference to from both
+// a DSO and a weak reference to the same symbol in an executable. The
+// symbol should remains weak.
+
+// This source is used to build an DSO that references the same weak
+// symbol as in a dependent DSO.
+
+extern void weak_ref (void) __attribute__((weak));
+
+void* ptr1 = weak_ref;
+
+int
+main (void)
+{
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/dyn_weak_ref_2.c b/binutils-2.25/gold/testsuite/dyn_weak_ref_2.c
new file mode 100644
index 00000000..8a087a15
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dyn_weak_ref_2.c
@@ -0,0 +1,32 @@
+// dyn_weak_ref_1.c -- test that a weak ref remains weak in output when
+// there is a DSO with the same weak ref.
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Doug Kwan <dougkwan@google.com>.
+
+// 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 test that we correctly deal with a weak reference to from both
+// a DSO and a weak reference to the same symbol in an executable. The
+// symbol should remains weak.
+
+// This source is used to build a DSO that contains a weak reference.
+
+extern void weak_ref (void) __attribute__((weak));
+
+void* ptr2 = weak_ref;
diff --git a/binutils-2.25/gold/testsuite/dynamic_list.sh b/binutils-2.25/gold/testsuite/dynamic_list.sh
new file mode 100755
index 00000000..dfd9f0fe
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dynamic_list.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+# dynamic_list.sh -- test --dynamic-list and --dynamic-list-*
+
+# Copyright 2008 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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 goes with dynamic_list.t, which is a dynamic-list script.
+
+check()
+{
+ if ! grep -qw "$2" "$1"
+ then
+ echo "Did not find expected text in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check dynamic_list.stdout "main" # comes via --dynamic-list
+check dynamic_list.stdout "_ZdlPv" # "operator delete(void*)"
+check dynamic_list.stdout "_Z4t1_6v" # t1_6()
+check dynamic_list.stdout "_ZN4t16aC2Ev" # t16a:t16a()
+check dynamic_list.stdout "_ZN4t16aD1Ev" # t16a:~t16a()
+check dynamic_list.stdout "_ZN4t16a1tEv" # t16a:t()
+check dynamic_list.stdout "_ZTI4t16a" # typeinfo for t16a
+check dynamic_list.stdout "_ZTI4t16b" # typeinfo for t16b
+check dynamic_list.stdout "_ZTS4t16a" # typeinfo name for t16a
+check dynamic_list.stdout "_ZTS4t16b" # typeinfo name for t16b
+check dynamic_list.stdout "t20v" # comes via --dynamic-list-data
diff --git a/binutils-2.25/gold/testsuite/dynamic_list.t b/binutils-2.25/gold/testsuite/dynamic_list.t
new file mode 100644
index 00000000..64571737
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/dynamic_list.t
@@ -0,0 +1,11 @@
+{
+ main;
+ not_a_symbol;
+ global;
+ extern "C++" { t1_6* };
+};
+{
+ extern "C++" { t16a* };
+ local;
+ extern;
+};
diff --git a/binutils-2.25/gold/testsuite/exception_test.h b/binutils-2.25/gold/testsuite/exception_test.h
new file mode 100644
index 00000000..0dcd8f2c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/exception_test.h
@@ -0,0 +1,27 @@
+// exception_test.h -- exception test case for gold, header file -*- C++ -*-
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 tests references between files. This is the shared header
+// file. See exception_test_1.cc for details.
+
+extern bool t1();
+extern void f1();
diff --git a/binutils-2.25/gold/testsuite/exception_test_1.cc b/binutils-2.25/gold/testsuite/exception_test_1.cc
new file mode 100644
index 00000000..56ae1434
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/exception_test_1.cc
@@ -0,0 +1,52 @@
+// exception_test_1.cc -- test exception handling for gold, file 1 of 2
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 tests throwing an exception across various boundaries. This
+// is a general test of the exception frame handling, and the
+// interaction with the compiler support libraries. This is file 1,
+// which catches the exception. We test in several different ways:
+
+// Files 1 and 2 linked together in executable.
+// File 1 in executable, file 2 in shared library.
+// File 1 in shared library, file 2 in executable.
+// Files 1 and 2 linked together in shared library.
+// Files 1 and 2 in different shared libraries.
+
+#include "exception_test.h"
+
+bool
+t1()
+{
+ int i;
+ try
+ {
+ i = 0;
+ f1();
+ i = 1;
+ }
+ catch (...)
+ {
+ return i == 0;
+ }
+
+ return false;
+}
diff --git a/binutils-2.25/gold/testsuite/exception_test_2.cc b/binutils-2.25/gold/testsuite/exception_test_2.cc
new file mode 100644
index 00000000..1098bd18
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/exception_test_2.cc
@@ -0,0 +1,31 @@
+// exception_test_1.cc -- test exception handling for gold, file 1 of 2
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+// Second part of exception test. See exception_test_1.cc for details.
+
+#include "exception_test.h"
+
+void
+f1()
+{
+ throw 0;
+}
diff --git a/binutils-2.25/gold/testsuite/exception_test_main.cc b/binutils-2.25/gold/testsuite/exception_test_main.cc
new file mode 100644
index 00000000..09a018d1
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/exception_test_main.cc
@@ -0,0 +1,35 @@
+// exception_test_main.cc -- an exception test case for gold, main function
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 tests references between files. This is the main file. See
+// two_file_test_1.cc for details.
+
+#include <cassert>
+
+#include "exception_test.h"
+
+int
+main()
+{
+ assert(t1());
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/exclude_libs_test.c b/binutils-2.25/gold/testsuite/exclude_libs_test.c
new file mode 100644
index 00000000..85441a0c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/exclude_libs_test.c
@@ -0,0 +1,14 @@
+extern void lib1_default (void);
+extern void lib2_default (void);
+extern void lib3_default (void);
+
+int
+main (int argc __attribute__ ((unused)),
+ char** argv __attribute__ ((unused)))
+{
+ lib1_default ();
+ lib2_default ();
+ lib3_default ();
+ return 0;
+}
+
diff --git a/binutils-2.25/gold/testsuite/exclude_libs_test.sh b/binutils-2.25/gold/testsuite/exclude_libs_test.sh
new file mode 100755
index 00000000..65ce03b2
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/exclude_libs_test.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+# exclude_libs_test.sh -- test that library symbols are not exported.
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>
+
+# 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 goes with exclude_libs_test.c, a C source file
+# linked with option -Wl,--exclude-libs. We run readelf on
+# the resulting executable and check that symbols from two test library
+# archives are correctly hidden or left unmodified.
+
+check()
+{
+ file=$1
+ sym=$2
+ vis=$3
+
+ found=`grep " $sym\$" $file`
+ if test -z "$found"; then
+ echo "Symbol $sym not found."
+ exit 1
+ fi
+
+ match_vis=`grep " $sym\$" $file | grep " $vis "`
+ if test -z "$match_vis"; then
+ echo "Expected symbol $sym to have visibility $vis but found"
+ echo "$found"
+ exit 1
+ fi
+}
+
+check "exclude_libs_test.syms" "lib1_default" "HIDDEN"
+check "exclude_libs_test.syms" "lib1_protected" "HIDDEN"
+check "exclude_libs_test.syms" "lib1_internal" "INTERNAL"
+check "exclude_libs_test.syms" "lib1_hidden" "HIDDEN"
+check "exclude_libs_test.syms" "lib2_default" "DEFAULT"
+check "exclude_libs_test.syms" "lib2_protected" "PROTECTED"
+check "exclude_libs_test.syms" "lib2_internal" "INTERNAL"
+check "exclude_libs_test.syms" "lib2_hidden" "HIDDEN"
+check "exclude_libs_test.syms" "lib3_default" "HIDDEN"
+check "exclude_libs_test.syms" "lib3_protected" "HIDDEN"
+check "exclude_libs_test.syms" "lib3_internal" "INTERNAL"
+check "exclude_libs_test.syms" "lib3_hidden" "HIDDEN"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/exclude_libs_test_1.c b/binutils-2.25/gold/testsuite/exclude_libs_test_1.c
new file mode 100644
index 00000000..48b617b0
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/exclude_libs_test_1.c
@@ -0,0 +1,32 @@
+void lib1_default (void);
+void lib1_hidden (void);
+void lib1_internal (void);
+void lib1_protected (void);
+void lib1_ref (void);
+extern void lib2_default (void);
+
+void __attribute__((visibility ("default")))
+lib1_default (void)
+{
+}
+
+void __attribute__((visibility ("hidden")))
+lib1_hidden (void)
+{
+}
+
+void __attribute__((visibility ("internal")))
+lib1_internal (void)
+{
+}
+
+void __attribute__((visibility ("protected")))
+lib1_protected (void)
+{
+}
+
+void
+lib1_ref (void)
+{
+ lib2_default ();
+}
diff --git a/binutils-2.25/gold/testsuite/exclude_libs_test_2.c b/binutils-2.25/gold/testsuite/exclude_libs_test_2.c
new file mode 100644
index 00000000..a8952e7a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/exclude_libs_test_2.c
@@ -0,0 +1,24 @@
+void lib2_default (void);
+void lib2_hidden (void);
+void lib2_internal (void);
+void lib2_protected (void);
+
+void __attribute__((visibility ("default")))
+lib2_default (void)
+{
+}
+
+void __attribute__((visibility ("hidden")))
+lib2_hidden (void)
+{
+}
+
+void __attribute__((visibility ("internal")))
+lib2_internal (void)
+{
+}
+
+void __attribute__((visibility ("protected")))
+lib2_protected (void)
+{
+}
diff --git a/binutils-2.25/gold/testsuite/exclude_libs_test_3.c b/binutils-2.25/gold/testsuite/exclude_libs_test_3.c
new file mode 100644
index 00000000..b4e26353
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/exclude_libs_test_3.c
@@ -0,0 +1,24 @@
+void lib3_default (void);
+void lib3_hidden (void);
+void lib3_internal (void);
+void lib3_protected (void);
+
+void __attribute__((visibility ("default")))
+lib3_default (void)
+{
+}
+
+void __attribute__((visibility ("hidden")))
+lib3_hidden (void)
+{
+}
+
+void __attribute__((visibility ("internal")))
+lib3_internal (void)
+{
+}
+
+void __attribute__((visibility ("protected")))
+lib3_protected (void)
+{
+}
diff --git a/binutils-2.25/gold/testsuite/final_layout.cc b/binutils-2.25/gold/testsuite/final_layout.cc
new file mode 100644
index 00000000..f5338859
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/final_layout.cc
@@ -0,0 +1,48 @@
+// final_layout.cc -- a test case for gold
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify if --section-ordering-file orders
+// the .text and .data sections correctly as specified.
+
+int global_vara;
+int global_varb;
+int global_varc;
+
+int foo()
+{
+ return 1;
+}
+
+int bar()
+{
+ return 1;
+}
+
+int baz()
+{
+ return 1;
+}
+
+int main()
+{
+ return 1;
+}
diff --git a/binutils-2.25/gold/testsuite/final_layout.sh b/binutils-2.25/gold/testsuite/final_layout.sh
new file mode 100755
index 00000000..d9d86ee3
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/final_layout.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+# final_layout.sh -- test --final-layout
+
+# Copyright 2010, 2011 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# 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 goal of this program is to verify if --section-ordering-file works as
+# intended. File final_layout.cc is in this test.
+
+set -e
+
+check()
+{
+ awk "
+BEGIN { saw1 = 0; saw2 = 0; err = 0; }
+/.*$2\$/ { saw1 = 1; }
+/.*$3\$/ {
+ saw2 = 1;
+ if (!saw1)
+ {
+ printf \"layout of $2 and $3 is not right\\n\";
+ err = 1;
+ exit 1;
+ }
+ }
+END {
+ if (!saw1 && !err)
+ {
+ printf \"did not see $2\\n\";
+ exit 1;
+ }
+ if (!saw2 && !err)
+ {
+ printf \"did not see $3\\n\";
+ exit 1;
+ }
+ }" $1
+}
+
+check final_layout.stdout "_Z3barv" "_Z3bazv"
+check final_layout.stdout "_Z3bazv" "_Z3foov"
+check final_layout.stdout "global_varb" "global_vara"
+check final_layout.stdout "global_vara" "global_varc"
diff --git a/binutils-2.25/gold/testsuite/gc_comdat_test.sh b/binutils-2.25/gold/testsuite/gc_comdat_test.sh
new file mode 100755
index 00000000..baff98d0
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gc_comdat_test.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# gc_comdat_test.sh -- test --gc-sections
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# 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 goal of this program is to verify if comdat's and garbage
+# collection work together. Files gc_comdat_test_1.cc and
+# gc_comdat_test_2.cc are used in this test. This program checks
+# if the kept comdat section is garbage collected.
+
+check()
+{
+ if grep -q "$2" "$1"
+ then
+ echo "Garbage collection failed to collect :"
+ echo " $2"
+ exit 1
+ fi
+}
+
+check gc_comdat_test.stdout "foo()"
+check gc_comdat_test.stdout "bar()"
+check gc_comdat_test.stdout "int GetMax<int>(int, int)"
diff --git a/binutils-2.25/gold/testsuite/gc_comdat_test_1.cc b/binutils-2.25/gold/testsuite/gc_comdat_test_1.cc
new file mode 100644
index 00000000..0b4b286d
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gc_comdat_test_1.cc
@@ -0,0 +1,42 @@
+// gc_comdat_test_1.cc -- a test case for gold
+
+// Copyright 2009 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify if comdat's and garbage
+// collection work together. This file is compiled with -g. The
+// comdat kept function for GetMax is garbage.
+
+int foo();
+template <class T>
+T GetMax (T a, T b)
+{
+ return (a > b)?a:b;
+}
+
+int bar ()
+{
+ return GetMax <int> (4,5);
+}
+
+int main()
+{
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/gc_comdat_test_2.cc b/binutils-2.25/gold/testsuite/gc_comdat_test_2.cc
new file mode 100644
index 00000000..5841bdf0
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gc_comdat_test_2.cc
@@ -0,0 +1,35 @@
+// gc_comdat_test_2.cc -- a test case for gold
+
+// Copyright 2009 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify if comdat's and garbage
+// collection work together. This file is compiled with -g.
+
+template <class T>
+T GetMax (T a, T b)
+{
+ return (a > b)?a:b;
+}
+
+int foo ()
+{
+ return GetMax <int> (10,11);
+}
diff --git a/binutils-2.25/gold/testsuite/gc_orphan_section_test.cc b/binutils-2.25/gold/testsuite/gc_orphan_section_test.cc
new file mode 100644
index 00000000..3443f8d2
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gc_orphan_section_test.cc
@@ -0,0 +1,36 @@
+// gc_orphan_section_test.cc -- a test case for gold
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify if garbage collection does not
+// discard orphan sections when references to them through __start_XXX
+// and __stop_XXX are present. Here section _foo must not be gc'ed but
+// _boo should be gc'ed.
+
+extern const int *__start__foo;
+int foo __attribute__((__section__("_foo"))) = 1;
+int boo __attribute__((__section__("_boo"))) = 1;
+
+int main()
+{
+ return *__start__foo;
+}
+
diff --git a/binutils-2.25/gold/testsuite/gc_orphan_section_test.sh b/binutils-2.25/gold/testsuite/gc_orphan_section_test.sh
new file mode 100755
index 00000000..6ce524da
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gc_orphan_section_test.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# gc_orphan_section_test.sh -- test --gc-sections
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# 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 goal of this program is to verify if gc-sections works as expected
+# with orphan sections.
+# File gc_orphan_sections_test.cc is in this test. This program checks if
+# the orphan sections are retained when they are referenced through
+# __start_XXX and __stop_XXX symbols.
+
+check()
+{
+ if grep -q " boo" "$1"
+ then
+ echo "Garbage collection failed to collect boo"
+ exit 1
+ fi
+ grep_foo=`grep -q " foo" $1`
+ if [ $? != 0 ];
+ then
+ echo "Garbage collection should not discard foo"
+ exit 1
+ fi
+}
+
+check gc_orphan_section_test.stdout
diff --git a/binutils-2.25/gold/testsuite/gc_tls_test.cc b/binutils-2.25/gold/testsuite/gc_tls_test.cc
new file mode 100644
index 00000000..1b10d987
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gc_tls_test.cc
@@ -0,0 +1,32 @@
+// gc_tls_test.cc -- a test case for gold
+
+// Copyright 2009 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify if tls sections are garbage
+// collected with --gc-sections.
+
+__thread int number;
+
+int main()
+{
+ return 0;
+}
+
diff --git a/binutils-2.25/gold/testsuite/gc_tls_test.sh b/binutils-2.25/gold/testsuite/gc_tls_test.sh
new file mode 100755
index 00000000..c4635c99
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gc_tls_test.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# gc_tls_test.sh -- test -- gc + tls
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# 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 goal of this program is to verify if tls sections are garbage
+# collected with --gc-sections. File gc_tls_test.cc is in this test.
+
+check()
+{
+ if grep -q "$2" "$1"
+ then
+ echo "Garbage collection failed to collect tls variable:"
+ echo " $2"
+ exit 1
+ fi
+
+}
+
+check gc_tls_test.stdout "number"
diff --git a/binutils-2.25/gold/testsuite/gdb_index_test.cc b/binutils-2.25/gold/testsuite/gdb_index_test.cc
new file mode 100644
index 00000000..d5ac2f19
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gdb_index_test.cc
@@ -0,0 +1,149 @@
+// gdb_index_test.cc -- a test case for the --gdb-index option.
+
+// Copyright 2012 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 source file defines a number of symbols of different forms
+// to exercise the DWARF scanner in gold.
+
+namespace
+{
+int c1_count;
+int c2_count;
+};
+
+namespace one
+{
+
+enum G
+{
+ G_A,
+ G_B,
+ G_C
+};
+
+class c1
+{
+ public:
+ static int count;
+
+ c1()
+ { ++c1_count; }
+
+ ~c1()
+ {
+ --c1_count;
+ }
+
+ enum E
+ {
+ E_A,
+ E_B,
+ E_C,
+ };
+
+ int
+ val()
+ { return E_A; }
+};
+
+c1 c1v;
+};
+
+namespace two
+{
+const int ci = 3;
+
+template <typename T>
+class c2
+{
+ public:
+ c2(T t)
+ : t_(t)
+ {
+ ++c2_count;
+ }
+
+ ~c2()
+ { --c2_count; }
+
+ T
+ val()
+ { return this->t_; }
+
+ T t_;
+};
+
+c2<int> c2v1(1);
+c2<double> c2v2(2.0);
+c2<int const*> c2v3(&ci);
+};
+
+enum F
+{
+ F_A,
+ F_B,
+ F_C
+};
+
+template <class C>
+bool
+check(C* c)
+{ return c->val() == 0; }
+
+bool
+check_enum(int i)
+{ return i > 0; }
+
+struct anonymous_union_container {
+ union {
+ struct astruct {
+ int a;
+ };
+ int b;
+ } u;
+};
+
+anonymous_union_container anonymous_union_var;
+
+#ifdef __GNUC__
+#define ALWAYS_INLINE __attribute__((always_inline))
+#else
+#define ALWAYS_INLINE
+#endif
+
+static inline ALWAYS_INLINE int
+inline_func_1(int i)
+{ return i * 17; }
+
+int
+main()
+{
+ F f = F_A;
+ one::G g = one::G_A;
+ check_enum(f);
+ check_enum(g);
+ check(&one::c1v);
+ check(&two::c2v1);
+ check(&two::c2v2);
+ check(&two::c2v3);
+ anonymous_union_var.u.b = inline_func_1(3) - 51;
+ return anonymous_union_var.u.b;
+}
diff --git a/binutils-2.25/gold/testsuite/gdb_index_test_1.sh b/binutils-2.25/gold/testsuite/gdb_index_test_1.sh
new file mode 100755
index 00000000..f04c8a77
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gdb_index_test_1.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# gdb_index_test_1.sh -- a test case for the --gdb-index option.
+
+# Copyright 2012 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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.
+
+exec ${srcdir}/gdb_index_test_comm.sh gdb_index_test_1.stdout
diff --git a/binutils-2.25/gold/testsuite/gdb_index_test_2.sh b/binutils-2.25/gold/testsuite/gdb_index_test_2.sh
new file mode 100755
index 00000000..e31aa422
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gdb_index_test_2.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# gdb_index_test_2.sh -- a test case for the --gdb-index option.
+
+# Copyright 2012 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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.
+
+exec ${srcdir}/gdb_index_test_comm.sh gdb_index_test_2.stdout
diff --git a/binutils-2.25/gold/testsuite/gdb_index_test_3.c b/binutils-2.25/gold/testsuite/gdb_index_test_3.c
new file mode 100644
index 00000000..df492613
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gdb_index_test_3.c
@@ -0,0 +1,39 @@
+// gdb_index_test.c -- a test case for the --gdb-index option.
+
+// 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.
+
+// This source file is just a simple C source file that is mainly to
+// test the CU DW_AT_high_pc FORM encoding is handled correctly by the
+// DWARF scanner in gold.
+
+int check_int (int);
+int main (void);
+
+int j = 0;
+
+int
+check_int (int i)
+{ return i > 0; }
+
+int
+main()
+{
+ return check_int (0);
+}
diff --git a/binutils-2.25/gold/testsuite/gdb_index_test_3.sh b/binutils-2.25/gold/testsuite/gdb_index_test_3.sh
new file mode 100755
index 00000000..bd1500b8
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gdb_index_test_3.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+# gdb_index_test_3.sh -- a test case for the --gdb-index option.
+
+# Copyright 2012 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output:"
+ echo " $2"
+ echo ""
+ echo "Actual error output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+STDOUT=gdb_index_test_3.stdout
+
+check $STDOUT "^Version [45]"
+
+# Look for the symbols we know should be in the symbol table.
+
+check $STDOUT "^\[ *[0-9]*\] main:"
+check $STDOUT "^\[ *[0-9]*\] check_int:"
+check $STDOUT "^\[ *[0-9]*\] j:"
+check $STDOUT "^\[ *[0-9]*\] int:"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/gdb_index_test_4.sh b/binutils-2.25/gold/testsuite/gdb_index_test_4.sh
new file mode 100755
index 00000000..44c8a9a1
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gdb_index_test_4.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# gdb_index_test_4.sh -- a test case for the --gdb-index option.
+
+# Copyright 2012 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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.
+
+exec ${srcdir}/gdb_index_test_comm.sh gdb_index_test_4.stdout
diff --git a/binutils-2.25/gold/testsuite/gdb_index_test_comm.sh b/binutils-2.25/gold/testsuite/gdb_index_test_comm.sh
new file mode 100755
index 00000000..4ab07b3c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/gdb_index_test_comm.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+
+# gdb_index_test_comm.sh -- common code for --gdb-index tests.
+
+# Copyright 2012 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output:"
+ echo " $2"
+ echo ""
+ echo "Actual error output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+STDOUT="$1"
+
+check $STDOUT "^Version [45]"
+
+# Look for the symbols we know should be in the symbol table.
+
+check $STDOUT "^\[ *[0-9]*\] (anonymous namespace):"
+check $STDOUT "^\[ *[0-9]*\] (anonymous namespace)::c1_count:"
+check $STDOUT "^\[ *[0-9]*\] (anonymous namespace)::c2_count:"
+check $STDOUT "^\[ *[0-9]*\] bool:"
+check $STDOUT "^\[ *[0-9]*\] check<one::c1>:"
+check $STDOUT "^\[ *[0-9]*\] check<two::c2<double> >:"
+check $STDOUT "^\[ *[0-9]*\] check<two::c2<int> >:"
+# check $STDOUT "^\[ *[0-9]*\] check<two::c2<int const\*> >:"
+check $STDOUT "^\[ *[0-9]*\] double:"
+check $STDOUT "^\[ *[0-9]*\] F_A:"
+check $STDOUT "^\[ *[0-9]*\] F_B:"
+check $STDOUT "^\[ *[0-9]*\] F_C:"
+check $STDOUT "^\[ *[0-9]*\] int:"
+check $STDOUT "^\[ *[0-9]*\] main:"
+check $STDOUT "^\[ *[0-9]*\] one:"
+check $STDOUT "^\[ *[0-9]*\] one::c1:"
+check $STDOUT "^\[ *[0-9]*\] one::c1::~c1:"
+check $STDOUT "^\[ *[0-9]*\] one::c1::c1:"
+check $STDOUT "^\[ *[0-9]*\] one::c1::val:"
+check $STDOUT "^\[ *[0-9]*\] one::c1v:"
+check $STDOUT "^\[ *[0-9]*\] one::G_A:"
+check $STDOUT "^\[ *[0-9]*\] one::G_B:"
+check $STDOUT "^\[ *[0-9]*\] one::G_B:"
+check $STDOUT "^\[ *[0-9]*\] two:"
+check $STDOUT "^\[ *[0-9]*\] two::c2<double>::~c2:"
+check $STDOUT "^\[ *[0-9]*\] two::c2<double>::c2:"
+check $STDOUT "^\[ *[0-9]*\] two::c2<double>::val:"
+check $STDOUT "^\[ *[0-9]*\] two::c2<double>:"
+check $STDOUT "^\[ *[0-9]*\] two::c2<int const\*>:"
+check $STDOUT "^\[ *[0-9]*\] two::c2<int const\*>::~c2:"
+check $STDOUT "^\[ *[0-9]*\] two::c2<int const\*>::c2:"
+check $STDOUT "^\[ *[0-9]*\] two::c2<int const\*>::val:"
+check $STDOUT "^\[ *[0-9]*\] two::c2<int>::~c2:"
+check $STDOUT "^\[ *[0-9]*\] two::c2<int>::c2:"
+check $STDOUT "^\[ *[0-9]*\] two::c2<int>::val:"
+check $STDOUT "^\[ *[0-9]*\] two::c2<int>:"
+check $STDOUT "^\[ *[0-9]*\] two::c2v1:"
+check $STDOUT "^\[ *[0-9]*\] two::c2v2:"
+check $STDOUT "^\[ *[0-9]*\] anonymous_union_var:"
+check $STDOUT "^\[ *[0-9]*\] inline_func_1:"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/hidden_test.sh b/binutils-2.25/gold/testsuite/hidden_test.sh
new file mode 100755
index 00000000..df51b376
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/hidden_test.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+# hidden_test.sh -- a test case for hidden and internal symbols.
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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 goes with hidden_test_main.c and hidden_test_1.c.
+# The main program defines several symbols with each of the ELF
+# visibilities, and the shared library attempts to reference the
+# symbols. We try to link the program and check that the expected
+# error messages are issued for the references to internal and
+# hidden symbols. The errors will be found in hidden_test.err.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected error in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual error output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check_missing()
+{
+ if grep -q "$2" "$1"
+ then
+ echo "Found unexpected error in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual error output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+# We should see errors for hidden and internal symbols.
+check hidden_test.err "hidden symbol 'main_hidden' in hidden_test_main.o is referenced by DSO libhidden.so"
+check hidden_test.err "internal symbol 'main_internal' in hidden_test_main.o is referenced by DSO libhidden.so"
+
+# We shouldn't see errors for the default and protected symbols.
+check_missing hidden_test.err "main_default"
+check_missing hidden_test.err "main_protected"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/hidden_test_1.c b/binutils-2.25/gold/testsuite/hidden_test_1.c
new file mode 100644
index 00000000..f685cabf
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/hidden_test_1.c
@@ -0,0 +1,41 @@
+/* hidden_test_1.c -- test hidden and internal symbols
+
+ Copyright 2009 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@google.com>
+
+ 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 is a test of symbols of various visibilities in the main program
+ and attempts to reference those symbols from a shared library.
+ The linker should issue an error message for references to hidden
+ and internal symbols. */
+
+extern void main_default (void);
+extern void main_hidden (void);
+extern void main_internal (void);
+extern void main_protected (void);
+
+int
+lib1 (void)
+{
+ main_default ();
+ main_hidden ();
+ main_internal ();
+ main_protected ();
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/hidden_test_main.c b/binutils-2.25/gold/testsuite/hidden_test_main.c
new file mode 100644
index 00000000..c54864dc
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/hidden_test_main.c
@@ -0,0 +1,61 @@
+/* hidden_test_main.c -- test hidden and internal symbols
+
+ Copyright 2009 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@google.com>
+
+ 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 is a test of symbols of various visibilities in the main program
+ and attempts to reference those symbols from a shared library.
+ The linker should issue an error message for references to hidden
+ and internal symbols. */
+
+extern void lib1 (void);
+
+void main_default (void);
+void main_hidden (void);
+void main_internal (void);
+void main_protected (void);
+
+void __attribute__((visibility ("default")))
+main_default (void)
+{
+}
+
+void __attribute__((visibility ("hidden")))
+main_hidden (void)
+{
+}
+
+void __attribute__((visibility ("internal")))
+main_internal (void)
+{
+}
+
+void __attribute__((visibility ("protected")))
+main_protected (void)
+{
+}
+
+int
+main (int argc __attribute__ ((unused)),
+ char** argv __attribute__ ((unused)))
+{
+ lib1 ();
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/icf_keep_unique_test.cc b/binutils-2.25/gold/testsuite/icf_keep_unique_test.cc
new file mode 100644
index 00000000..37f6437a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_keep_unique_test.cc
@@ -0,0 +1,39 @@
+// icf_keep_unique_test.cc -- a test case for gold
+
+// Copyright 2009 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify if --keep-unique works
+// as intended when used with --icf.
+
+int kept_func()
+{
+ return 0;
+}
+
+int unique_func()
+{
+ return 0;
+}
+
+int main()
+{
+ return 1;
+}
diff --git a/binutils-2.25/gold/testsuite/icf_keep_unique_test.sh b/binutils-2.25/gold/testsuite/icf_keep_unique_test.sh
new file mode 100755
index 00000000..c2673737
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_keep_unique_test.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# icf_keep_unique_test.sh -- test --icf --keep-unique
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# 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 goal of this program is to verify if --keep-unique works
+# as intended when used with --icf.
+
+check()
+{
+ func_addr_1=`grep $2 $1 | awk '{print $1}'`
+ func_addr_2=`grep $3 $1 | awk '{print $1}'`
+ if [ $func_addr_1 = $func_addr_2 ]
+ then
+ echo "Identical Code Folding with keep-unique failed to unfold" $2
+ exit 1
+ fi
+}
+
+check icf_keep_unique_test.stdout "kept_func" "unique_func"
diff --git a/binutils-2.25/gold/testsuite/icf_preemptible_functions_test.cc b/binutils-2.25/gold/testsuite/icf_preemptible_functions_test.cc
new file mode 100644
index 00000000..35a96bc5
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_preemptible_functions_test.cc
@@ -0,0 +1,47 @@
+// icf_preemptible_functions_test.cc -- a test case for gold
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify that preemptible functions are
+// correctly handled by ICF. In this program, foo and bar should not
+// be folded although they are identical as zap or zip could be preempted.
+
+int zap()
+{
+ return 0;
+}
+
+int zip()
+{
+ return 0;
+}
+
+int foo()
+{
+ zap();
+ return 0;
+}
+
+int bar()
+{
+ zip();
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/icf_preemptible_functions_test.sh b/binutils-2.25/gold/testsuite/icf_preemptible_functions_test.sh
new file mode 100755
index 00000000..dd90d7fd
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_preemptible_functions_test.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+# icf_preemptible_functions_test.sh -- test --icf=all
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# 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.
+
+
+check()
+{
+ func_addr_1=`grep $2 $1 | awk '{print $1}'`
+ func_addr_2=`grep $3 $1 | awk '{print $1}'`
+ if [ $func_addr_1 = $func_addr_2 ]
+ then
+ echo "Identical Code Folding should not fold" $2 "and" $3
+ exit 1
+ fi
+}
+
+check icf_preemptible_functions_test.stdout "_Z3foov" "_Z3barv"
diff --git a/binutils-2.25/gold/testsuite/icf_safe_so_test.cc b/binutils-2.25/gold/testsuite/icf_safe_so_test.cc
new file mode 100644
index 00000000..0f50ad61
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_safe_so_test.cc
@@ -0,0 +1,74 @@
+// icf_safe_so_test.cc -- a test case for gold
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify if identical code folding
+// in safe mode correctly folds functions in a shared object. The
+// foo_* functions below should not be folded. For x86-64,
+// foo_glob and bar_glob should be folded as their function pointers
+// are addresses of PLT entries in shared objects. For 32-bit X86,
+// the hidden protected and internal symbols can be folded.
+
+int __attribute__ ((visibility ("protected")))
+foo_prot()
+{
+ return 1;
+}
+
+int __attribute__ ((visibility ("hidden")))
+foo_hidden()
+{
+ return 1;
+}
+
+int __attribute__ ((visibility ("internal")))
+foo_internal()
+{
+ return 1;
+}
+
+static int
+foo_static()
+{
+ return 1;
+}
+
+int foo_glob()
+{
+ return 2;
+}
+
+int bar_glob()
+{
+ return 2;
+}
+
+int main()
+{
+ int (*p)() = foo_glob;
+ (void)p;
+ foo_static();
+ foo_prot();
+ foo_hidden();
+ foo_internal();
+ return 0;
+}
+
diff --git a/binutils-2.25/gold/testsuite/icf_safe_so_test.sh b/binutils-2.25/gold/testsuite/icf_safe_so_test.sh
new file mode 100755
index 00000000..813248e5
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_safe_so_test.sh
@@ -0,0 +1,102 @@
+#!/bin/sh
+
+# icf_safe_so_test.sh -- test --icf=safe
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# 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 goal of this program is to verify if --icf=safe works as expected.
+# File icf_safe_so_test.cc is in this test. The goal of this script is
+# to verify if identical code folding in safe mode correctly folds
+# functions in a shared object.
+
+error_if_symbol_absent()
+{
+ if ! is_symbol_present $1 $2;
+ then
+ echo "Symbol" $2 "not present, possibly folded."
+ exit 1
+ fi
+}
+
+is_symbol_present()
+{
+ grep $2 $1 > /dev/null 2>&1
+ return $?
+}
+
+check_nofold()
+{
+ error_if_symbol_absent $1 $2
+ error_if_symbol_absent $1 $3
+ func_addr_1=`grep $2 $1 | awk '{print $1}'`
+ func_addr_2=`grep $3 $1 | awk '{print $1}'`
+ if [ $func_addr_1 = $func_addr_2 ];
+ then
+ echo "Safe Identical Code Folding folded" $2 "and" $3
+ exit 1
+ fi
+}
+
+check_fold()
+{
+ if ! is_symbol_present $1 $2
+ then
+ return 0
+ fi
+
+ if ! is_symbol_present $1 $3
+ then
+ return 0
+ fi
+
+ awk "
+BEGIN { discard = 0; }
+/^Discarded input/ { discard = 1; }
+/^Memory map/ { discard = 0; }
+/.*\\.text\\..*($2|$3).*/ { act[discard] = act[discard] \" \" \$0; }
+END {
+ # printf \"kept\" act[0] \"\\nfolded\" act[1] \"\\n\";
+ if (length(act[0]) == 0 || length(act[1]) == 0)
+ {
+ printf \"Safe Identical Code Folding did not fold $2 and $3\\n\"
+ exit 1;
+ }
+ }" $4
+}
+
+arch_specific_safe_fold()
+{
+ grep -e "Intel 80386" -e "ARM" -e "PowerPC" $1 > /dev/null 2>&1
+ if [ $? -eq 0 ];
+ then
+ check_fold $2 $4 $5 $3
+ else
+ check_nofold $2 $4 $5
+ fi
+}
+
+arch_specific_safe_fold icf_safe_so_test_2.stdout icf_safe_so_test_1.stdout icf_safe_so_test.map "foo_prot" "foo_hidden"
+arch_specific_safe_fold icf_safe_so_test_2.stdout icf_safe_so_test_1.stdout icf_safe_so_test.map "foo_prot" "foo_internal"
+arch_specific_safe_fold icf_safe_so_test_2.stdout icf_safe_so_test_1.stdout icf_safe_so_test.map "foo_prot" "foo_static"
+arch_specific_safe_fold icf_safe_so_test_2.stdout icf_safe_so_test_1.stdout icf_safe_so_test.map "foo_hidden" "foo_internal"
+arch_specific_safe_fold icf_safe_so_test_2.stdout icf_safe_so_test_1.stdout icf_safe_so_test.map "foo_hidden" "foo_static"
+arch_specific_safe_fold icf_safe_so_test_2.stdout icf_safe_so_test_1.stdout icf_safe_so_test.map "foo_internal" "foo_static"
+check_nofold icf_safe_so_test_1.stdout "foo_glob" "bar_glob"
diff --git a/binutils-2.25/gold/testsuite/icf_safe_test.cc b/binutils-2.25/gold/testsuite/icf_safe_test.cc
new file mode 100644
index 00000000..87294dcc
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_safe_test.cc
@@ -0,0 +1,63 @@
+// icf_safe_test.cc -- a test case for gold
+
+// Copyright 2009 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify if identical code folding
+// in safe mode correctly folds only ctors and dtors. kept_func_1 must
+// not be folded into kept_func_2 other than for X86 (32 and 64 bit)
+// which can use relocation types to determine if function pointers are
+// taken. kept_func_3 should never be folded as its pointer is taken.
+// The ctor and dtor of class A must be folded.
+
+class A
+{
+ public:
+ A()
+ {
+ }
+ ~A()
+ {
+ }
+};
+
+A a;
+
+int kept_func_1()
+{
+ return 1;
+}
+
+int kept_func_2()
+{
+ return 1;
+}
+
+int kept_func_3()
+{
+ return 1;
+}
+
+int main()
+{
+ int (*p)() = kept_func_3;
+ p();
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/icf_safe_test.sh b/binutils-2.25/gold/testsuite/icf_safe_test.sh
new file mode 100755
index 00000000..fe224f69
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_safe_test.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+# icf_safe_test.sh -- test --icf=safe
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# 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 goal of this program is to verify if --icf=safe works as expected.
+# File icf_safe_test.cc is in this test. This program checks if only
+# ctors and dtors are folded, except for x86 (32 and 64 bit), which
+# uses relocation types to detect if function pointers are taken.
+
+check_nofold()
+{
+ func_addr_1=`grep $2 $1 | awk '{print $1}'`
+ func_addr_2=`grep $3 $1 | awk '{print $1}'`
+ if [ $func_addr_1 = $func_addr_2 ]
+ then
+ echo "Safe Identical Code Folding folded" $2 "and" $3
+ exit 1
+ fi
+}
+
+check_fold()
+{
+ awk "
+BEGIN { discard = 0; }
+/^Discarded input/ { discard = 1; }
+/^Memory map/ { discard = 0; }
+/.*\\.text\\..*($2|$3).*/ { act[discard] = act[discard] \" \" \$0; }
+END {
+ # printf \"kept\" act[0] \"\\nfolded\" act[1] \"\\n\";
+ if (length(act[0]) == 0 || length(act[1]) == 0)
+ {
+ printf \"Safe Identical Code Folding did not fold $2 and $3\\n\"
+ exit 1;
+ }
+ }" $1
+}
+
+arch_specific_safe_fold()
+{
+ grep_x86=`grep -q -e "Advanced Micro Devices X86-64" -e "Intel 80386" -e "ARM" -e "TILE" -e "PowerPC" $2`
+ if [ $? -eq 0 ];
+ then
+ check_fold $3 $4 $5
+ else
+ check_nofold $1 $4 $5
+ fi
+}
+
+arch_specific_safe_fold icf_safe_test_1.stdout icf_safe_test_2.stdout \
+ icf_safe_test.map "kept_func_1" "kept_func_2"
+check_fold icf_safe_test.map "_ZN1AD2Ev" "_ZN1AC2Ev"
+check_nofold icf_safe_test_1.stdout "kept_func_3" "kept_func_1"
+check_nofold icf_safe_test_1.stdout "kept_func_3" "kept_func_2"
diff --git a/binutils-2.25/gold/testsuite/icf_sht_rel_addend_test.sh b/binutils-2.25/gold/testsuite/icf_sht_rel_addend_test.sh
new file mode 100755
index 00000000..9077e25e
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_sht_rel_addend_test.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+# icf_sht_rel_addend_test.sh -- test --icf=all
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# 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.
+
+
+check()
+{
+ func_addr_1=`grep $2 $1 | awk '{print $1}'`
+ func_addr_2=`grep $3 $1 | awk '{print $1}'`
+ if [ $func_addr_1 = $func_addr_2 ]
+ then
+ echo "Identical Code Folding should not fold" $2 "and" $3
+ exit 1
+ fi
+}
+
+check icf_sht_rel_addend_test.stdout "name1" "name2"
diff --git a/binutils-2.25/gold/testsuite/icf_sht_rel_addend_test_1.cc b/binutils-2.25/gold/testsuite/icf_sht_rel_addend_test_1.cc
new file mode 100644
index 00000000..ecc2a1b0
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_sht_rel_addend_test_1.cc
@@ -0,0 +1,44 @@
+// icf_sht_rel_addend_test_1.cc -- a test case for gold
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify is strings are handled correctly
+// by ICF when the relocation types are SHT_REL. ICF inlines strings that
+// can be merged. To do this, it must get the addend of the relocation
+// pointing to the string. For SHT_REL relocations, the addend is encoded
+// in the text section at the offset of the relocation. If ICF fails to
+// get the addend correctly, function name1 will be incorrectly folded with
+// function name2 in icf_sht_rel_addend_test_2.cc.
+
+
+const char* bar()
+{
+ return "AAAAAA";
+}
+const char* name1()
+{
+ return "Name1";
+}
+
+int main()
+{
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/icf_sht_rel_addend_test_2.cc b/binutils-2.25/gold/testsuite/icf_sht_rel_addend_test_2.cc
new file mode 100644
index 00000000..d85e3b4d
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_sht_rel_addend_test_2.cc
@@ -0,0 +1,39 @@
+// icf_sht_rel_addend_test_2.cc -- a test case for gold
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify is strings are handled correctly
+// by ICF when the relocation types are SHT_REL. ICF inlines strings that
+// can be merged. To do this, it must get the addend of the relocation
+// pointing to the string. For SHT_REL relocations, the addend is encoded
+// in the text section at the offset of the relocation. If ICF fails to
+// get the addend correctly, function name1 in icf_sht_rel_addend_test_1.cc
+// will be incorrectly folded with name2.
+
+
+const char* foo()
+{
+ return "AAAAAA";
+}
+const char* name2()
+{
+ return "Name2";
+}
diff --git a/binutils-2.25/gold/testsuite/icf_string_merge_test.cc b/binutils-2.25/gold/testsuite/icf_string_merge_test.cc
new file mode 100644
index 00000000..b1e11910
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_string_merge_test.cc
@@ -0,0 +1,50 @@
+// icf_string_merge_test.cc -- a test case for gold
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify is strings are handled correctly
+// by ICF. ICF inlines strings that can be merged. In some cases, the
+// addend of the relocation pointing to a string merge section must be
+// ignored. This program has no pair of identical functions that can be
+// folded. However, if the addend is not ignored then get2 and get3 will
+// become identical.
+
+const char* const str1 = "aaaaaaaaaastr1";
+const char* const str2 = "bbbbaaaaaastr1";
+const char* const str3 = "cccccaaaaastr1";
+
+const char* get1()
+{
+ return str1;
+}
+const char* get2()
+{
+ return str2;
+}
+
+const char* get3()
+{
+ return str3;
+}
+int main()
+{
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/icf_string_merge_test.sh b/binutils-2.25/gold/testsuite/icf_string_merge_test.sh
new file mode 100755
index 00000000..e8d70de2
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_string_merge_test.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# icf_string_merge_test.sh -- test --icf=all
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# 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.
+
+
+check()
+{
+ func_addr_1=`grep $2 $1 | awk '{print $1}'`
+ func_addr_2=`grep $3 $1 | awk '{print $1}'`
+ if [ $func_addr_1 = $func_addr_2 ]
+ then
+ echo "Identical Code Folding should not fold" $2 "and" $3
+ exit 1
+ fi
+}
+
+check icf_string_merge_test.stdout "get1" "get2"
+check icf_string_merge_test.stdout "get1" "get3"
+check icf_string_merge_test.stdout "get2" "get3"
diff --git a/binutils-2.25/gold/testsuite/icf_test.cc b/binutils-2.25/gold/testsuite/icf_test.cc
new file mode 100644
index 00000000..c7a5ea9d
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_test.cc
@@ -0,0 +1,51 @@
+// icf_test.cc -- a test case for gold
+
+// Copyright 2009 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify if identical code folding
+// correctly identifies and folds functions. folded_func must be
+// folded into kept_func.
+
+int common()
+{
+ return 1;
+}
+
+int kept_func()
+{
+ common();
+ // Recursive call.
+ kept_func();
+ return 1;
+}
+
+int folded_func()
+{
+ common();
+ // Recursive call.
+ folded_func();
+ return 1;
+}
+
+int main()
+{
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/icf_test.sh b/binutils-2.25/gold/testsuite/icf_test.sh
new file mode 100755
index 00000000..50abd90e
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_test.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# icf_test.sh -- test --icf
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# 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 goal of this program is to verify if icf works as expected.
+# File icf_test.cc is in this test. This program checks if the
+# identical sections are correctly folded.
+
+check()
+{
+ awk "
+BEGIN { discard = 0; }
+/^Discarded input/ { discard = 1; }
+/^Memory map/ { discard = 0; }
+/.*\\.text\\..*($2|$3).*/ { act[discard] = act[discard] \" \" \$0; }
+END {
+ # printf \"kept\" act[0] \"\\nfolded\" act[1] \"\\n\";
+ if (length(act[0]) == 0 || length(act[1]) == 0)
+ {
+ printf \"Identical Code Folding did not fold $2 and $3\\n\"
+ exit 1;
+ }
+ }" $1
+}
+
+check icf_test.map "folded_func" "kept_func"
diff --git a/binutils-2.25/gold/testsuite/icf_virtual_function_folding_test.cc b/binutils-2.25/gold/testsuite/icf_virtual_function_folding_test.cc
new file mode 100644
index 00000000..ba063c8a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/icf_virtual_function_folding_test.cc
@@ -0,0 +1,71 @@
+// icf_virtual_function_folding_test.cc -- a test case for gold
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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.
+
+// Foo::fn1 is folded into fn2 with ICF. Since this file is linked as a
+// position independent executable, a dynamic reloc is needed
+// for the virtual call fn1 entry in the vtable. This test makes sure
+// the call to Foo::fn1 works correctly after the folding.
+
+int fn2(void *)
+{
+ return 0xA;
+}
+
+namespace
+{
+
+class Bar
+{
+ public:
+ virtual ~Bar() { }
+ virtual int fn1();
+};
+
+int Bar::fn1()
+{
+ return 123;
+}
+
+class Foo : public Bar
+{
+ virtual int fn1();
+};
+
+int Foo::fn1()
+{
+ return 0xA;
+}
+
+Bar* get()
+{
+ Bar *f = new Foo();
+ return f;
+}
+
+} // end of anonymous namespace.
+
+int main()
+{
+ Bar *f = get();
+ f->fn1();
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/ifunc-sel.h b/binutils-2.25/gold/testsuite/ifunc-sel.h
new file mode 100644
index 00000000..94396592
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifunc-sel.h
@@ -0,0 +1,92 @@
+/* Used by the elf ifunc tests. */
+#ifndef ELF_IFUNC_SEL_H
+#define ELF_IFUNC_SEL_H 1
+
+extern int global;
+
+static inline __attribute__ ((always_inline)) void *
+ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void))
+{
+#ifdef __powerpc__
+ /* When generating PIC, powerpc gcc loads the address of "global"
+ from the GOT, but the GOT may not have been relocated.
+ Similarly, "f1", "f2" and "f3" may be loaded from non-relocated
+ GOT entries.
+
+ There is NO WAY to make this ill conceived IFUNC misfeature
+ reliably work on targets that use a GOT for function or variable
+ addresses, short of implementing two passes over relocations in
+ ld.so, with ifunc relocations being applied after all other
+ relocations, globally.
+
+ Cheat. Don't use the GOT. Rely on this function being inlined
+ and calculate all variable and function addresses relative to pc.
+ Using the 'X' constraint is risky, but that's the only way to
+ make the asm here see the function names for %4, %5 and %6.
+ Sadly, powerpc64 gcc doesn't accept use of %3 here with 'X' for
+ some reason, so we expand it ourselves. */
+ register void *ret __asm__ ("r3");
+ void *temp1, *temp2;
+ __asm__ ("mflr %1\n\t"
+ "bcl 20,31,1f\n"
+ "1:\tmflr %2\n\t"
+ "mtlr %1\n\t"
+ "addis %1,%2,global-1b@ha\n\t"
+ "lwz %1,global-1b@l(%1)\n\t"
+ "addis %0,%2,%4-1b@ha\n\t"
+ "addi %0,%0,%4-1b@l\n\t"
+ "cmpwi %1,1\n\t"
+ "beqlr\n\t"
+ "addis %0,%2,%5-1b@ha\n\t"
+ "addi %0,%0,%5-1b@l\n\t"
+ "cmpwi %1,-1\n\t"
+ "beqlr\n\t"
+ "addis %0,%2,%6-1b@ha\n\t"
+ "addi %0,%0,%6-1b@l"
+ : "=&b" (ret), "=&b" (temp1), "=&b" (temp2)
+ : "X" (&global), "X" (f1), "X" (f2), "X" (f3));
+ return ret;
+#else
+ switch (global)
+ {
+ case 1:
+ return f1;
+ case -1:
+ return f2;
+ default:
+ return f3;
+ }
+#endif
+}
+
+static inline __attribute__ ((always_inline)) void *
+ifunc_one (int (*f1) (void))
+{
+#ifdef __powerpc__
+ /* As above, PIC may use an unrelocated GOT entry for f1.
+
+ Case study: ifuncmain6pie's shared library, ifuncmod6.so, wants
+ the address of "foo" in function get_foo(). So there is a GOT
+ entry for "foo" in ifuncmod6.so. ld.so relocates ifuncmod6.so
+ *before* ifuncmain6pie, and on finding "foo" to be STT_GNU_IFUNC,
+ calls this function with f1 set to "one". But the address of
+ "one" is loaded from ifuncmain6pie's GOT, which hasn't been
+ relocated yet.
+
+ Cheat as for ifunc-sel. */
+ register void *ret __asm__ ("r3");
+ void *temp;
+ __asm__ ("mflr %1\n\t"
+ "bcl 20,31,1f\n"
+ "1:\tmflr %0\n\t"
+ "mtlr %1\n\t"
+ "addis %0,%0,%2-1b@ha\n\t"
+ "addi %0,%0,%2-1b@l"
+ : "=&b" (ret), "=&r" (temp)
+ : "X" (f1));
+ return ret;
+#else
+ return f1;
+#endif
+}
+#endif
diff --git a/binutils-2.25/gold/testsuite/ifuncdep2.c b/binutils-2.25/gold/testsuite/ifuncdep2.c
new file mode 100644
index 00000000..758bae19
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncdep2.c
@@ -0,0 +1,50 @@
+/* Test 3 STT_GNU_IFUNC symbols. */
+
+#include "ifunc-sel.h"
+
+int global __attribute__ ((visibility ("protected"))) = -1;
+
+static int
+one (void)
+{
+ return 1;
+}
+
+static int
+minus_one (void)
+{
+ return -1;
+}
+
+static int
+zero (void)
+{
+ return 0;
+}
+
+void * foo1_ifunc (void) __asm__ ("foo1");
+__asm__(".type foo1, %gnu_indirect_function");
+
+void *
+foo1_ifunc (void)
+{
+ return ifunc_sel (one, minus_one, zero);
+}
+
+void * foo2_ifunc (void) __asm__ ("foo2");
+__asm__(".type foo2, %gnu_indirect_function");
+
+void *
+foo2_ifunc (void)
+{
+ return ifunc_sel (minus_one, one, zero);
+}
+
+void * foo3_ifunc (void) __asm__ ("foo3");
+__asm__(".type foo3, %gnu_indirect_function");
+
+void *
+foo3_ifunc (void)
+{
+ return ifunc_sel (one, zero, minus_one);
+}
diff --git a/binutils-2.25/gold/testsuite/ifuncmain1.c b/binutils-2.25/gold/testsuite/ifuncmain1.c
new file mode 100644
index 00000000..cc1e5ec5
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncmain1.c
@@ -0,0 +1,64 @@
+/* Test STT_GNU_IFUNC symbols:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Visibility without override.
+ */
+
+#include <stdlib.h>
+
+int ret_foo;
+int ret_foo_hidden;
+int ret_foo_protected;
+
+extern int foo (void);
+extern int foo_protected (void);
+
+#ifndef FOO_P
+typedef int (*foo_p) (void);
+#endif
+
+foo_p foo_ptr = foo;
+foo_p foo_procted_ptr = foo_protected;
+
+extern foo_p get_foo_p (void);
+extern foo_p get_foo_hidden_p (void);
+extern foo_p get_foo_protected_p (void);
+
+int
+main (void)
+{
+ foo_p p;
+
+ if (foo_ptr != foo)
+ abort ();
+ if (foo () != -1)
+ abort ();
+ if ((*foo_ptr) () != -1)
+ abort ();
+
+ if (foo_procted_ptr != foo_protected)
+ abort ();
+ if (foo_protected () != 0)
+ abort ();
+ if ((*foo_procted_ptr) () != 0)
+ abort ();
+
+ p = get_foo_p ();
+ if (p != foo)
+ abort ();
+ if (ret_foo != -1 || (*p) () != ret_foo)
+ abort ();
+
+ p = get_foo_hidden_p ();
+ if (ret_foo_hidden != 1 || (*p) () != ret_foo_hidden)
+ abort ();
+
+ p = get_foo_protected_p ();
+ if (p != foo_protected)
+ abort ();
+ if (ret_foo_protected != 0 || (*p) () != ret_foo_protected)
+ abort ();
+
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/ifuncmain1vis.c b/binutils-2.25/gold/testsuite/ifuncmain1vis.c
new file mode 100644
index 00000000..c16af63a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncmain1vis.c
@@ -0,0 +1,89 @@
+/* Test STT_GNU_IFUNC symbols:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Visibility with override.
+ */
+
+#include <stdlib.h>
+
+int __attribute__ ((noinline)) foo_hidden (void);
+
+int ret_foo;
+int ret_foo_hidden;
+int ret_foo_protected;
+
+extern int foo (void);
+extern int foo_protected (void);
+
+#ifndef FOO_P
+typedef int (*foo_p) (void);
+#endif
+
+foo_p foo_ptr = foo;
+foo_p foo_procted_ptr = foo_protected;
+
+extern foo_p get_foo_p (void);
+extern foo_p get_foo_hidden_p (void);
+extern foo_p get_foo_protected_p (void);
+
+int
+__attribute__ ((noinline))
+foo (void)
+{
+ return -30;
+}
+
+int
+__attribute__ ((noinline))
+foo_hidden (void)
+{
+ return -20;
+}
+
+int
+__attribute__ ((noinline))
+foo_protected (void)
+{
+ return -40;
+}
+
+int
+main (void)
+{
+ foo_p p;
+
+ if (foo_ptr != foo)
+ abort ();
+ if ((*foo_ptr) () != -30)
+ abort ();
+
+ if (foo_procted_ptr != foo_protected)
+ abort ();
+ if ((*foo_procted_ptr) () != -40)
+ abort ();
+
+ p = get_foo_p ();
+ if (p != foo)
+ abort ();
+ if (foo () != -30)
+ abort ();
+ if (ret_foo != -30 || (*p) () != ret_foo)
+ abort ();
+
+ p = get_foo_hidden_p ();
+ if (foo_hidden () != -20)
+ abort ();
+ if (ret_foo_hidden != 1 || (*p) () != ret_foo_hidden)
+ abort ();
+
+ p = get_foo_protected_p ();
+ if (p == foo_protected)
+ abort ();
+ if (foo_protected () != -40)
+ abort ();
+ if (ret_foo_protected != 0 || (*p) () != ret_foo_protected)
+ abort ();
+
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/ifuncmain2.c b/binutils-2.25/gold/testsuite/ifuncmain2.c
new file mode 100644
index 00000000..db3ba56a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncmain2.c
@@ -0,0 +1,14 @@
+/* Test calling one STT_GNU_IFUNC function with 3 different
+ STT_GNU_IFUNC definitions. */
+
+#include <stdlib.h>
+
+extern int foo1 (void);
+
+int
+main (void)
+{
+ if (foo1 () != -1)
+ abort ();
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/ifuncmain3.c b/binutils-2.25/gold/testsuite/ifuncmain3.c
new file mode 100644
index 00000000..8e543e59
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncmain3.c
@@ -0,0 +1,133 @@
+/* Test STT_GNU_IFUNC symbols with dlopen:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Visibility with override.
+ */
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+extern int __attribute__ ((noinline)) foo (void);
+extern int __attribute__ ((noinline)) foo_hidden (void);
+extern int __attribute__ ((noinline)) foo_protected (void);
+
+typedef int (*foo_p) (void);
+
+int
+__attribute__ ((noinline))
+foo (void)
+{
+ return -30;
+}
+
+int
+__attribute__ ((noinline))
+foo_hidden (void)
+{
+ return -20;
+}
+
+int
+__attribute__ ((noinline))
+foo_protected (void)
+{
+ return -40;
+}
+
+int
+main (void)
+{
+ foo_p p;
+ foo_p (*f) (void);
+ int *ret;
+
+ void *h = dlopen ("ifuncmod3.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot load: %s\n", dlerror ());
+ return 1;
+ }
+
+ p = dlsym (h, "foo");
+ if (p == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+ if ((*p) () != -1)
+ abort ();
+
+ f = dlsym (h, "get_foo_p");
+ if (f == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ ret = dlsym (h, "ret_foo");
+ if (ret == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ p = (*f) ();
+ if (p != foo)
+ abort ();
+ if (foo () != -30)
+ abort ();
+ if (*ret != -30 || (*p) () != *ret)
+ abort ();
+
+ f = dlsym (h, "get_foo_hidden_p");
+ if (f == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ ret = dlsym (h, "ret_foo_hidden");
+ if (ret == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ p = (*f) ();
+ if (foo_hidden () != -20)
+ abort ();
+ if (*ret != 1 || (*p) () != *ret)
+ abort ();
+
+ f = dlsym (h, "get_foo_protected_p");
+ if (f == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ ret = dlsym (h, "ret_foo_protected");
+ if (ret == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ p = (*f) ();
+ if (p == foo_protected)
+ abort ();
+ if (foo_protected () != -40)
+ abort ();
+ if (*ret != 0 || (*p) () != *ret)
+ abort ();
+
+ if (dlclose (h) != 0)
+ {
+ printf ("cannot close: %s\n", dlerror ());
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/ifuncmain4.c b/binutils-2.25/gold/testsuite/ifuncmain4.c
new file mode 100644
index 00000000..e55fee2e
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncmain4.c
@@ -0,0 +1,4 @@
+/* Test STT_GNU_IFUNC symbols in a single source file. */
+
+#include "ifuncmod1.c"
+#include "ifuncmain1.c"
diff --git a/binutils-2.25/gold/testsuite/ifuncmain5.c b/binutils-2.25/gold/testsuite/ifuncmain5.c
new file mode 100644
index 00000000..9e6c2c16
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncmain5.c
@@ -0,0 +1,41 @@
+/* Test STT_GNU_IFUNC symbols with dynamic function pointer only. */
+
+#include <stdlib.h>
+
+extern int foo (void);
+extern int foo_protected (void);
+
+typedef int (*foo_p) (void);
+
+extern foo_p __attribute__ ((noinline)) get_foo (void);
+extern foo_p __attribute__ ((noinline)) get_foo_protected (void);
+
+foo_p
+__attribute__ ((noinline))
+get_foo (void)
+{
+ return foo;
+}
+
+foo_p
+__attribute__ ((noinline))
+get_foo_protected (void)
+{
+ return foo_protected;
+}
+
+int
+main (void)
+{
+ foo_p p;
+
+ p = get_foo ();
+ if ((*p) () != -1)
+ abort ();
+
+ p = get_foo_protected ();
+ if ((*p) () != 0)
+ abort ();
+
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/ifuncmain6pie.c b/binutils-2.25/gold/testsuite/ifuncmain6pie.c
new file mode 100644
index 00000000..8478d4c4
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncmain6pie.c
@@ -0,0 +1,64 @@
+/* Test STT_GNU_IFUNC symbols in PIE:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Reference from a shared library.
+ */
+
+#include <stdlib.h>
+#include "ifunc-sel.h"
+
+typedef int (*foo_p) (void);
+extern foo_p foo_ptr;
+
+static int
+one (void)
+{
+ return -30;
+}
+
+void * foo_ifunc (void) __asm__ ("foo");
+__asm__(".type foo, %gnu_indirect_function");
+
+void *
+foo_ifunc (void)
+{
+ return ifunc_one (one);
+}
+
+extern int foo (void);
+extern foo_p get_foo (void);
+extern foo_p get_foo_p (void);
+
+foo_p my_foo_ptr = foo;
+
+int
+main (void)
+{
+ foo_p p;
+
+ p = get_foo ();
+ if (p != foo)
+ abort ();
+ if ((*p) () != -30)
+ abort ();
+
+ p = get_foo_p ();
+ if (p != foo)
+ abort ();
+ if ((*p) () != -30)
+ abort ();
+
+ if (foo_ptr != foo)
+ abort ();
+ if (my_foo_ptr != foo)
+ abort ();
+ if ((*foo_ptr) () != -30)
+ abort ();
+ if ((*my_foo_ptr) () != -30)
+ abort ();
+ if (foo () != -30)
+ abort ();
+
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/ifuncmain7.c b/binutils-2.25/gold/testsuite/ifuncmain7.c
new file mode 100644
index 00000000..c2524aa5
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncmain7.c
@@ -0,0 +1,74 @@
+/* Test local STT_GNU_IFUNC symbols:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ */
+
+#include <stdlib.h>
+#include "ifunc-sel.h"
+
+extern int foo (void);
+
+static int
+one (void)
+{
+ return -30;
+}
+
+static void * __attribute__ ((used)) foo_ifunc (void) __asm__ ("foo");
+__asm__(".type foo, %gnu_indirect_function");
+
+static void *
+__attribute__ ((used))
+foo_ifunc (void)
+{
+ return ifunc_one (one);
+}
+
+typedef int (*foo_p) (void);
+
+extern foo_p __attribute__ ((noinline)) get_foo_p (void);
+extern foo_p __attribute__ ((noinline)) get_foo (void);
+
+foo_p foo_ptr = foo;
+
+foo_p
+__attribute__ ((noinline))
+get_foo_p (void)
+{
+ return foo_ptr;
+}
+
+foo_p
+__attribute__ ((noinline))
+get_foo (void)
+{
+ return foo;
+}
+
+int
+main (void)
+{
+ foo_p p;
+
+ p = get_foo ();
+ if (p != foo)
+ abort ();
+ if ((*p) () != -30)
+ abort ();
+
+ p = get_foo_p ();
+ if (p != foo)
+ abort ();
+ if ((*p) () != -30)
+ abort ();
+
+ if (foo_ptr != foo)
+ abort ();
+ if ((*foo_ptr) () != -30)
+ abort ();
+ if (foo () != -30)
+ abort ();
+
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/ifuncmod1.c b/binutils-2.25/gold/testsuite/ifuncmod1.c
new file mode 100644
index 00000000..e3b37cb5
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncmod1.c
@@ -0,0 +1,95 @@
+/* Test STT_GNU_IFUNC symbols:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Visibility.
+ */
+#include "ifunc-sel.h"
+
+int global __attribute__ ((visibility ("protected"))) = -1;
+
+static int
+one (void)
+{
+ return 1;
+}
+
+static int
+minus_one (void)
+{
+ return -1;
+}
+
+static int
+zero (void)
+{
+ return 0;
+}
+
+void * foo_ifunc (void) __asm__ ("foo");
+__asm__(".type foo, %gnu_indirect_function");
+
+void *
+foo_ifunc (void)
+{
+ return ifunc_sel (one, minus_one, zero);
+}
+
+void * foo_hidden_ifunc (void) __asm__ ("foo_hidden");
+__asm__(".type foo_hidden, %gnu_indirect_function");
+
+void *
+foo_hidden_ifunc (void)
+{
+ return ifunc_sel (minus_one, one, zero);
+}
+
+void * foo_protected_ifunc (void) __asm__ ("foo_protected");
+__asm__(".type foo_protected, %gnu_indirect_function");
+
+void *
+foo_protected_ifunc (void)
+{
+ return ifunc_sel (one, zero, minus_one);
+}
+
+/* Test hidden indirect function. */
+__asm__(".hidden foo_hidden");
+
+/* Test protected indirect function. */
+__asm__(".protected foo_protected");
+
+extern int foo (void);
+extern int foo_hidden (void);
+extern int foo_protected (void);
+extern int ret_foo;
+extern int ret_foo_hidden;
+extern int ret_foo_protected;
+
+#define FOO_P
+typedef int (*foo_p) (void);
+
+extern foo_p get_foo_p (void);
+extern foo_p get_foo_hidden_p (void);
+extern foo_p get_foo_protected_p (void);
+
+foo_p
+get_foo_p (void)
+{
+ ret_foo = foo ();
+ return foo;
+}
+
+foo_p
+get_foo_hidden_p (void)
+{
+ ret_foo_hidden = foo_hidden ();
+ return foo_hidden;
+}
+
+foo_p
+get_foo_protected_p (void)
+{
+ ret_foo_protected = foo_protected ();
+ return foo_protected;
+}
diff --git a/binutils-2.25/gold/testsuite/ifuncmod3.c b/binutils-2.25/gold/testsuite/ifuncmod3.c
new file mode 100644
index 00000000..ca2d9626
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncmod3.c
@@ -0,0 +1,7 @@
+/* Test STT_GNU_IFUNC symbols with dlopen. */
+
+#include "ifuncmod1.c"
+
+int ret_foo;
+int ret_foo_hidden;
+int ret_foo_protected;
diff --git a/binutils-2.25/gold/testsuite/ifuncmod5.c b/binutils-2.25/gold/testsuite/ifuncmod5.c
new file mode 100644
index 00000000..9a08e8cf
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncmod5.c
@@ -0,0 +1,55 @@
+/* Test STT_GNU_IFUNC symbols without direct function call. */
+#include "ifunc-sel.h"
+
+int global __attribute__ ((visibility ("protected"))) = -1;
+
+static int
+one (void)
+{
+ return 1;
+}
+
+static int
+minus_one (void)
+{
+ return -1;
+}
+
+static int
+zero (void)
+{
+ return 0;
+}
+
+void * foo_ifunc (void) __asm__ ("foo");
+__asm__(".type foo, %gnu_indirect_function");
+
+void *
+foo_ifunc (void)
+{
+ return ifunc_sel (one, minus_one, zero);
+}
+
+void * foo_hidden_ifunc (void) __asm__ ("foo_hidden");
+__asm__(".type foo_hidden, %gnu_indirect_function");
+
+void *
+foo_hidden_ifunc (void)
+{
+ return ifunc_sel (minus_one, one, zero);
+}
+
+void * foo_protected_ifunc (void) __asm__ ("foo_protected");
+__asm__(".type foo_protected, %gnu_indirect_function");
+
+void *
+foo_protected_ifunc (void)
+{
+ return ifunc_sel (one, zero, minus_one);
+}
+
+/* Test hidden indirect function. */
+__asm__(".hidden foo_hidden");
+
+/* Test protected indirect function. */
+__asm__(".protected foo_protected");
diff --git a/binutils-2.25/gold/testsuite/ifuncmod6.c b/binutils-2.25/gold/testsuite/ifuncmod6.c
new file mode 100644
index 00000000..89a50f93
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncmod6.c
@@ -0,0 +1,22 @@
+/* Test STT_GNU_IFUNC symbol reference in a shared library. */
+
+extern int foo (void);
+
+typedef int (*foo_p) (void);
+
+extern foo_p get_foo_p (void);
+extern foo_p get_foo (void);
+
+foo_p foo_ptr = foo;
+
+foo_p
+get_foo_p (void)
+{
+ return foo_ptr;
+}
+
+foo_p
+get_foo (void)
+{
+ return foo;
+}
diff --git a/binutils-2.25/gold/testsuite/ifuncvar1.c b/binutils-2.25/gold/testsuite/ifuncvar1.c
new file mode 100644
index 00000000..75af2a6a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncvar1.c
@@ -0,0 +1,20 @@
+/* Test global variable initialized to hidden STT_GNU_IFUNC symbol. */
+
+int didit;
+
+extern void doit (void);
+
+void
+doit (void)
+{
+ didit = 1;
+}
+
+void (*get_foo (void)) (void) __asm__ ("foo");
+__asm__ (".type foo, %gnu_indirect_function");
+__asm__ (".hidden foo");
+
+void (*get_foo (void)) (void)
+{
+ return &doit;
+}
diff --git a/binutils-2.25/gold/testsuite/ifuncvar2.c b/binutils-2.25/gold/testsuite/ifuncvar2.c
new file mode 100644
index 00000000..f09de0e1
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncvar2.c
@@ -0,0 +1,12 @@
+/* Test global variable initialized to hidden STT_GNU_IFUNC symbol. */
+
+extern void foo (void);
+void (*f) (void) = &foo;
+
+extern void bar (void);
+
+void
+bar (void)
+{
+ f ();
+}
diff --git a/binutils-2.25/gold/testsuite/ifuncvar3.c b/binutils-2.25/gold/testsuite/ifuncvar3.c
new file mode 100644
index 00000000..e078b567
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ifuncvar3.c
@@ -0,0 +1,14 @@
+/* Test global variable initialized to hidden STT_GNU_IFUNC symbol. */
+
+#include <assert.h>
+
+extern void bar (void);
+extern int didit;
+
+int
+main (void)
+{
+ bar ();
+ assert (didit == 1);
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/incr_comdat_test_1.cc b/binutils-2.25/gold/testsuite/incr_comdat_test_1.cc
new file mode 100644
index 00000000..7a232c24
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/incr_comdat_test_1.cc
@@ -0,0 +1,68 @@
+// incr_comdat_test_1.cc -- test incremental update with comdat sections
+
+// Copyright 2011 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 <cstdio>
+
+template <class T>
+T GetMax(T a, T b)
+{
+ return a > b ? a : b;
+}
+
+extern int foo();
+
+int bar()
+{
+ return GetMax<int>(4, 5);
+}
+
+class A
+{
+ public:
+ int sum(int k)
+ {
+ static int total = 0;
+ total += k;
+ return total;
+ }
+};
+
+#define CHECK_EQ(var, expected) \
+ do \
+ { \
+ if ((var) != (expected)) \
+ { \
+ printf(#var ": expected %d, found %d\n", expected, var); \
+ return 1; \
+ } \
+ } \
+ while (0)
+
+int main()
+{
+ A a;
+ CHECK_EQ(bar(), 5);
+ CHECK_EQ(foo(), 11);
+ CHECK_EQ(a.sum(55), 11 + 55);
+ CHECK_EQ(a.sum(66), 11 + 55 + 66);
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/incr_comdat_test_2_v1.cc b/binutils-2.25/gold/testsuite/incr_comdat_test_2_v1.cc
new file mode 100644
index 00000000..f7d6a8cc
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/incr_comdat_test_2_v1.cc
@@ -0,0 +1,44 @@
+// incr_comdat_test_2.cc -- test incremental update with comdat sections
+
+// Copyright 2011 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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.
+
+template <class T>
+T GetMax(T a, T b)
+{
+ return a > b ? a : b;
+}
+
+class A
+{
+ public:
+ int sum(int k)
+ {
+ static int total = 0;
+ total += k;
+ return total;
+ }
+};
+
+int foo()
+{
+ A a;
+ return GetMax<int>(10, a.sum(8));
+}
diff --git a/binutils-2.25/gold/testsuite/incr_comdat_test_2_v2.cc b/binutils-2.25/gold/testsuite/incr_comdat_test_2_v2.cc
new file mode 100644
index 00000000..fca7fda9
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/incr_comdat_test_2_v2.cc
@@ -0,0 +1,44 @@
+// incr_comdat_test_2.cc -- test incremental update with comdat sections
+
+// Copyright 2011 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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.
+
+template <class T>
+T GetMax(T a, T b)
+{
+ return a > b ? a : b;
+}
+
+class A
+{
+ public:
+ int sum(int k)
+ {
+ static int total = 0;
+ total += k;
+ return total;
+ }
+};
+
+int foo()
+{
+ A a;
+ return GetMax<int>(10, a.sum(9));
+}
diff --git a/binutils-2.25/gold/testsuite/incr_comdat_test_2_v3.cc b/binutils-2.25/gold/testsuite/incr_comdat_test_2_v3.cc
new file mode 100644
index 00000000..cbb83c1a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/incr_comdat_test_2_v3.cc
@@ -0,0 +1,44 @@
+// incr_comdat_test_2.cc -- test incremental update with comdat sections
+
+// Copyright 2011 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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.
+
+template <class T>
+T GetMax(T a, T b)
+{
+ return a > b ? a : b;
+}
+
+class A
+{
+ public:
+ int sum(int k)
+ {
+ static int total = 0;
+ total += k;
+ return total;
+ }
+};
+
+int foo()
+{
+ A a;
+ return GetMax<int>(10, a.sum(11));
+}
diff --git a/binutils-2.25/gold/testsuite/incremental_test.sh b/binutils-2.25/gold/testsuite/incremental_test.sh
new file mode 100755
index 00000000..930d7d14
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/incremental_test.sh
@@ -0,0 +1,89 @@
+#!/bin/sh
+
+# incremental_test.sh -- test that incremental linking information is correct.
+
+# Copyright 2009, 2010 Free Software Foundation, Inc.
+# Written by Rafael Avila de Espindola <espindola@google.com>
+# and Cary Coutant <ccoutant@google.com>
+
+# 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.
+
+check_cmp()
+{
+ if ! cmp -s "$1" "$2"
+ then
+ echo "Actual output differs from expected:"
+ echo "diff $1 $2"
+ diff $1 $2
+ exit 1
+ fi
+}
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+# Extract actual command line from linker's -v output.
+cat incremental_test.cmdline |
+ grep "gcctestdir/ld " |
+ sed "s/--incremental[-a-z]* //g" |
+ cut -d ' ' -f 2- > actual
+
+# Extract recorded command line from dump of the output file.
+cat incremental_test.stdout |
+ grep "Link command line" |
+ cut -d : -f 2- |
+ cut -d ' ' -f 3- |
+ sed "s/'//g" > recorded
+
+# Verify that the command line was recorded correctly.
+check_cmp actual recorded
+
+rm -f actual recorded
+
+# Filter the incremental-dump output into a format that can be grepped
+# more easily.
+
+awk '
+ /^[A-Za-z][A-Za-z ]+:$/ { section = $0; }
+ /^[[]/ { subsection = $0; }
+ /^ / { print section, subsection, $0; }
+' < incremental_test.stdout > incremental_test.dump
+
+check incremental_test.dump "Input sections: .* incremental_test_1.o *1 "
+check incremental_test.dump "Input sections: .* incremental_test_2.o *1 "
+check incremental_test.dump "Global symbol table: .* main .* relocation type "
+check incremental_test.dump "Global symbol table: .* a *incremental_test_1.o "
+check incremental_test.dump "Global symbol table: .* a .* relocation type "
+check incremental_test.dump "Global symbol table: .* b *incremental_test_2.o "
+check incremental_test.dump "Global symbol table: .* b .* relocation type "
+check incremental_test.dump "Global symbol table: .* t1 *incremental_test_2.o "
+check incremental_test.dump "Global symbol table: .* t1 .* relocation type "
+
+rm -f incremental_test.dump
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/incremental_test_1.c b/binutils-2.25/gold/testsuite/incremental_test_1.c
new file mode 100644
index 00000000..291caa06
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/incremental_test_1.c
@@ -0,0 +1,28 @@
+// Copyright 2009, 2010 Free Software Foundation, Inc.
+// Written by Rafael Avila de Espindola <espindola@google.com>
+
+// 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.
+
+int a = -1;
+
+extern int t1(int);
+
+int t1(int b)
+{
+ return a + b;
+}
diff --git a/binutils-2.25/gold/testsuite/incremental_test_2.c b/binutils-2.25/gold/testsuite/incremental_test_2.c
new file mode 100644
index 00000000..7fcecc42
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/incremental_test_2.c
@@ -0,0 +1,29 @@
+// Copyright 2009 Free Software Foundation, Inc.
+// Written by Rafael Avila de Espindola <espindola@google.com>
+
+// 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.
+
+int b = 1;
+
+extern int t1(int);
+
+int main(void) {
+ if (t1(b) != 0)
+ return 1;
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/initpri1.c b/binutils-2.25/gold/testsuite/initpri1.c
new file mode 100644
index 00000000..1c5252d8
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/initpri1.c
@@ -0,0 +1,105 @@
+/* initpri1.c -- test constructor priorities.
+
+ Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copied from the gcc testsuite, where the test was contributed by
+ Mark Mitchell <mark@codesourcery.com>.
+
+ 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 tests that the linker handles constructor and destructor
+ priorities correctly. */
+
+#include <stdlib.h>
+
+/* Constructor priorities in attributes were added in gcc 4.3. */
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)
+
+int i;
+int j;
+
+void c1(void) __attribute__((constructor (500)));
+void c2(void) __attribute__((constructor (700)));
+void c3(void) __attribute__((constructor (600)));
+
+void c1() {
+ if (i++ != 0)
+ abort ();
+}
+
+void c2() {
+ if (i++ != 2)
+ abort ();
+}
+
+void c3() {
+ if (i++ != 1)
+ abort ();
+}
+
+void d1(void) __attribute__((destructor (500)));
+void d2(void) __attribute__((destructor (700)));
+void d3(void) __attribute__((destructor (600)));
+
+void d1() {
+ if (--i != 0)
+ abort ();
+}
+
+void d2() {
+ if (--i != 2)
+ abort ();
+}
+
+void d3() {
+ if (j != 4)
+ abort ();
+ if (--i != 1)
+ abort ();
+}
+
+void cd4(void) __attribute__((constructor (800), destructor (800)));
+
+void cd4() {
+ if (i != 3)
+ abort ();
+ ++j;
+}
+
+void cd5(void) __attribute__((constructor, destructor));
+
+void cd5() {
+ if (i != 3)
+ abort();
+ ++j;
+}
+
+int main (void) {
+ if (i != 3)
+ return 1;
+ if (j != 2)
+ abort ();
+ return 0;
+}
+
+#else /* !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) */
+
+int main (void) {
+ exit (0);
+}
+
+#endif /* !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) */
diff --git a/binutils-2.25/gold/testsuite/initpri2.c b/binutils-2.25/gold/testsuite/initpri2.c
new file mode 100644
index 00000000..525661f5
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/initpri2.c
@@ -0,0 +1,118 @@
+/* initpri2.c -- test mixing init_array and ctor priorities.
+
+ Copyright 2011 Free Software Foundation, Inc.
+ Copied from the gcc configury, where the test was contributed by
+ H.J. Lu <hongjiu.lu@intel.com>.
+
+ 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 tests that the linker correctly combines .ctor and .init_array
+ sections when both have priorities. */
+
+#include <stdlib.h>
+
+static int count;
+
+static void
+init1005 (void)
+{
+ if (count != 0)
+ abort ();
+ count = 1005;
+}
+void (*const init_array1005[]) (void)
+ __attribute__ ((section (".init_array.01005"), aligned (sizeof (void *))))
+ = { init1005 };
+static void
+fini1005 (void)
+{
+ if (count != 1005)
+ abort ();
+}
+void (*const fini_array1005[]) (void)
+ __attribute__ ((section (".fini_array.01005"), aligned (sizeof (void *))))
+ = { fini1005 };
+
+static void
+ctor1007 (void)
+{
+ if (count != 1005)
+ abort ();
+ count = 1007;
+}
+void (*const ctors1007[]) (void)
+ __attribute__ ((section (".ctors.64528"), aligned (sizeof (void *))))
+ = { ctor1007 };
+static void
+dtor1007 (void)
+{
+ if (count != 1007)
+ abort ();
+ count = 1005;
+}
+void (*const dtors1007[]) (void)
+ __attribute__ ((section (".dtors.64528"), aligned (sizeof (void *))))
+ = { dtor1007 };
+
+static void
+init65530 (void)
+{
+ if (count != 1007)
+ abort ();
+ count = 65530;
+}
+void (*const init_array65530[]) (void)
+ __attribute__ ((section (".init_array.65530"), aligned (sizeof (void *))))
+ = { init65530 };
+static void
+fini65530 (void)
+{
+ if (count != 65530)
+ abort ();
+ count = 1007;
+}
+void (*const fini_array65530[]) (void)
+ __attribute__ ((section (".fini_array.65530"), aligned (sizeof (void *))))
+ = { fini65530 };
+
+static void
+ctor65535 (void)
+{
+ if (count != 65530)
+ abort ();
+ count = 65535;
+}
+void (*const ctors65535[]) (void)
+ __attribute__ ((section (".ctors"), aligned (sizeof (void *))))
+ = { ctor65535 };
+static void
+dtor65535 (void)
+{
+ if (count != 65535)
+ abort ();
+ count = 65530;
+}
+void (*const dtors65535[]) (void)
+ __attribute__ ((section (".dtors"), aligned (sizeof (void *))))
+ = { dtor65535 };
+
+int
+main (void)
+{
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/initpri3.c b/binutils-2.25/gold/testsuite/initpri3.c
new file mode 100644
index 00000000..01e233d1
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/initpri3.c
@@ -0,0 +1,80 @@
+/* initpri3.c -- test ctor odering when using init_array.
+
+ Copyright 2011 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>.
+
+ 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 tests that the linker correctly orders .ctor entries when
+ putting them into .init_array, as is the default. */
+
+#include <assert.h>
+
+int i = 1;
+
+static void
+ctor1 (void)
+{
+ assert (i == 1);
+ i = 2;
+}
+
+static void
+ctor2 (void)
+{
+ assert (i == 2);
+ i = 3;
+}
+
+static void
+dtor1 (void)
+{
+ assert (i == 3);
+ i = 2;
+}
+
+static void
+dtor2 (void)
+{
+ assert (i == 2);
+ i = 1;
+}
+
+/* The .ctors section is run in reverse order, the .dtors section in
+ run in forward order. We give these arrays the "aligned" attribute
+ because the x86_64 ABI would otherwise give them a 16-byte
+ alignment, which may leave a hole in the section. */
+
+void (*ctors[]) (void)
+ __attribute__ ((aligned (4), section (".ctors"))) = {
+ ctor2,
+ ctor1
+};
+
+void (*dtors[]) (void)
+ __attribute__ ((aligned (4), section (".dtors"))) = {
+ dtor1,
+ dtor2
+};
+
+int
+main (void)
+{
+ assert (i == 3);
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/justsyms.t b/binutils-2.25/gold/testsuite/justsyms.t
new file mode 100644
index 00000000..45418be8
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/justsyms.t
@@ -0,0 +1,31 @@
+/* justsyms.t -- test --just-symbols for gold.
+
+ Copyright 2008 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>.
+
+ 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. */
+
+SECTIONS
+{
+ /* This script is only used for a .o file. */
+ . = 0x100;
+ .gold_test : { *(.gold_test) }
+ .text : { *(.text) }
+ .data : { *(.data) }
+ .bss : { *(.bss) }
+}
diff --git a/binutils-2.25/gold/testsuite/justsyms_1.cc b/binutils-2.25/gold/testsuite/justsyms_1.cc
new file mode 100644
index 00000000..50716b06
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/justsyms_1.cc
@@ -0,0 +1,54 @@
+// justsyms_1.cc -- test --just-symbols for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 Linux kernel builds an object file using a linker script, and
+// then links against that object file using the -R option. This is a
+// test for that usage.
+
+#include <cassert>
+#include <csignal>
+#include <cstddef>
+#include <cstdlib>
+#include <stdint.h>
+
+extern char justsyms_string[];
+
+// We expect to get a SIGSEGV.
+static void
+handle_sigsegv(int)
+{
+ exit(0);
+}
+
+int
+main(int, char**)
+{
+ // The linker script should arrange for this symbol to be exactly at
+ // address 0x10000.
+ assert(reinterpret_cast<uintptr_t>(justsyms_string) == 0x100);
+
+ // However, since the file was linked with --just-symbols, we should
+ // not be able to actually access the symbol.
+ signal(SIGSEGV, handle_sigsegv);
+ char c = justsyms_string[0];
+ exit(c == '\0' ? 1 : c);
+}
diff --git a/binutils-2.25/gold/testsuite/justsyms_2.cc b/binutils-2.25/gold/testsuite/justsyms_2.cc
new file mode 100644
index 00000000..dbbf4b54
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/justsyms_2.cc
@@ -0,0 +1,27 @@
+// justsyms_2.cc -- test --just-symbols for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 test goes with justsyms_1.cc. We compile this file, then
+// apply a linker script with -r to set the section addresses.
+
+char justsyms_string[] __attribute__ ((section(".gold_test"))) =
+ "justsyms string";
diff --git a/binutils-2.25/gold/testsuite/justsyms_exec.c b/binutils-2.25/gold/testsuite/justsyms_exec.c
new file mode 100644
index 00000000..66702863
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/justsyms_exec.c
@@ -0,0 +1,56 @@
+// justsyms_exec.c -- test --just-symbols for gold
+
+// Copyright 2011 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 Linux kernel builds an executable file using a linker script, and
+// then links against that object file using the -R option. This is a
+// test for that usage.
+
+#include <stdio.h>
+
+extern int exported_func(void);
+
+extern int exported_data;
+
+static int errs = 0;
+
+void check(void *sym, long v, const char *name);
+
+void
+check(void *sym, long v, const char *name)
+{
+ if (sym != (void *)v)
+ {
+ fprintf(stderr, "&%s is %8p, expected %08lx\n", name, sym, v);
+ errs++;
+ }
+}
+
+int
+main(void)
+{
+#ifndef __powerpc64__
+ /* PowerPC64 uses function descriptors. */
+ check(exported_func, 0x1000200, "exported_func");
+#endif
+ check(&exported_data, 0x2000000, "exported_data");
+ return errs;
+}
diff --git a/binutils-2.25/gold/testsuite/justsyms_lib.c b/binutils-2.25/gold/testsuite/justsyms_lib.c
new file mode 100644
index 00000000..9666fb78
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/justsyms_lib.c
@@ -0,0 +1,35 @@
+// justsyms_lib.cc -- test --just-symbols for gold
+
+// Copyright 2011 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 test goes with justsyms_exec.cc. We compile this file, then
+// link it into an executable image with -Ttext and -Tdata to set
+// the starting addresses for each segment.
+
+int exported_func(void);
+
+int exported_data = 0x1000;
+
+int
+exported_func(void)
+{
+ return 1;
+}
diff --git a/binutils-2.25/gold/testsuite/large.c b/binutils-2.25/gold/testsuite/large.c
new file mode 100644
index 00000000..796242a1
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/large.c
@@ -0,0 +1,59 @@
+/* large.c -- a test case for gold
+
+ Copyright 2009 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>.
+
+ 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 <assert.h>
+
+/* Test large sections in gold. */
+
+int v1;
+int v2 = 1;
+int v3[0x10000];
+int v4[0x10000] = { 1 };
+const int v5[0x10000] = { 2 };
+int v6;
+int v7 = 1;
+
+int
+main (int argc __attribute__ ((unused)), char** argv __attribute ((unused)))
+{
+ assert (v1 == 0);
+ assert (v2 == 1);
+ assert (v3[0] == 0 && v3[0xffff] == 0);
+ assert (v4[0] == 1 && v4[0xffff] == 0);
+ assert (v5[0] == 2 && v5[0xffff] == 0);
+ assert (v6 == 0);
+ assert (v7 == 1);
+
+ /* The large symbols must follow the small ones. */
+ assert (&v1 < v3 && &v1 < v4 && &v1 < v5);
+ assert (&v2 < v3 && &v2 < v4 && &v2 < v5);
+ assert (&v6 < v3 && &v6 < v4 && &v6 < v5);
+ assert (&v7 < v3 && &v7 < v4 && &v7 < v5);
+
+ /* Large symbols should be BSS followed by read-only followed by
+ read-write. */
+ assert (v3 < v4);
+ assert (v3 < v5);
+ assert (v5 < v4);
+
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/large_symbol_alignment.cc b/binutils-2.25/gold/testsuite/large_symbol_alignment.cc
new file mode 100644
index 00000000..1b4a63d4
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/large_symbol_alignment.cc
@@ -0,0 +1,49 @@
+// large_symbol_alignment.cc -- a test case for gold
+
+// Copyright 2013 Free Software Foundation, Inc.
+// Written by Alexander Ivchenko <alexander.ivchenko@intel.com>.
+
+// 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 goal of this program is to verify that Gold correctly aligns
+// the symbol with a large alignemnt (often larger than the page size).
+
+#include <stdint.h>
+
+__attribute__ ((aligned(8192))) int aligned_8k_var;
+__attribute__ ((aligned(4096))) int aligned_4k_var;
+__attribute__ ((aligned(16384))) int aligned_16k_var;
+
+bool
+is_aligned(const int& var, int align) __attribute__((noinline));
+
+bool
+is_aligned(const int& var, int align)
+{
+ return (reinterpret_cast<uintptr_t>(&var) & (align - 1)) == 0;
+}
+
+int
+main()
+{
+ if (!is_aligned(aligned_16k_var, 16384)
+ || !is_aligned(aligned_8k_var, 8192)
+ || !is_aligned(aligned_4k_var, 4096))
+ return 1;
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/leb128_unittest.cc b/binutils-2.25/gold/testsuite/leb128_unittest.cc
new file mode 100644
index 00000000..05c70937
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/leb128_unittest.cc
@@ -0,0 +1,88 @@
+// leb_unittest.cc -- test read_signed_LEB_128 and read_unsigned_LEB_128
+
+// Copyright 2012 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 <sys/types.h>
+
+#include "int_encoding.h"
+
+#include "test.h"
+
+namespace gold_testsuite
+{
+
+using namespace gold;
+
+bool
+Leb128_test(Test_report*)
+{
+ size_t len;
+
+ // Unsigned tests.
+ static unsigned char u1[] = { 0 }; // 0
+ static unsigned char u2[] = { 1 }; // 1
+ static unsigned char u3[] = { 126 }; // 126
+ static unsigned char u4[] = { 127 }; // 127
+ static unsigned char u5[] = { 0x80+0, 1 }; // 128
+ static unsigned char u6[] = { 0x80+1, 1 }; // 129
+ static unsigned char u7[] = { 0x80+57, 100 }; // 12857
+ static unsigned char u8[] = { 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80,
+ 0x80, 1}; // 1ULL << 63
+
+ // Signed tests.
+ static unsigned char s1[] = { 0 }; // 0
+ static unsigned char s2[] = { 1 }; // 1
+ static unsigned char s3[] = { 0x7e }; // -2
+ static unsigned char s4[] = { 0x80+127, 0 }; // 127
+ static unsigned char s5[] = { 0x80+1, 0x7f }; // -127
+ static unsigned char s6[] = { 0x80+0, 1 }; // 128
+ static unsigned char s7[] = { 0x80+0, 0x7f }; // -128
+ static unsigned char s8[] = { 0x80+1, 1 }; // 129
+ static unsigned char s9[] = { 0xff, 0x7e }; // -129
+
+ CHECK(read_unsigned_LEB_128(u1, &len) == 0 && len == sizeof(u1));
+ CHECK(read_unsigned_LEB_128(u2, &len) == 1 && len == sizeof(u2));
+ CHECK(read_unsigned_LEB_128(u3, &len) == 126 && len == sizeof(u3));
+ CHECK(read_unsigned_LEB_128(u4, &len) == 127 && len == sizeof(u4));
+ CHECK(read_unsigned_LEB_128(u5, &len) == 128 && len == sizeof(u5));
+ CHECK(read_unsigned_LEB_128(u6, &len) == 129 && len == sizeof(u6));
+ CHECK(read_unsigned_LEB_128(u7, &len) == 12857 && len == sizeof(u7));
+ CHECK(read_unsigned_LEB_128(u8, &len) == (1ULL << 63) && len == sizeof(u8));
+
+ CHECK(read_signed_LEB_128(s1, &len) == 0 && len == sizeof(s1));
+ CHECK(read_signed_LEB_128(s2, &len) == 1 && len == sizeof(s2));
+ CHECK(read_signed_LEB_128(s3, &len) == -2 && len == sizeof(s3));
+ CHECK(read_signed_LEB_128(s4, &len) == 127 && len == sizeof(s4));
+ CHECK(read_signed_LEB_128(s5, &len) == -127 && len == sizeof(s5));
+ CHECK(read_signed_LEB_128(s6, &len) == 128 && len == sizeof(s6));
+ CHECK(read_signed_LEB_128(s7, &len) == -128 && len == sizeof(s7));
+ CHECK(read_signed_LEB_128(s8, &len) == 129 && len == sizeof(s8));
+ CHECK(read_signed_LEB_128(s9, &len) == -129 && len == sizeof(s9));
+
+ return true;
+}
+
+Register_test leb128_register("LEB128", Leb128_test);
+
+} // End namespace gold_testsuite.
diff --git a/binutils-2.25/gold/testsuite/many_sections_test.cc b/binutils-2.25/gold/testsuite/many_sections_test.cc
new file mode 100644
index 00000000..e4b74c34
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/many_sections_test.cc
@@ -0,0 +1,51 @@
+// many_sections_test.cc -- test lots of sections for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 program tests having many sections. It uses a generated .h
+// files to define 70,000 variables, each in a different section. It
+// uses another generated .h file to verify that they all have the
+// right value.
+
+#include <cassert>
+
+#include "many_sections_define.h"
+
+// This tests a section group.
+template<typename T>
+class C
+{
+ public:
+ static T val() { return C::val_; }
+ private:
+ static T val_;
+};
+
+template<typename T>
+T C<T>::val_;
+
+int
+main(int, char**)
+{
+#include "many_sections_check.h"
+ assert(C<int>::val() == 0);
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/memory_test.s b/binutils-2.25/gold/testsuite/memory_test.s
new file mode 100644
index 00000000..ce8576c1
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/memory_test.s
@@ -0,0 +1,14 @@
+ .section .sec0, "a"
+ .long 0
+
+ .section .sec1, "a"
+ .long 0x11
+
+ .section .sec2, "a"
+ .long 0x22
+
+ .section .sec3, "a"
+ .long 0x33
+
+ .section .sec4, "a"
+ .long 0x44
diff --git a/binutils-2.25/gold/testsuite/memory_test.sh b/binutils-2.25/gold/testsuite/memory_test.sh
new file mode 100755
index 00000000..db3917a7
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/memory_test.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+# memory_test.sh -- test MEMORY regions.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Nick Clifton <nickc@redhat.com>
+
+# 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.
+
+
+# NOTE: The linker script used in this test (memory_test.t)
+# should be the same as the one used in the rgn-at5 linker
+# test (ld/testsuite/ld-scripts/rgn-at5.t).
+#
+# Modulo some section ordering the output from GOLD in this
+# test should be the same as the output from GNU LD in the
+# rgn-at5 test.
+
+check()
+{
+ file=$1
+ pattern=$2
+ found=`grep "$pattern" $file`
+ if test -z "$found"; then
+ echo "pattern \"$pattern\" not found in file $file."
+ echo $found
+ exit 1
+ fi
+}
+
+check memory_test.stdout \
+ " LOAD 0x001000 0x0*02000 0x0*02000 0x0*04 0x0*04 R 0x1000"
+check memory_test.stdout \
+ " LOAD 0x001004 0x0*01000 0x0*02004 0x0*04 0x0*04 R 0x1000"
+check memory_test.stdout \
+ " LOAD 0x001008 0x0*02008 0x0*02008 0x0*08 0x0*08 R 0x1000"
+check memory_test.stdout \
+ " LOAD 0x002000 0x0*05000 0x0*05000 0x0*04 0x0*04 R 0x1000"
+check memory_test.stdout \
+ " LOAD 0x00203c 0x0*04000 0x0*0603c 0x0*04 0x0*04 R 0x1000"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/memory_test.t b/binutils-2.25/gold/testsuite/memory_test.t
new file mode 100644
index 00000000..3a35994c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/memory_test.t
@@ -0,0 +1,26 @@
+MEMORY
+{
+ region1 : ORIGIN = 0x1000, LENGTH = 0x1000 ,
+ region2 (r) : org = 0x2000, len = 300
+ region3 (wx) : o = 0x4000, l = 4
+ region4 (!r) : o = 0x6000 + 60, len = 0x30 * 0x6
+}
+
+SECTIONS
+{
+ .sec0 : { *(*.sec0) }
+
+ .sec1 ORIGIN (region1) : { *(*.sec1) } AT> region2
+
+ fred = ORIGIN (region1) + LENGTH (region1);
+
+ .sec2 : { *(*.sec2) } > region3 AT> region4
+
+ .sec3 0x5000 : { *(*.sec3) }
+
+ .sec4 : { *(*.sec4) } AT> region2
+
+ .sec5 : { LONG(0x5555) } > region2
+
+ /DISCARD/ : { *(*) }
+}
diff --git a/binutils-2.25/gold/testsuite/merge_string_literals.sh b/binutils-2.25/gold/testsuite/merge_string_literals.sh
new file mode 100755
index 00000000..486a8959
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/merge_string_literals.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# merge_string_literals.sh -- test
+
+# Copyright 2013 Free Software Foundation, Inc.
+# Written by Alexander Ivchenko <alexander.ivchenko@intel.com>.
+
+# 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 goal of this program is to check whether string literals from different
+# object files are merged together
+
+set -e
+
+check()
+{
+ number_of_occurrence=`grep $2 ./$1 -o| wc -l`
+ if [ $number_of_occurrence != $3 ]
+ then
+ echo "String literals were not merged"
+ exit 1
+ fi
+}
+
+# If string literals were merged, then "abcd" appears two times
+check merge_string_literals.stdout "abcd" 2
diff --git a/binutils-2.25/gold/testsuite/merge_string_literals_1.cc b/binutils-2.25/gold/testsuite/merge_string_literals_1.cc
new file mode 100644
index 00000000..fc0487c3
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/merge_string_literals_1.cc
@@ -0,0 +1,31 @@
+// merge_string_literals_1.c -- a test case for gold
+
+// Copyright 2013 Free Software Foundation, Inc.
+// Written by Alexander Ivchenko <alexander.ivchenko@intel.com>
+
+// 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 goal of this program is to check whether string literals from different
+// object files are merged together
+
+const char* bar1() {
+ return "abcdefghijklmnopqrstuvwxyz0123456789";
+}
+const char* bar1_short() {
+ return "abcdef";
+}
diff --git a/binutils-2.25/gold/testsuite/merge_string_literals_2.cc b/binutils-2.25/gold/testsuite/merge_string_literals_2.cc
new file mode 100644
index 00000000..d1185cde
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/merge_string_literals_2.cc
@@ -0,0 +1,31 @@
+// merge_string_literals_2.c -- a test case for gold
+
+// Copyright 2013 Free Software Foundation, Inc.
+// Written by Alexander Ivchenko <alexander.ivchenko@intel.com>
+
+// 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 goal of this program is to check whether string literals from different
+// object files are merged together
+
+const char* bar2() {
+ return "abcdefghijklmnopqrstuvwxyz0123456789";
+}
+const char* bar2_short() {
+ return "abcdef";
+}
diff --git a/binutils-2.25/gold/testsuite/missing_key_func.cc b/binutils-2.25/gold/testsuite/missing_key_func.cc
new file mode 100644
index 00000000..5a5b7d95
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/missing_key_func.cc
@@ -0,0 +1,46 @@
+// basic_test.cc -- a test case for gold
+
+// Copyright 2013 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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.
+
+// Define a class, but leave its key function undefined.
+
+class C
+{
+ public:
+ C() : c(1) { }
+ virtual void set();
+ virtual void clear();
+ int c;
+};
+
+void
+C::clear()
+{
+ c = 0;
+}
+
+int
+main()
+{
+ C c;
+ c.clear();
+ return c.c;
+}
diff --git a/binutils-2.25/gold/testsuite/missing_key_func.sh b/binutils-2.25/gold/testsuite/missing_key_func.sh
new file mode 100755
index 00000000..54c7b57b
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/missing_key_func.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+# missing_key_func.sh -- a test case for printing error messages when
+# a class is missing its key function.
+
+# Copyright 2013 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>
+
+# 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 goes with debug_msg.cc, a C++ source file constructed to
+# have undefined references. We compile that file with debug
+# information and then try to link it, and make sure the proper errors
+# are displayed. The errors will be found in debug_msg.err.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected error in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual error output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check_missing()
+{
+ if grep -q "$2" "$1"
+ then
+ echo "Found unexpected error in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual error output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check missing_key_func.err "error: undefined reference to 'vtable for C'"
+check missing_key_func.err "class is missing its key function"
diff --git a/binutils-2.25/gold/testsuite/no_version_test.c b/binutils-2.25/gold/testsuite/no_version_test.c
new file mode 100644
index 00000000..e42d04f0
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/no_version_test.c
@@ -0,0 +1,32 @@
+// ver_no_default.c -- a test case for gold
+
+// Copyright 2009 Free Software Foundation, Inc.
+// Written by Doug Kwan <dougkwan@google.com>.
+
+// 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 should not create any .gnu.version sections if symbol versioning
+// is not used.
+
+extern int the_answer(void);
+
+int
+the_answer(void)
+{
+ return 42;
+}
diff --git a/binutils-2.25/gold/testsuite/no_version_test.sh b/binutils-2.25/gold/testsuite/no_version_test.sh
new file mode 100755
index 00000000..f4ca9b10
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/no_version_test.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# no_version_test.sh -- test that .gnu.version* sections are not created
+# in a shared object when symbol versioning is not used.
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>
+
+# 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 goes with no_version_test.c, a C source file
+# linked with option -shared -nostdlib. We run objdump on
+# the resulting executable and check that .gnu.version* sections
+# are not created.
+
+check()
+{
+ file=$1
+
+ found=`egrep "\.gnu\.version.*" $file`
+ if test -n "$found"; then
+ echo "These section should not be in $file:"
+ echo "$found"
+ exit 1
+ fi
+}
+
+check "no_version_test.stdout"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/object_unittest.cc b/binutils-2.25/gold/testsuite/object_unittest.cc
new file mode 100644
index 00000000..7dedeaef
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/object_unittest.cc
@@ -0,0 +1,105 @@
+// object_unittest.cc -- test Object, Relobj, etc.
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 "options.h"
+#include "parameters.h"
+
+#include "test.h"
+#include "testfile.h"
+
+namespace gold_testsuite
+{
+
+using namespace gold;
+
+// Test basic Object functionality.
+
+template<int size, bool big_endian>
+bool
+Sized_object_test(const unsigned char* test_file, unsigned int test_file_size)
+{
+ parameters_clear_target();
+ // We need a pretend Task.
+ const Task* task = reinterpret_cast<const Task*>(-1);
+ Input_file input_file(task, "test.o", test_file, test_file_size);
+ Object* object = make_elf_object("test.o", &input_file, 0,
+ test_file, test_file_size, NULL);
+ CHECK(object->name() == "test.o");
+ CHECK(!object->is_dynamic());
+ CHECK(object->is_locked());
+ object->unlock(task);
+ CHECK(!object->is_locked());
+ object->lock(task);
+ CHECK(object->shnum() == 5);
+ CHECK(object->section_name(0).empty());
+ CHECK(object->section_name(1) == ".test");
+ CHECK(object->section_flags(0) == 0);
+ CHECK(object->section_flags(1) == elfcpp::SHF_ALLOC);
+ object->unlock(task);
+ return true;
+}
+
+bool
+Object_test(Test_report*)
+{
+ General_options options;
+ int fail = 0;
+
+ set_parameters_options(&options);
+
+#ifdef HAVE_TARGET_32_LITTLE
+ if (!Sized_object_test<32, false>(test_file_1_32_little,
+ test_file_1_size_32_little))
+ ++fail;
+ CHECK(&parameters->target() == target_test_pointer_32_little);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+ if (!Sized_object_test<32, true>(test_file_1_32_big,
+ test_file_1_size_32_big))
+ ++fail;
+ CHECK(&parameters->target() == target_test_pointer_32_big);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+ if (!Sized_object_test<64, false>(test_file_1_64_little,
+ test_file_1_size_64_little))
+ ++fail;
+ CHECK(&parameters->target() == target_test_pointer_64_little);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+ if (!Sized_object_test<64, true>(test_file_1_64_big,
+ test_file_1_size_64_big))
+ ++fail;
+ CHECK(&parameters->target() == target_test_pointer_64_big);
+#endif
+
+ return fail == 0;
+}
+
+Register_test object_register("Object", Object_test);
+
+} // End namespace gold_testsuite.
diff --git a/binutils-2.25/gold/testsuite/odr_header1.h b/binutils-2.25/gold/testsuite/odr_header1.h
new file mode 100644
index 00000000..3d9c4880
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/odr_header1.h
@@ -0,0 +1,6 @@
+#include "odr_header2.h"
+
+struct OdrDerived : OdrBase {
+ ~OdrDerived() {
+ }
+};
diff --git a/binutils-2.25/gold/testsuite/odr_header2.h b/binutils-2.25/gold/testsuite/odr_header2.h
new file mode 100644
index 00000000..0fb9449a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/odr_header2.h
@@ -0,0 +1,4 @@
+struct OdrBase {
+ virtual ~OdrBase() {
+ }
+};
diff --git a/binutils-2.25/gold/testsuite/odr_violation1.cc b/binutils-2.25/gold/testsuite/odr_violation1.cc
new file mode 100644
index 00000000..8b37cea7
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/odr_violation1.cc
@@ -0,0 +1,23 @@
+#include <algorithm>
+#include "odr_header1.h"
+
+class Ordering {
+ public:
+ bool operator()(int a, int b) {
+ return a < b;
+ }
+};
+
+void SortAscending(int array[], int size) {
+ std::sort(array, array + size, Ordering());
+}
+
+extern "C" int OverriddenCFunction(int i) __attribute__ ((weak));
+extern "C" int OverriddenCFunction(int i) {
+ return i;
+}
+
+// Instantiate the Derived vtable, without optimization.
+OdrBase* CreateOdrDerived1() {
+ return new OdrDerived;
+}
diff --git a/binutils-2.25/gold/testsuite/odr_violation2.cc b/binutils-2.25/gold/testsuite/odr_violation2.cc
new file mode 100644
index 00000000..e3d30f39
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/odr_violation2.cc
@@ -0,0 +1,34 @@
+#include <algorithm>
+#include "odr_header1.h"
+
+class Ordering {
+ public:
+ bool operator()(int a, int b) __attribute__((never_inline));
+};
+
+// This comment makes the line numbers in Ordering::operator() all have
+// two digits, which causes gold's output to be independent of which
+// instruction the compiler optimizes into the front of the function.
+bool Ordering::operator()(int a, int b) {
+ // Optimization makes this operator() a different size than the one
+ // in odr_violation1.cc.
+ return a + 12345 > b / 67;
+}
+
+void SortDescending(int array[], int size) {
+ std::sort(array, array + size, Ordering());
+}
+
+// This is weak in odr_violation1.cc.
+extern "C" int OverriddenCFunction(int i) {
+ return i * i;
+}
+// This is inline in debug_msg.cc, which makes it a weak symbol too.
+int SometimesInlineFunction(int i) {
+ return i * i;
+}
+
+// Instantiate the Derived vtable, with optimization (see Makefile.am).
+OdrBase* CreateOdrDerived2() {
+ return new OdrDerived;
+}
diff --git a/binutils-2.25/gold/testsuite/plugin_common_test_1.c b/binutils-2.25/gold/testsuite/plugin_common_test_1.c
new file mode 100644
index 00000000..262c2985
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_common_test_1.c
@@ -0,0 +1,48 @@
+/* plugin_common_test_1.c -- test common symbol handling in plugins
+
+ Copyright 2010 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@google.com>
+
+ 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 is a test of common symbols in plugin objects. C1-C5 test
+ various combinations of tentative definitions, extern declarations,
+ and definitions. */
+
+#include <assert.h>
+
+int c1;
+int c2;
+extern int c3;
+int c4;
+int c5 = 50;
+
+extern void foo (void);
+
+int
+main (int argc __attribute__ ((unused)), char** argv __attribute__ ((unused)))
+{
+ foo();
+
+ assert (c1 == 10);
+ assert (c2 == 20);
+ assert (c3 == 30);
+ assert (c4 == 40);
+
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/plugin_common_test_2.c b/binutils-2.25/gold/testsuite/plugin_common_test_2.c
new file mode 100644
index 00000000..54139ceb
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_common_test_2.c
@@ -0,0 +1,45 @@
+/* plugin_common_test_2.c -- test common symbol handling in plugins
+
+ Copyright 2010 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@google.com>
+
+ 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 is a test of common symbols in plugin objects. C1-C5 test
+ various combinations of tentative definitions, extern declarations,
+ and definitions. */
+
+#include <assert.h>
+
+int c1;
+extern int c2;
+int c3;
+int c4 = 40;
+int c5;
+
+extern void foo (void);
+
+void
+foo (void)
+{
+ c1 = 10;
+ c2 = 20;
+ c3 = 30;
+
+ assert (c5 == 50);
+}
diff --git a/binutils-2.25/gold/testsuite/plugin_final_layout.cc b/binutils-2.25/gold/testsuite/plugin_final_layout.cc
new file mode 100644
index 00000000..169eeefd
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_final_layout.cc
@@ -0,0 +1,47 @@
+// plugin_final_layout.cc -- a test case for gold
+
+// Copyright 2011 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify if section ordering
+// via plugins happens correctly. Also, test if plugin based ordering
+// overrides default text section ordering where ".text.hot" sections
+// are grouped. The plugin does not want foo and baz next to each other.
+// Plugin section order is foo() followed by bar() and then baz().
+
+__attribute__ ((section(".text._Z3barv")))
+void bar ()
+{
+}
+
+__attribute__ ((section(".text.hot._Z3bazv")))
+void baz ()
+{
+}
+
+__attribute__ ((section(".text.hot._Z3foov")))
+void foo ()
+{
+}
+
+int main ()
+{
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/plugin_final_layout.sh b/binutils-2.25/gold/testsuite/plugin_final_layout.sh
new file mode 100755
index 00000000..75a40d3c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_final_layout.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+
+# plugin_final_layout.sh -- test
+
+# Copyright 2011 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# 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 goal of this program is to verify if --section-ordering-file works as
+# intended. File final_layout.cc is in this test.
+
+
+set -e
+
+check()
+{
+ awk "
+BEGIN { saw1 = 0; saw2 = 0; err = 0; }
+/.*$2\$/ { saw1 = 1; }
+/.*$3\$/ {
+ saw2 = 1;
+ if (!saw1)
+ {
+ printf \"layout of $2 and $3 is not right\\n\";
+ err = 1;
+ exit 1;
+ }
+ }
+END {
+ if (!saw1 && !err)
+ {
+ printf \"did not see $2\\n\";
+ exit 1;
+ }
+ if (!saw2 && !err)
+ {
+ printf \"did not see $3\\n\";
+ exit 1;
+ }
+ }" $1
+}
+
+# With readelf -l, an ELF Section to Segment mapping is printed as :
+##############################################
+# Section to Segment mapping:
+# Segment Sections...
+# ...
+# 0x .text.plugin_created_unique
+# ...
+##############################################
+# Check of .text.plugin_created_unique is the only section in the segment.
+check_unique_segment()
+{
+ awk "
+BEGIN { saw_section = 0; saw_unique = 0; }
+/$2/ { saw_section = 1; }
+/[ ]*0[0-9][ ]*$2[ ]*\$/ { saw_unique = 1; }
+END {
+ if (!saw_section)
+ {
+ printf \"Section $2 not seen in output\\n\";
+ exit 1;
+ }
+ else if (!saw_unique)
+ {
+ printf \"Unique segment not seen for: $2\\n\";
+ exit 1;
+ }
+ }" $1
+}
+
+check plugin_final_layout.stdout "_Z3foov" "_Z3barv"
+check plugin_final_layout.stdout "_Z3barv" "_Z3bazv"
+check_unique_segment plugin_final_layout_readelf.stdout ".text.plugin_created_unique"
diff --git a/binutils-2.25/gold/testsuite/plugin_section_order.c b/binutils-2.25/gold/testsuite/plugin_section_order.c
new file mode 100644
index 00000000..fdc6fe4e
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_section_order.c
@@ -0,0 +1,188 @@
+/* plugin_section_reorder.c -- Simple plugin to reorder function sections
+
+ Copyright 2011 Free Software Foundation, Inc.
+ Written by Sriraman Tallam <tmsriram@google.com>.
+
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "plugin-api.h"
+
+static ld_plugin_get_input_section_count get_input_section_count = NULL;
+static ld_plugin_get_input_section_type get_input_section_type = NULL;
+static ld_plugin_get_input_section_name get_input_section_name = NULL;
+static ld_plugin_get_input_section_contents get_input_section_contents = NULL;
+static ld_plugin_update_section_order update_section_order = NULL;
+static ld_plugin_allow_section_ordering allow_section_ordering = NULL;
+static ld_plugin_allow_unique_segment_for_sections
+ allow_unique_segment_for_sections = NULL;
+static ld_plugin_unique_segment_for_sections unique_segment_for_sections = NULL;
+
+enum ld_plugin_status onload(struct ld_plugin_tv *tv);
+enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file,
+ int *claimed);
+enum ld_plugin_status all_symbols_read_hook(void);
+
+/* Plugin entry point. */
+enum ld_plugin_status
+onload(struct ld_plugin_tv *tv)
+{
+ struct ld_plugin_tv *entry;
+ for (entry = tv; entry->tv_tag != LDPT_NULL; ++entry)
+ {
+ switch (entry->tv_tag)
+ {
+ case LDPT_REGISTER_CLAIM_FILE_HOOK:
+ assert((*entry->tv_u.tv_register_claim_file) (claim_file_hook)
+ == LDPS_OK);
+ break;
+ case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
+ assert((*entry->tv_u.tv_register_all_symbols_read)
+ (all_symbols_read_hook)
+ == LDPS_OK);
+ break;
+ case LDPT_GET_INPUT_SECTION_COUNT:
+ get_input_section_count = *entry->tv_u.tv_get_input_section_count;
+ break;
+ case LDPT_GET_INPUT_SECTION_TYPE:
+ get_input_section_type = *entry->tv_u.tv_get_input_section_type;
+ break;
+ case LDPT_GET_INPUT_SECTION_NAME:
+ get_input_section_name = *entry->tv_u.tv_get_input_section_name;
+ break;
+ case LDPT_GET_INPUT_SECTION_CONTENTS:
+ get_input_section_contents
+ = *entry->tv_u.tv_get_input_section_contents;
+ break;
+ case LDPT_UPDATE_SECTION_ORDER:
+ update_section_order = *entry->tv_u.tv_update_section_order;
+ break;
+ case LDPT_ALLOW_SECTION_ORDERING:
+ allow_section_ordering = *entry->tv_u.tv_allow_section_ordering;
+ break;
+ case LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS:
+ allow_unique_segment_for_sections
+ = *entry->tv_u.tv_allow_unique_segment_for_sections;
+ case LDPT_UNIQUE_SEGMENT_FOR_SECTIONS:
+ unique_segment_for_sections
+ = *entry->tv_u.tv_unique_segment_for_sections;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (get_input_section_count == NULL
+ || get_input_section_type == NULL
+ || get_input_section_name == NULL
+ || get_input_section_contents == NULL
+ || update_section_order == NULL
+ || allow_section_ordering == NULL
+ || allow_unique_segment_for_sections == NULL
+ || unique_segment_for_sections == NULL)
+ {
+ fprintf(stderr, "Some interfaces are missing\n");
+ return LDPS_ERR;
+ }
+
+ return LDPS_OK;
+}
+
+inline static int is_prefix_of(const char *prefix, const char *str)
+{
+ return strncmp(prefix, str, strlen (prefix)) == 0;
+}
+
+struct ld_plugin_section section_list[3];
+int num_entries = 0;
+
+/* This function is called by the linker for every new object it encounters. */
+enum ld_plugin_status
+claim_file_hook(const struct ld_plugin_input_file *file, int *claimed)
+{
+ static int is_ordering_specified = 0;
+ struct ld_plugin_section section;
+ unsigned int count = 0;
+ unsigned int shndx;
+
+ *claimed = 0;
+ if (is_ordering_specified == 0)
+ {
+ /* Inform the linker to prepare for section reordering. */
+ (*allow_section_ordering)();
+ /* Inform the linker to prepare to map some sections to unique
+ segments. */
+ (*allow_unique_segment_for_sections)();
+ is_ordering_specified = 1;
+ }
+
+ (*get_input_section_count)(file->handle, &count);
+
+ for (shndx = 0; shndx < count; ++shndx)
+ {
+ char *name = NULL;
+ int position = 3;
+
+ section.handle = file->handle;
+ section.shndx = shndx;
+ (*get_input_section_name)(section, &name);
+
+ /* Order is foo() followed by bar() followed by baz() */
+ if (is_prefix_of(".text.", name))
+ {
+ if (strstr(name, "_Z3foov") != NULL)
+ position = 0;
+ else if (strstr(name, "_Z3barv") != NULL)
+ position = 1;
+ else if (strstr(name, "_Z3bazv") != NULL)
+ position = 2;
+ else
+ position = 3;
+ }
+ if (position < 3)
+ {
+ section_list[position].handle = file->handle;
+ section_list[position].shndx = shndx;
+ num_entries++;
+ }
+ }
+ return LDPS_OK;
+}
+
+/* This function is called by the linker after all the symbols have been read.
+ At this stage, it is fine to tell the linker the desired function order. */
+
+enum ld_plugin_status
+all_symbols_read_hook(void)
+{
+ if (num_entries == 3)
+ {
+ update_section_order(section_list, num_entries);
+ unique_segment_for_sections (".text.plugin_created_unique", 0, 0x1000,
+ section_list, num_entries);
+ }
+
+ return LDPS_OK;
+}
diff --git a/binutils-2.25/gold/testsuite/plugin_test.c b/binutils-2.25/gold/testsuite/plugin_test.c
new file mode 100644
index 00000000..47d400a0
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_test.c
@@ -0,0 +1,600 @@
+/* test_plugin.c -- simple linker plugin test
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@google.com>.
+
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "plugin-api.h"
+
+struct claimed_file
+{
+ const char* name;
+ void* handle;
+ int nsyms;
+ struct ld_plugin_symbol* syms;
+ struct claimed_file* next;
+};
+
+struct sym_info
+{
+ int size;
+ char* type;
+ char* bind;
+ char* vis;
+ char* sect;
+ char* name;
+};
+
+static struct claimed_file* first_claimed_file = NULL;
+static struct claimed_file* last_claimed_file = NULL;
+
+static ld_plugin_register_claim_file register_claim_file_hook = NULL;
+static ld_plugin_register_all_symbols_read register_all_symbols_read_hook = NULL;
+static ld_plugin_register_cleanup register_cleanup_hook = NULL;
+static ld_plugin_add_symbols add_symbols = NULL;
+static ld_plugin_get_symbols get_symbols = NULL;
+static ld_plugin_get_symbols get_symbols_v2 = NULL;
+static ld_plugin_add_input_file add_input_file = NULL;
+static ld_plugin_message message = NULL;
+static ld_plugin_get_input_file get_input_file = NULL;
+static ld_plugin_release_input_file release_input_file = NULL;
+static ld_plugin_get_input_section_count get_input_section_count = NULL;
+static ld_plugin_get_input_section_type get_input_section_type = NULL;
+static ld_plugin_get_input_section_name get_input_section_name = NULL;
+static ld_plugin_get_input_section_contents get_input_section_contents = NULL;
+static ld_plugin_update_section_order update_section_order = NULL;
+static ld_plugin_allow_section_ordering allow_section_ordering = NULL;
+
+#define MAXOPTS 10
+
+static const char *opts[MAXOPTS];
+static int nopts = 0;
+
+enum ld_plugin_status onload(struct ld_plugin_tv *tv);
+enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file,
+ int *claimed);
+enum ld_plugin_status all_symbols_read_hook(void);
+enum ld_plugin_status cleanup_hook(void);
+
+static void parse_readelf_line(char*, struct sym_info*);
+
+enum ld_plugin_status
+onload(struct ld_plugin_tv *tv)
+{
+ struct ld_plugin_tv *entry;
+ int api_version = 0;
+ int gold_version = 0;
+ int i;
+
+ for (entry = tv; entry->tv_tag != LDPT_NULL; ++entry)
+ {
+ switch (entry->tv_tag)
+ {
+ case LDPT_API_VERSION:
+ api_version = entry->tv_u.tv_val;
+ break;
+ case LDPT_GOLD_VERSION:
+ gold_version = entry->tv_u.tv_val;
+ break;
+ case LDPT_LINKER_OUTPUT:
+ break;
+ case LDPT_OPTION:
+ if (nopts < MAXOPTS)
+ opts[nopts++] = entry->tv_u.tv_string;
+ break;
+ case LDPT_REGISTER_CLAIM_FILE_HOOK:
+ register_claim_file_hook = entry->tv_u.tv_register_claim_file;
+ break;
+ case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
+ register_all_symbols_read_hook =
+ entry->tv_u.tv_register_all_symbols_read;
+ break;
+ case LDPT_REGISTER_CLEANUP_HOOK:
+ register_cleanup_hook = entry->tv_u.tv_register_cleanup;
+ break;
+ case LDPT_ADD_SYMBOLS:
+ add_symbols = entry->tv_u.tv_add_symbols;
+ break;
+ case LDPT_GET_SYMBOLS:
+ get_symbols = entry->tv_u.tv_get_symbols;
+ break;
+ case LDPT_GET_SYMBOLS_V2:
+ get_symbols_v2 = entry->tv_u.tv_get_symbols;
+ break;
+ case LDPT_ADD_INPUT_FILE:
+ add_input_file = entry->tv_u.tv_add_input_file;
+ break;
+ case LDPT_MESSAGE:
+ message = entry->tv_u.tv_message;
+ break;
+ case LDPT_GET_INPUT_FILE:
+ get_input_file = entry->tv_u.tv_get_input_file;
+ break;
+ case LDPT_RELEASE_INPUT_FILE:
+ release_input_file = entry->tv_u.tv_release_input_file;
+ break;
+ case LDPT_GET_INPUT_SECTION_COUNT:
+ get_input_section_count = *entry->tv_u.tv_get_input_section_count;
+ break;
+ case LDPT_GET_INPUT_SECTION_TYPE:
+ get_input_section_type = *entry->tv_u.tv_get_input_section_type;
+ break;
+ case LDPT_GET_INPUT_SECTION_NAME:
+ get_input_section_name = *entry->tv_u.tv_get_input_section_name;
+ break;
+ case LDPT_GET_INPUT_SECTION_CONTENTS:
+ get_input_section_contents = *entry->tv_u.tv_get_input_section_contents;
+ break;
+ case LDPT_UPDATE_SECTION_ORDER:
+ update_section_order = *entry->tv_u.tv_update_section_order;
+ break;
+ case LDPT_ALLOW_SECTION_ORDERING:
+ allow_section_ordering = *entry->tv_u.tv_allow_section_ordering;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (message == NULL)
+ {
+ fprintf(stderr, "tv_message interface missing\n");
+ return LDPS_ERR;
+ }
+
+ if (register_claim_file_hook == NULL)
+ {
+ fprintf(stderr, "tv_register_claim_file_hook interface missing\n");
+ return LDPS_ERR;
+ }
+
+ if (register_all_symbols_read_hook == NULL)
+ {
+ fprintf(stderr, "tv_register_all_symbols_read_hook interface missing\n");
+ return LDPS_ERR;
+ }
+
+ if (register_cleanup_hook == NULL)
+ {
+ fprintf(stderr, "tv_register_cleanup_hook interface missing\n");
+ return LDPS_ERR;
+ }
+
+ (*message)(LDPL_INFO, "API version: %d", api_version);
+ (*message)(LDPL_INFO, "gold version: %d", gold_version);
+
+ for (i = 0; i < nopts; ++i)
+ (*message)(LDPL_INFO, "option: %s", opts[i]);
+
+ if ((*register_claim_file_hook)(claim_file_hook) != LDPS_OK)
+ {
+ (*message)(LDPL_ERROR, "error registering claim file hook");
+ return LDPS_ERR;
+ }
+
+ if ((*register_all_symbols_read_hook)(all_symbols_read_hook) != LDPS_OK)
+ {
+ (*message)(LDPL_ERROR, "error registering all symbols read hook");
+ return LDPS_ERR;
+ }
+
+ if ((*register_cleanup_hook)(cleanup_hook) != LDPS_OK)
+ {
+ (*message)(LDPL_ERROR, "error registering cleanup hook");
+ return LDPS_ERR;
+ }
+
+ if (get_input_section_count == NULL)
+ {
+ fprintf(stderr, "tv_get_input_section_count interface missing\n");
+ return LDPS_ERR;
+ }
+
+ if (get_input_section_type == NULL)
+ {
+ fprintf(stderr, "tv_get_input_section_type interface missing\n");
+ return LDPS_ERR;
+ }
+
+ if (get_input_section_name == NULL)
+ {
+ fprintf(stderr, "tv_get_input_section_name interface missing\n");
+ return LDPS_ERR;
+ }
+
+ if (get_input_section_contents == NULL)
+ {
+ fprintf(stderr, "tv_get_input_section_contents interface missing\n");
+ return LDPS_ERR;
+ }
+
+ if (update_section_order == NULL)
+ {
+ fprintf(stderr, "tv_update_section_order interface missing\n");
+ return LDPS_ERR;
+ }
+
+ if (allow_section_ordering == NULL)
+ {
+ fprintf(stderr, "tv_allow_section_ordering interface missing\n");
+ return LDPS_ERR;
+ }
+
+ return LDPS_OK;
+}
+
+enum ld_plugin_status
+claim_file_hook (const struct ld_plugin_input_file* file, int* claimed)
+{
+ int len;
+ off_t end_offset;
+ char buf[160];
+ struct claimed_file* claimed_file;
+ struct ld_plugin_symbol* syms;
+ int nsyms = 0;
+ int maxsyms = 0;
+ FILE* irfile;
+ struct sym_info info;
+ int weak;
+ int def;
+ int vis;
+ int is_comdat;
+ int i;
+
+ (*message)(LDPL_INFO,
+ "%s: claim file hook called (offset = %ld, size = %ld)",
+ file->name, (long)file->offset, (long)file->filesize);
+
+ /* Look for the beginning of output from readelf -s. */
+ irfile = fdopen(file->fd, "r");
+ (void)fseek(irfile, file->offset, SEEK_SET);
+ end_offset = file->offset + file->filesize;
+ len = fread(buf, 1, 13, irfile);
+ if (len < 13 || strncmp(buf, "\nSymbol table", 13) != 0)
+ return LDPS_OK;
+
+ /* Skip the two header lines. */
+ (void) fgets(buf, sizeof(buf), irfile);
+ (void) fgets(buf, sizeof(buf), irfile);
+
+ if (add_symbols == NULL)
+ {
+ fprintf(stderr, "tv_add_symbols interface missing\n");
+ return LDPS_ERR;
+ }
+
+ /* Parse the output from readelf. The columns are:
+ Index Value Size Type Binding Visibility Section Name. */
+ syms = (struct ld_plugin_symbol*)malloc(sizeof(struct ld_plugin_symbol) * 8);
+ if (syms == NULL)
+ return LDPS_ERR;
+ maxsyms = 8;
+ while (ftell(irfile) < end_offset
+ && fgets(buf, sizeof(buf), irfile) != NULL)
+ {
+ parse_readelf_line(buf, &info);
+
+ /* Ignore local symbols. */
+ if (strncmp(info.bind, "LOCAL", 5) == 0)
+ continue;
+
+ weak = strncmp(info.bind, "WEAK", 4) == 0;
+ if (strncmp(info.sect, "UND", 3) == 0)
+ def = weak ? LDPK_WEAKUNDEF : LDPK_UNDEF;
+ else if (strncmp(info.sect, "COM", 3) == 0)
+ def = LDPK_COMMON;
+ else
+ def = weak ? LDPK_WEAKDEF : LDPK_DEF;
+
+ if (strncmp(info.vis, "INTERNAL", 8) == 0)
+ vis = LDPV_INTERNAL;
+ else if (strncmp(info.vis, "HIDDEN", 6) == 0)
+ vis = LDPV_HIDDEN;
+ else if (strncmp(info.vis, "PROTECTED", 9) == 0)
+ vis = LDPV_PROTECTED;
+ else
+ vis = LDPV_DEFAULT;
+
+ /* If the symbol is listed in the options list, special-case
+ it as a comdat symbol. */
+ is_comdat = 0;
+ for (i = 0; i < nopts; ++i)
+ {
+ if (info.name != NULL && strcmp(info.name, opts[i]) == 0)
+ {
+ is_comdat = 1;
+ break;
+ }
+ }
+
+ if (nsyms >= maxsyms)
+ {
+ syms = (struct ld_plugin_symbol*)
+ realloc(syms, sizeof(struct ld_plugin_symbol) * maxsyms * 2);
+ if (syms == NULL)
+ return LDPS_ERR;
+ maxsyms *= 2;
+ }
+
+ if (info.name == NULL)
+ syms[nsyms].name = NULL;
+ else
+ {
+ len = strlen(info.name);
+ syms[nsyms].name = malloc(len + 1);
+ strncpy(syms[nsyms].name, info.name, len + 1);
+ }
+ syms[nsyms].version = NULL;
+ syms[nsyms].def = def;
+ syms[nsyms].visibility = vis;
+ syms[nsyms].size = info.size;
+ syms[nsyms].comdat_key = is_comdat ? syms[nsyms].name : NULL;
+ syms[nsyms].resolution = LDPR_UNKNOWN;
+ ++nsyms;
+ }
+
+ claimed_file = (struct claimed_file*) malloc(sizeof(struct claimed_file));
+ if (claimed_file == NULL)
+ return LDPS_ERR;
+
+ claimed_file->name = file->name;
+ claimed_file->handle = file->handle;
+ claimed_file->nsyms = nsyms;
+ claimed_file->syms = syms;
+ claimed_file->next = NULL;
+ if (last_claimed_file == NULL)
+ first_claimed_file = claimed_file;
+ else
+ last_claimed_file->next = claimed_file;
+ last_claimed_file = claimed_file;
+
+ (*message)(LDPL_INFO, "%s: claiming file, adding %d symbols",
+ file->name, nsyms);
+
+ if (nsyms > 0)
+ (*add_symbols)(file->handle, nsyms, syms);
+
+ *claimed = 1;
+ return LDPS_OK;
+}
+
+enum ld_plugin_status
+all_symbols_read_hook(void)
+{
+ int i;
+ const char* res;
+ struct claimed_file* claimed_file;
+ struct ld_plugin_input_file file;
+ FILE* irfile;
+ off_t end_offset;
+ struct sym_info info;
+ int len;
+ char buf[160];
+ char* p;
+ const char* filename;
+
+ (*message)(LDPL_INFO, "all symbols read hook called");
+
+ if (get_symbols_v2 == NULL)
+ {
+ fprintf(stderr, "tv_get_symbols (v2) interface missing\n");
+ return LDPS_ERR;
+ }
+
+ for (claimed_file = first_claimed_file;
+ claimed_file != NULL;
+ claimed_file = claimed_file->next)
+ {
+ (*get_symbols_v2)(claimed_file->handle, claimed_file->nsyms,
+ claimed_file->syms);
+
+ for (i = 0; i < claimed_file->nsyms; ++i)
+ {
+ switch (claimed_file->syms[i].resolution)
+ {
+ case LDPR_UNKNOWN:
+ res = "UNKNOWN";
+ break;
+ case LDPR_UNDEF:
+ res = "UNDEF";
+ break;
+ case LDPR_PREVAILING_DEF:
+ res = "PREVAILING_DEF_REG";
+ break;
+ case LDPR_PREVAILING_DEF_IRONLY:
+ res = "PREVAILING_DEF_IRONLY";
+ break;
+ case LDPR_PREVAILING_DEF_IRONLY_EXP:
+ res = "PREVAILING_DEF_IRONLY_EXP";
+ break;
+ case LDPR_PREEMPTED_REG:
+ res = "PREEMPTED_REG";
+ break;
+ case LDPR_PREEMPTED_IR:
+ res = "PREEMPTED_IR";
+ break;
+ case LDPR_RESOLVED_IR:
+ res = "RESOLVED_IR";
+ break;
+ case LDPR_RESOLVED_EXEC:
+ res = "RESOLVED_EXEC";
+ break;
+ case LDPR_RESOLVED_DYN:
+ res = "RESOLVED_DYN";
+ break;
+ default:
+ res = "?";
+ break;
+ }
+ (*message)(LDPL_INFO, "%s: %s: %s", claimed_file->name,
+ claimed_file->syms[i].name, res);
+ }
+ }
+
+ if (add_input_file == NULL)
+ {
+ fprintf(stderr, "tv_add_input_file interface missing\n");
+ return LDPS_ERR;
+ }
+ if (get_input_file == NULL)
+ {
+ fprintf(stderr, "tv_get_input_file interface missing\n");
+ return LDPS_ERR;
+ }
+ if (release_input_file == NULL)
+ {
+ fprintf(stderr, "tv_release_input_file interface missing\n");
+ return LDPS_ERR;
+ }
+
+ for (claimed_file = first_claimed_file;
+ claimed_file != NULL;
+ claimed_file = claimed_file->next)
+ {
+ (*get_input_file) (claimed_file->handle, &file);
+
+ /* Look for the beginning of output from readelf -s. */
+ irfile = fdopen(file.fd, "r");
+ (void)fseek(irfile, file.offset, SEEK_SET);
+ end_offset = file.offset + file.filesize;
+ len = fread(buf, 1, 13, irfile);
+ if (len < 13 || strncmp(buf, "\nSymbol table", 13) != 0)
+ {
+ fprintf(stderr, "%s: can't re-read original input file\n",
+ claimed_file->name);
+ return LDPS_ERR;
+ }
+
+ /* Skip the two header lines. */
+ (void) fgets(buf, sizeof(buf), irfile);
+ (void) fgets(buf, sizeof(buf), irfile);
+
+ filename = NULL;
+ while (ftell(irfile) < end_offset
+ && fgets(buf, sizeof(buf), irfile) != NULL)
+ {
+ parse_readelf_line(buf, &info);
+
+ /* Look for file name. */
+ if (strncmp(info.type, "FILE", 4) == 0)
+ {
+ len = strlen(info.name);
+ p = malloc(len + 1);
+ strncpy(p, info.name, len + 1);
+ filename = p;
+ break;
+ }
+ }
+
+ (*release_input_file) (claimed_file->handle);
+
+ if (filename == NULL)
+ filename = claimed_file->name;
+
+ if (claimed_file->nsyms == 0)
+ continue;
+
+ if (strlen(filename) >= sizeof(buf))
+ {
+ (*message)(LDPL_FATAL, "%s: filename too long", filename);
+ return LDPS_ERR;
+ }
+ strcpy(buf, filename);
+ p = strrchr(buf, '.');
+ if (p == NULL
+ || (strcmp(p, ".syms") != 0
+ && strcmp(p, ".c") != 0
+ && strcmp(p, ".cc") != 0))
+ {
+ (*message)(LDPL_FATAL, "%s: filename has unknown suffix",
+ filename);
+ return LDPS_ERR;
+ }
+ p[1] = 'o';
+ p[2] = '\0';
+ (*message)(LDPL_INFO, "%s: adding new input file", buf);
+ (*add_input_file)(buf);
+ }
+
+ return LDPS_OK;
+}
+
+enum ld_plugin_status
+cleanup_hook(void)
+{
+ (*message)(LDPL_INFO, "cleanup hook called");
+ return LDPS_OK;
+}
+
+static void
+parse_readelf_line(char* p, struct sym_info* info)
+{
+ int len;
+
+ p += strspn(p, " ");
+
+ /* Index field. */
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Value field. */
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Size field. */
+ info->size = atoi(p);
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Type field. */
+ info->type = p;
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Binding field. */
+ info->bind = p;
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Visibility field. */
+ info->vis = p;
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Section field. */
+ info->sect = p;
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Name field. */
+ /* FIXME: Look for version. */
+ len = strlen(p);
+ if (len == 0)
+ p = NULL;
+ else if (p[len-1] == '\n')
+ p[--len] = '\0';
+ info->name = p;
+}
diff --git a/binutils-2.25/gold/testsuite/plugin_test_1.sh b/binutils-2.25/gold/testsuite/plugin_test_1.sh
new file mode 100755
index 00000000..4d3ed417
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_test_1.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+# plugin_test_1.sh -- a test case for the plugin API.
+
+# Copyright 2008, 2009 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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 goes with plugin_test_1.c, a simple plug-in library that
+# exercises the basic interfaces and prints out version numbers and
+# options passed to the plugin.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check plugin_test_1.err "API version:"
+check plugin_test_1.err "gold version:"
+check plugin_test_1.err "option: _Z4f13iv"
+check plugin_test_1.err "two_file_test_main.o: claim file hook called"
+check plugin_test_1.err "two_file_test_1.syms: claim file hook called"
+check plugin_test_1.err "two_file_test_1b.syms: claim file hook called"
+check plugin_test_1.err "two_file_test_2.syms: claim file hook called"
+check plugin_test_1.err "two_file_test_1.syms: _Z4f13iv: PREVAILING_DEF_IRONLY"
+check plugin_test_1.err "two_file_test_1.syms: _Z2t2v: PREVAILING_DEF_REG"
+check plugin_test_1.err "two_file_test_1.syms: v2: RESOLVED_IR"
+check plugin_test_1.err "two_file_test_1.syms: t17data: RESOLVED_IR"
+check plugin_test_1.err "two_file_test_2.syms: _Z4f13iv: PREEMPTED_IR"
+check plugin_test_1.err "two_file_test_1.o: adding new input file"
+check plugin_test_1.err "two_file_test_1b.o: adding new input file"
+check plugin_test_1.err "two_file_test_2.o: adding new input file"
+check plugin_test_1.err "cleanup hook called"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/plugin_test_2.sh b/binutils-2.25/gold/testsuite/plugin_test_2.sh
new file mode 100755
index 00000000..293b1f00
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_test_2.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+# plugin_test_2.sh -- a test case for the plugin API.
+
+# Copyright 2008, 2009 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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 goes with plugin_test_1.c, a simple plug-in library that
+# exercises the basic interfaces and prints out version numbers and
+# options passed to the plugin.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check plugin_test_2.err "API version:"
+check plugin_test_2.err "gold version:"
+check plugin_test_2.err "two_file_test_main.o: claim file hook called"
+check plugin_test_2.err "two_file_test_1.syms: claim file hook called"
+check plugin_test_2.err "two_file_test_1b.syms: claim file hook called"
+check plugin_test_2.err "two_file_shared_2.so: claim file hook called"
+check plugin_test_2.err "two_file_test_1.syms: _Z4f13iv: PREVAILING_DEF_IRONLY_EXP"
+check plugin_test_2.err "two_file_test_1.syms: _Z2t2v: PREVAILING_DEF_REG"
+check plugin_test_2.err "two_file_test_1.syms: v2: RESOLVED_DYN"
+check plugin_test_2.err "two_file_test_1.syms: t17data: RESOLVED_DYN"
+check plugin_test_2.err "two_file_test_1.o: adding new input file"
+check plugin_test_2.err "two_file_test_1b.o: adding new input file"
+check plugin_test_2.err "cleanup hook called"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/plugin_test_3.sh b/binutils-2.25/gold/testsuite/plugin_test_3.sh
new file mode 100755
index 00000000..39356d13
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_test_3.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+# plugin_test_3.sh -- a test case for the plugin API.
+
+# Copyright 2008, 2009 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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 goes with plugin_test.c, a simple plug-in library that
+# exercises the basic interfaces and prints out version numbers and
+# options passed to the plugin.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check plugin_test_3.err "API version:"
+check plugin_test_3.err "gold version:"
+check plugin_test_3.err "option: _Z4f13iv"
+check plugin_test_3.err "two_file_test_main.o: claim file hook called"
+check plugin_test_3.err "two_file_test_1.syms: claim file hook called"
+check plugin_test_3.err "two_file_test_1b.syms: claim file hook called"
+check plugin_test_3.err "two_file_test_2.syms: claim file hook called"
+check plugin_test_3.err "two_file_test_1.syms: _Z4f13iv: PREVAILING_DEF_IRONLY_EXP"
+check plugin_test_3.err "two_file_test_1.syms: _Z2t2v: PREVAILING_DEF_REG"
+check plugin_test_3.err "two_file_test_1.syms: v2: RESOLVED_IR"
+check plugin_test_3.err "two_file_test_1.syms: t17data: RESOLVED_IR"
+check plugin_test_3.err "two_file_test_2.syms: _Z4f13iv: PREEMPTED_IR"
+check plugin_test_3.err "two_file_test_1.o: adding new input file"
+check plugin_test_3.err "two_file_test_1b.o: adding new input file"
+check plugin_test_3.err "two_file_test_2.o: adding new input file"
+check plugin_test_3.err "cleanup hook called"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/plugin_test_4.sh b/binutils-2.25/gold/testsuite/plugin_test_4.sh
new file mode 100755
index 00000000..89df46ca
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_test_4.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+# plugin_test_4.sh -- a test case for the plugin API.
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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 goes with plugin_test_4.c, a simple plug-in library that
+# exercises the basic interfaces and prints out version numbers and
+# options passed to the plugin.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check plugin_test_4.err "API version:"
+check plugin_test_4.err "gold version:"
+check plugin_test_4.err "option: _Z4f13iv"
+check plugin_test_4.err "two_file_test_main.o: claim file hook called"
+check plugin_test_4.err "plugin_test_4.a: claim file hook called"
+check plugin_test_4.err "plugin_test_4.a: claiming file"
+check plugin_test_4.err "plugin_test_4.a: _Z4f13iv: PREVAILING_DEF_IRONLY"
+check plugin_test_4.err "plugin_test_4.a: _Z2t2v: PREVAILING_DEF_REG"
+check plugin_test_4.err "plugin_test_4.a: v2: RESOLVED_IR"
+check plugin_test_4.err "plugin_test_4.a: t17data: RESOLVED_IR"
+check plugin_test_4.err "plugin_test_4.a: _Z4f13iv: PREEMPTED_IR"
+check plugin_test_4.err "two_file_test_1.o: adding new input file"
+check plugin_test_4.err "two_file_test_1b.o: adding new input file"
+check plugin_test_4.err "two_file_test_2.o: adding new input file"
+check plugin_test_4.err "cleanup hook called"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/plugin_test_6.sh b/binutils-2.25/gold/testsuite/plugin_test_6.sh
new file mode 100755
index 00000000..9b368e78
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_test_6.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+# plugin_test_6.sh -- a test case for the plugin API.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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 goes with plugin_test_6.c, a simple plug-in library that
+# exercises the basic interfaces and prints out version numbers and
+# options passed to the plugin.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check plugin_test_6.err "API version:"
+check plugin_test_6.err "gold version:"
+check plugin_test_6.err "plugin_common_test_1.syms: claim file hook called"
+check plugin_test_6.err "plugin_common_test_2.syms: claim file hook called"
+check plugin_test_6.err "plugin_common_test_1.syms: c1: PREVAILING_DEF_IRONLY"
+check plugin_test_6.err "plugin_common_test_1.syms: c2: PREVAILING_DEF_IRONLY"
+check plugin_test_6.err "plugin_common_test_1.syms: c3: RESOLVED_IR"
+check plugin_test_6.err "plugin_common_test_1.syms: c4: RESOLVED_IR"
+check plugin_test_6.err "plugin_common_test_1.syms: c5: PREVAILING_DEF_IRONLY"
+check plugin_test_6.err "plugin_common_test_2.syms: c1: RESOLVED_IR"
+check plugin_test_6.err "plugin_common_test_2.syms: c2: RESOLVED_IR"
+check plugin_test_6.err "plugin_common_test_2.syms: c3: PREVAILING_DEF_IRONLY"
+check plugin_test_6.err "plugin_common_test_2.syms: c4: PREVAILING_DEF_IRONLY"
+check plugin_test_6.err "plugin_common_test_2.syms: c5: RESOLVED_IR"
+check plugin_test_6.err "cleanup hook called"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/plugin_test_7.sh b/binutils-2.25/gold/testsuite/plugin_test_7.sh
new file mode 100755
index 00000000..27723f9c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_test_7.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+# plugin_test_7.sh -- a test case for the plugin API with GC.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Rafael Avila de Espindola <espindola@google.com>.
+
+# 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.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check_not()
+{
+ if grep -q "$2" "$1"
+ then
+ echo "Found unexpected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+
+check plugin_test_7.err "set_x: PREVAILING_DEF_IRONLY"
+check plugin_test_7.err "fun2: RESOLVED_EXEC"
+check plugin_test_7.err "fun1: PREVAILING_DEF_REG"
+check plugin_test_7.err "removing unused section from '.text.fun2' in file 'plugin_test_7_2.o'"
+check_not plugin_test_7.syms "fun2"
diff --git a/binutils-2.25/gold/testsuite/plugin_test_7_1.c b/binutils-2.25/gold/testsuite/plugin_test_7_1.c
new file mode 100644
index 00000000..5f4c4f34
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_test_7_1.c
@@ -0,0 +1,43 @@
+/* plugin_test_7_1.c -- a test case for the plugin API with GC.
+
+ Copyright 2010 Free Software Foundation, Inc.
+ Written by Rafael Avila de Espindola <espindola@google.com>.
+
+ 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. */
+
+int fun1(void);
+int fun2(void);
+void set_x(int y);
+
+#ifndef LTO
+static int x = 0;
+
+void set_x(int y)
+{
+ x = y;
+}
+#endif
+
+int fun1(void)
+{
+#ifndef LTO
+ if (x)
+ return fun2();
+#endif
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/plugin_test_7_2.c b/binutils-2.25/gold/testsuite/plugin_test_7_2.c
new file mode 100644
index 00000000..06b7676b
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_test_7_2.c
@@ -0,0 +1,33 @@
+/* plugin_test_7_1.c -- a test case for the plugin API with GC.
+
+ Copyright 2010 Free Software Foundation, Inc.
+ Written by Rafael Avila de Espindola <espindola@google.com>.
+
+ 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. */
+
+int fun1(void);
+void fun2(void);
+
+void fun2(void)
+{
+}
+
+int main(void)
+{
+ return fun1();
+}
diff --git a/binutils-2.25/gold/testsuite/plugin_test_tls.sh b/binutils-2.25/gold/testsuite/plugin_test_tls.sh
new file mode 100755
index 00000000..22b5458c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/plugin_test_tls.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+# plugin_test_tls.sh -- a test case for the plugin API.
+
+# Copyright 2013 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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 goes with plugin_test.c, a simple plug-in library that
+# exercises the basic interfaces and prints out version numbers and
+# options passed to the plugin.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check plugin_test_tls.err "API version:"
+check plugin_test_tls.err "gold version:"
+check plugin_test_tls.err "option: _Z4f13iv"
+check plugin_test_tls.err "two_file_test_tls.o: claim file hook called"
+check plugin_test_tls.err "two_file_test_1.syms: claim file hook called"
+check plugin_test_tls.err "two_file_test_1b.syms: claim file hook called"
+check plugin_test_tls.err "two_file_test_2_tls.syms: claim file hook called"
+check plugin_test_tls.err "two_file_test_1.syms: _Z4f13iv: PREVAILING_DEF_IRONLY"
+check plugin_test_tls.err "two_file_test_1.syms: _Z2t2v: PREVAILING_DEF_REG"
+check plugin_test_tls.err "two_file_test_1.syms: v2: RESOLVED_IR"
+check plugin_test_tls.err "two_file_test_1.syms: t17data: RESOLVED_IR"
+check plugin_test_tls.err "two_file_test_2_tls.syms: _Z4f13iv: PREEMPTED_IR"
+check plugin_test_tls.err "two_file_test_2_tls.syms: tls1: PREVAILING_DEF_REG"
+check plugin_test_tls.err "two_file_test_1.o: adding new input file"
+check plugin_test_tls.err "two_file_test_1b.o: adding new input file"
+check plugin_test_tls.err "two_file_test_2_tls.o: adding new input file"
+check plugin_test_tls.err "cleanup hook called"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/pr12826.sh b/binutils-2.25/gold/testsuite/pr12826.sh
new file mode 100755
index 00000000..a4fa2e3a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/pr12826.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# pr12826.sh -- a test case for combining ARM arch attributes.
+
+# Copyright 2011 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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 goes with pr12826_1.s and pr12826_2.s, two ARM assembly source
+# files constructed to test handling of arch attributes.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find attribute in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual attribute below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+# Check that arch is armv7e-m.
+check pr12826.stdout "Tag_CPU_arch: v7E-M"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/pr12826_1.s b/binutils-2.25/gold/testsuite/pr12826_1.s
new file mode 100644
index 00000000..b4f68418
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/pr12826_1.s
@@ -0,0 +1,13 @@
+ .syntax unified
+ .arch armv7e-m
+ .thumb
+ .text
+ .align 2
+ .global f1
+ .thumb
+ .thumb_func
+ .type f1, %function
+f1:
+ movs r0, #0
+ bx lr
+ .size f1, .-f1
diff --git a/binutils-2.25/gold/testsuite/pr12826_2.s b/binutils-2.25/gold/testsuite/pr12826_2.s
new file mode 100644
index 00000000..2dd7dc99
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/pr12826_2.s
@@ -0,0 +1,13 @@
+ .syntax unified
+ .arch armv7e-m
+ .thumb
+ .text
+ .align 2
+ .global f2
+ .thumb
+ .thumb_func
+ .type f2, %function
+f2:
+ movs r0, #0
+ bx lr
+ .size f2, .-f2
diff --git a/binutils-2.25/gold/testsuite/pr14265.c b/binutils-2.25/gold/testsuite/pr14265.c
new file mode 100644
index 00000000..6bb8f9aa
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/pr14265.c
@@ -0,0 +1,20 @@
+int foo0 __attribute__((used,section(".foo0.0")));
+int foo1 __attribute__((used,section(".foo1.0")));
+int foo2 __attribute__((used,section(".foo2.0")));
+
+extern unsigned long __foo0_start;
+extern unsigned long __foo0_end;
+
+extern unsigned long __foo1_start;
+extern unsigned long __foo1_end;
+
+extern unsigned long __foo2_start;
+extern unsigned long __foo2_end;
+
+int
+main (void)
+{
+ return ((__foo0_end - __foo0_start) -
+ (__foo1_end - __foo1_start) -
+ (__foo2_end - __foo2_start));
+}
diff --git a/binutils-2.25/gold/testsuite/pr14265.sh b/binutils-2.25/gold/testsuite/pr14265.sh
new file mode 100755
index 00000000..4e477b22
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/pr14265.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+# pr14265.sh -- test --gc-sections with KEEP
+
+# Copyright 2012 Free Software Foundation, Inc.
+# Written by Nick Clifton <nickc@redhat.com>
+
+# 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.
+
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Garbage collection failed to KEEP :"
+ echo " $2"
+ exit 1
+ fi
+}
+
+check pr14265.stdout "foo1_start"
+check pr14265.stdout "foo1_end"
+check pr14265.stdout "foo2_start"
+check pr14265.stdout "foo2_end"
+
diff --git a/binutils-2.25/gold/testsuite/pr14265.t b/binutils-2.25/gold/testsuite/pr14265.t
new file mode 100644
index 00000000..e6d163af
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/pr14265.t
@@ -0,0 +1,25 @@
+SECTIONS
+{
+ .text : { *(.text) }
+
+ __foo0_start = .;
+ .foo0 : { *(.foo0.*) }
+ __foo0_end = .;
+
+ __foo1_start = .;
+ .foo1 : { KEEP(*(.foo1.*)) }
+ __foo1_end = .;
+
+ .foo2 : {
+ __foo2_start = .;
+ KEEP(*(.foo2.*))
+ __foo2_end = .;
+ }
+
+ .got : { *(.got .toc) }
+}
+
+
+ASSERT (__foo1_start < __foo1_end, "foo1 not KEPT");
+ASSERT ((__foo1_end - __foo1_start) == (__foo2_end - __foo2_start),"foo2 not KEPT");
+
diff --git a/binutils-2.25/gold/testsuite/protected_1.cc b/binutils-2.25/gold/testsuite/protected_1.cc
new file mode 100644
index 00000000..049bda74
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/protected_1.cc
@@ -0,0 +1,58 @@
+// protected_1.cc -- a test case for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 function f1 is protected, which means that other callers in the
+// same shared library will call this version.
+
+int
+f1() __attribute__ ((__visibility__ ("protected")));
+
+int
+f1()
+{
+ return 1;
+}
+
+// The function f2 is used to test that the executable can see the
+// same function address for a protected function in the executable
+// and in the shared library. We can't use the visibility attribute
+// here, becaues that may cause gcc to generate a PC relative reloc;
+// we need it to get the value from the GOT. I'm not sure this is
+// really useful, given that it doesn't work with the visibility
+// attribute. This test exists here mainly because the glibc
+// testsuite has the same test, and we want to make sure that gold
+// passes the glibc testsuite.
+
+extern "C" int f2();
+asm(".protected f2");
+
+extern "C" int
+f2()
+{
+ return 2;
+}
+
+int
+(*get_f2_addr())()
+{
+ return f2;
+}
diff --git a/binutils-2.25/gold/testsuite/protected_2.cc b/binutils-2.25/gold/testsuite/protected_2.cc
new file mode 100644
index 00000000..19d8276e
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/protected_2.cc
@@ -0,0 +1,31 @@
+// protected_2.cc -- a test case for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 should call the protected version of f1.
+
+extern int f1();
+
+bool
+t1()
+{
+ return f1() == 1;
+}
diff --git a/binutils-2.25/gold/testsuite/protected_3.cc b/binutils-2.25/gold/testsuite/protected_3.cc
new file mode 100644
index 00000000..8a27a2a6
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/protected_3.cc
@@ -0,0 +1,33 @@
+// protected_2.cc -- a test case for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 will also call the protected version of f1. In some versions
+// of the test this will be overridden by a version in the main
+// program.
+
+extern int f1();
+
+bool
+t2()
+{
+ return f1() == 1;
+}
diff --git a/binutils-2.25/gold/testsuite/protected_4.cc b/binutils-2.25/gold/testsuite/protected_4.cc
new file mode 100644
index 00000000..58e3e2b0
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/protected_4.cc
@@ -0,0 +1,32 @@
+// protected_4.cc -- a test case for gold
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 function f1 is protected but not defined.
+
+int
+f1() __attribute__ ((__visibility__ ("protected")));
+
+int
+f2()
+{
+ return f1();
+}
diff --git a/binutils-2.25/gold/testsuite/protected_main_1.cc b/binutils-2.25/gold/testsuite/protected_main_1.cc
new file mode 100644
index 00000000..271446f8
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/protected_main_1.cc
@@ -0,0 +1,40 @@
+// protected_main_1.cc -- a test case for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cassert>
+
+// This function in the shared library will call the protected version
+// of f1 in the shared library.
+
+extern bool t1();
+extern bool t2();
+
+extern "C" int f2();
+extern int (*get_f2_addr()) ();
+
+int
+main()
+{
+ assert(t1());
+ assert(t2());
+ assert(&f2 == get_f2_addr());
+}
diff --git a/binutils-2.25/gold/testsuite/protected_main_2.cc b/binutils-2.25/gold/testsuite/protected_main_2.cc
new file mode 100644
index 00000000..69603227
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/protected_main_2.cc
@@ -0,0 +1,29 @@
+// protected_main_2.cc -- a test case for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 version of f1 will not be called by the shared library code.
+
+int
+f1()
+{
+ return 2;
+}
diff --git a/binutils-2.25/gold/testsuite/protected_main_3.cc b/binutils-2.25/gold/testsuite/protected_main_3.cc
new file mode 100644
index 00000000..f356f3d2
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/protected_main_3.cc
@@ -0,0 +1,31 @@
+// protected_main_3.cc -- a test case for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 should call the unprotected version of f1.
+
+extern int f1();
+
+bool
+t2()
+{
+ return f1() == 2;
+}
diff --git a/binutils-2.25/gold/testsuite/relro_script_test.t b/binutils-2.25/gold/testsuite/relro_script_test.t
new file mode 100644
index 00000000..3a6e3e91
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/relro_script_test.t
@@ -0,0 +1,54 @@
+/* relro_test.t -- relro script test for gold
+
+ Copyright 2008 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>.
+
+ 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. */
+
+/* With luck this will work on all platforms. */
+
+using_script = 1;
+
+SECTIONS
+{
+ . = SIZEOF_HEADERS;
+
+ .text : { *(.text) }
+
+ .eh_frame : ONLY_IF_RO { KEEP(*(.eh_frame)) }
+
+ . = (ALIGN(CONSTANT(MAXPAGESIZE))
+ - ((CONSTANT(MAXPAGESIZE) - .) & (CONSTANT(MAXPAGESIZE) - 1)));
+ . = DATA_SEGMENT_ALIGN(CONSTANT(MAXPAGESIZE), CONSTANT(COMMONPAGESIZE));
+
+ .eh_frame : ONLY_IF_RW { KEEP(*(.eh_frame)) }
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*)
+ *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+ .dynamic : { *(.dynamic) }
+ .got : { *(.got) }
+
+ . = DATA_SEGMENT_RELRO_END(0, .);
+
+ .got.plt : { *(.got.plt) }
+
+ .data : { *(.data .data.* .gnu.linkonce.d.*) }
+
+ . = DATA_SEGMENT_END (.);
+}
diff --git a/binutils-2.25/gold/testsuite/relro_test.cc b/binutils-2.25/gold/testsuite/relro_test.cc
new file mode 100644
index 00000000..795ad391
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/relro_test.cc
@@ -0,0 +1,160 @@
+// relro_test.cc -- test -z relro for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cassert>
+#include <csignal>
+#include <cstdio>
+#include <cstdlib>
+#include <exception>
+#include <stdint.h>
+#include <unistd.h>
+
+// This tests we were linked with a script. If we were linked with a
+// script, relro currently does not work.
+
+extern char using_script[] __attribute__ ((weak));
+
+// This code is put into a shared library linked with -z relro.
+
+// i1 and i2 are not relro variables.
+int i1 = 1;
+static int i2 = 2;
+
+// P1 is a global relro variable.
+int* const p1 __attribute__ ((aligned(64))) = &i1;
+
+// P2 is a local relro variable.
+int* const p2 __attribute__ ((aligned(64))) = &i2;
+
+// Add a TLS variable to make sure -z relro works correctly with TLS.
+__thread int i3 = 1;
+
+// Test symbol addresses.
+
+bool
+t1()
+{
+ if (using_script)
+ return true;
+
+ void* i1addr = static_cast<void*>(&i1);
+ void* i2addr = static_cast<void*>(&i2);
+ const void* p1addr = static_cast<const void*>(&p1);
+ const void* p2addr = static_cast<const void*>(&p2);
+
+ // The relro variables should precede the non-relro variables in the
+ // memory image.
+ assert(i1addr > p1addr);
+ assert(i1addr > p2addr);
+ assert(i2addr > p1addr);
+ assert(i2addr > p2addr);
+
+ // The relro variables should not be on the same page as the
+ // non-relro variables.
+ const size_t page_size = getpagesize();
+ uintptr_t i1page = reinterpret_cast<uintptr_t>(i1addr) & ~ (page_size - 1);
+ uintptr_t i2page = reinterpret_cast<uintptr_t>(i2addr) & ~ (page_size - 1);
+ uintptr_t p1page = reinterpret_cast<uintptr_t>(p1addr) & ~ (page_size - 1);
+ uintptr_t p2page = reinterpret_cast<uintptr_t>(p2addr) & ~ (page_size - 1);
+ assert(i1page != p1page);
+ assert(i1page != p2page);
+ assert(i2page != p1page);
+ assert(i2page != p2page);
+ assert(i3 == 1);
+
+ return true;
+}
+
+// Tell terminate handler that we are throwing from a signal handler.
+
+static bool throwing;
+
+// A signal handler for SIGSEGV.
+
+extern "C"
+void
+sigsegv_handler(int)
+{
+ throwing = true;
+ throw 0;
+}
+
+// The original terminate handler.
+
+std::terminate_handler orig_terminate;
+
+// Throwing an exception out of a signal handler doesn't always work
+// reliably. When that happens the program will call terminate. We
+// set a terminate handler to indicate that the test probably passed.
+
+void
+terminate_handler()
+{
+ if (!throwing)
+ {
+ orig_terminate();
+ ::exit(EXIT_FAILURE);
+ }
+ fprintf(stderr,
+ "relro_test: terminate called due to failure to throw through signal handler\n");
+ fprintf(stderr, "relro_test: assuming test succeeded\n");
+ ::exit(EXIT_SUCCESS);
+}
+
+// Use a separate function to throw the exception, so that we don't
+// need to use -fnon-call-exceptions.
+
+void f2() __attribute__ ((noinline));
+void
+f2()
+{
+ int** pp1 = const_cast<int**>(&p1);
+ *pp1 = &i2;
+
+ // We shouldn't get here--the assignment to *pp1 should write to
+ // memory which the dynamic linker marked as read-only, giving us a
+ // SIGSEGV, causing sigsegv_handler to be invoked, to throw past us.
+ assert(0);
+}
+
+// Changing a relro variable should give us a SIGSEGV.
+
+bool
+t2()
+{
+ if (using_script)
+ return true;
+
+ signal(SIGSEGV, sigsegv_handler);
+ orig_terminate = std::set_terminate(terminate_handler);
+
+ try
+ {
+ f2();
+ return false;
+ }
+ catch (int i)
+ {
+ assert(i == 0);
+ return true;
+ }
+}
diff --git a/binutils-2.25/gold/testsuite/relro_test.sh b/binutils-2.25/gold/testsuite/relro_test.sh
new file mode 100755
index 00000000..47a94910
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/relro_test.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+
+# relro_test.sh -- test -z relro
+
+# Copyright 2010, 2011 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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 test checks that the PT_GNU_RELRO segment is properly
+# aligned and is coincident with the beginning of the data segment.
+
+
+# Cleans a hexadecimal number for input to dc.
+clean_hex()
+{
+ echo "$1" | sed -e 's/0x//' -e 'y/abcdef/ABCDEF/'
+}
+
+check()
+{
+ # Get the address and length of the PT_GNU_RELRO segment.
+ RELRO_START=`grep GNU_RELRO "$1" | awk '{ print $3; }'`
+ RELRO_LEN=`grep GNU_RELRO "$1" | awk '{ print $6; }'`
+
+ if test -z "$RELRO_START"
+ then
+ echo "Did not find a PT_GNU_RELRO segment."
+ exit 1
+ fi
+
+ # Get the address and alignment of the PT_LOAD segment whose address
+ # matches the PT_GNU_RELRO segment.
+ LOAD_ALIGN=`grep LOAD "$1" | awk -v A=$RELRO_START '$3 == A { print $NF; }'`
+ LOAD_LEN=`grep LOAD "$1" | awk -v A=$RELRO_START '$3 == A { print $6; }'`
+
+ if test -z "$LOAD_LEN"
+ then
+ echo "Did not find a PT_LOAD segment matching the PT_GNU_RELRO segment."
+ exit 1
+ fi
+
+ # Compute the address of the end of the PT_GNU_RELRO segment,
+ # modulo the alignment of the PT_LOAD segment.
+ RELRO_START=`clean_hex "$RELRO_START"`
+ RELRO_LEN=`clean_hex "$RELRO_LEN"`
+ LOAD_ALIGN=`clean_hex "$LOAD_ALIGN"`
+ RELRO_END=`echo "16o 16i $RELRO_START $RELRO_LEN + p" | dc`
+ REM=`echo "16i $RELRO_END $LOAD_ALIGN % p" | dc`
+
+ if test "$REM" -eq 0; then
+ :
+ else
+ echo "PT_GNU_RELRO segment does not end at page boundary."
+ exit 1
+ fi
+}
+
+check relro_test.stdout
diff --git a/binutils-2.25/gold/testsuite/relro_test_main.cc b/binutils-2.25/gold/testsuite/relro_test_main.cc
new file mode 100644
index 00000000..6f5ea2bb
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/relro_test_main.cc
@@ -0,0 +1,33 @@
+// relro_test_main.cc -- test -z relro for gold, main function
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cassert>
+
+extern bool t1();
+extern bool t2();
+
+int
+main()
+{
+ assert(t1());
+ assert(t2());
+}
diff --git a/binutils-2.25/gold/testsuite/retain_symbols_file_test.sh b/binutils-2.25/gold/testsuite/retain_symbols_file_test.sh
new file mode 100755
index 00000000..e0d3ffce
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/retain_symbols_file_test.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# retain_symbols_file_test.sh -- a test case for -retain-symbols-file
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Craig Silverstein <csilvers@google.com>.
+
+# 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 Makefile tries linking simple_test.o with -retain-symbols-file.
+# It then runs nm over the results. We check that the output is right.
+
+check_present()
+{
+ if ! grep -q "$1" retain_symbols_file_test.stdout
+ then
+ echo "Did not find expected symbol $1 in retain_symbols_file_test.stdout"
+ exit 1
+ fi
+}
+
+check_absent()
+{
+ if grep -q "$1" retain_symbols_file_test.stdout
+ then
+ echo "Found unexpected symbol $1 in retain_symbols_file_test.stdout"
+ exit 1
+ fi
+}
+
+check_present 't1'
+check_present 't16b::t16b()'
+check_present 't20a::get()'
+check_present 't18()'
+check_absent 't10'
+check_absent 't1()'
+check_absent 't16b::t()'
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/script_test_1.cc b/binutils-2.25/gold/testsuite/script_test_1.cc
new file mode 100644
index 00000000..1bdf770e
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_1.cc
@@ -0,0 +1,47 @@
+// script_test_1.cc -- linker script test 1 for gold -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+// A test for a linker script which sets symbols to values.
+
+#include <cassert>
+#include <cstddef>
+#include <stdint.h>
+
+extern char a, b, c, d, e, f, g;
+int sym = 3;
+int common_sym;
+
+int
+main(int, char**)
+{
+ assert(reinterpret_cast<intptr_t>(&a) == 123);
+ assert(reinterpret_cast<intptr_t>(&b) == reinterpret_cast<intptr_t>(&a) * 2);
+ assert(reinterpret_cast<intptr_t>(&c)
+ == reinterpret_cast<intptr_t>(&b) + 3 * 6);
+ assert(reinterpret_cast<intptr_t>(&d)
+ == (reinterpret_cast<intptr_t>(&b) + 3) * 6);
+ assert(reinterpret_cast<int*>(&e) == &sym);
+ assert(reinterpret_cast<intptr_t>(&f)
+ == reinterpret_cast<intptr_t>(&sym) + 10);
+ assert(reinterpret_cast<int*>(&g) == &common_sym);
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/script_test_1.t b/binutils-2.25/gold/testsuite/script_test_1.t
new file mode 100644
index 00000000..af971c66
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_1.t
@@ -0,0 +1,29 @@
+/* script_test_1.t -- linker script test 1 for gold
+
+ Copyright 2008 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>.
+
+ 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. */
+
+a = 123;
+b = a * 2;
+c = b + 3 * 6;
+d = (b + 3) * 6;
+e = sym;
+f = sym + 10;
+g = common_sym;
diff --git a/binutils-2.25/gold/testsuite/script_test_10.s b/binutils-2.25/gold/testsuite/script_test_10.s
new file mode 100644
index 00000000..5f3e30f9
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_10.s
@@ -0,0 +1,14 @@
+ .section .sec0, "a"
+ .word 0
+
+ .section .sec2, "a"
+ .word 0x22
+
+ .section .sec1, "a"
+ .word 0x11
+
+ .section .secz, "a"
+
+ .section .sec3, "a"
+ .word 0x44
+
diff --git a/binutils-2.25/gold/testsuite/script_test_10.sh b/binutils-2.25/gold/testsuite/script_test_10.sh
new file mode 100755
index 00000000..58446ab5
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_10.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# script_test_10.sh -- test for the section order.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Viktor Kutuzov <vkutuzov@accesssoftek.com>.
+
+# 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.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected section in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check script_test_10.stdout ".*\[ 1\] .text"
+check script_test_10.stdout ".*\[ 2\] .sec0"
+check script_test_10.stdout ".*\[ 3\] .sec1"
+check script_test_10.stdout ".*\[ 4\] .sec2"
+check script_test_10.stdout ".*\[ 5\] .secz"
+check script_test_10.stdout ".*\[ 6\] .sec3"
+check script_test_10.stdout ".*\[ 7\] .data"
+check script_test_10.stdout ".* .bss"
+
diff --git a/binutils-2.25/gold/testsuite/script_test_10.t b/binutils-2.25/gold/testsuite/script_test_10.t
new file mode 100644
index 00000000..98f2107a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_10.t
@@ -0,0 +1,34 @@
+/* script_test_10.t -- test section order for gold.
+
+ Copyright 2010 Free Software Foundation, Inc.
+ Written by Viktor Kutuzov <vkutuzov@accesssoftek.com>.
+
+ 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. */
+
+SECTIONS
+{
+ .text : { *(.text) }
+ .sec0 : { *(.sec0) }
+ .sec1 : { *(.sec1) }
+ .sec2 : { *(.sec2) }
+ .secz : { *(.secz) }
+ .sec3 : { *(.sec3) }
+ .data : { *(.data) }
+ .bss : { *(.bss) }
+}
+
diff --git a/binutils-2.25/gold/testsuite/script_test_11.c b/binutils-2.25/gold/testsuite/script_test_11.c
new file mode 100644
index 00000000..d932813c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_11.c
@@ -0,0 +1,16 @@
+static unsigned int buffer1[256] __attribute((used));
+static unsigned int buffer2[256] __attribute((used)) = { 1 };
+
+unsigned int foo __attribute__((section(".foo")));
+extern char __foo_start;
+extern char __foo_end;
+
+int
+main (void)
+{
+ if (&__foo_end - &__foo_start != sizeof(foo))
+ return 1;
+ if (&__foo_start != (char *)&foo)
+ return 2;
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/script_test_11.t b/binutils-2.25/gold/testsuite/script_test_11.t
new file mode 100644
index 00000000..0ec6bcde
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_11.t
@@ -0,0 +1,8 @@
+SECTIONS
+{
+ .foo : {
+ __foo_start = .;
+ KEEP(*(.foo))
+ __foo_end = .;
+ }
+}
diff --git a/binutils-2.25/gold/testsuite/script_test_2.cc b/binutils-2.25/gold/testsuite/script_test_2.cc
new file mode 100644
index 00000000..71045516
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_2.cc
@@ -0,0 +1,74 @@
+// script_test_2.cc -- linker script test 2 for gold -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+// A test of some uses of the SECTIONS clause. Look at
+// script_test_2.t to make sense of this test.
+
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <stdint.h>
+
+extern char start_test_area[];
+extern char start_test_area_1[];
+extern char start_data[];
+extern char end_data[];
+extern char start_fill[];
+extern char end_fill[];
+extern char end_test_area[];
+extern char test_addr[];
+extern char test_addr_alias[];
+
+int
+main(int, char**)
+{
+ assert(reinterpret_cast<uintptr_t>(start_test_area) == 0x20000001);
+ assert(reinterpret_cast<uintptr_t>(start_test_area_1) == 0x20000010);
+
+ // We should see the string from script_test_2b.o next. The
+ // subalign should move it up to 0x20000020.
+ for (int i = 0; i < 16; ++i)
+ assert(start_test_area_1[i] == 0);
+ assert(strcmp(start_test_area_1 + 16, "test bb") == 0);
+
+ // Next the string from script_test_2a.o, after the subalign.
+ for (int i = 16 + 7; i < 48; ++i)
+ assert(start_test_area_1[i] == 0);
+ assert(strcmp(start_test_area_1 + 48, "test aa") == 0);
+
+ // Move four bytes forward to start_data.
+ assert(reinterpret_cast<uintptr_t>(start_test_area_1 + 48 + 8 + 4)
+ == reinterpret_cast<uintptr_t>(start_data));
+ assert(memcmp(start_data, "\1\2\0\4\0\0\0\010\0\0\0\0\0\0\0", 15) == 0
+ || memcmp(start_data, "\1\0\2\0\0\0\4\0\0\0\0\0\0\0\010", 15) == 0);
+ assert(end_data == start_data + 15);
+
+ // Check that FILL works as expected.
+ assert(start_fill == end_data);
+ assert(memcmp(start_fill, "\x12\x34\x56\x78\x12\x34\x56\0", 8) == 0);
+ assert(end_fill == start_fill + 8);
+
+ assert(end_test_area == end_fill);
+
+ assert(test_addr == start_test_area_1);
+ assert(test_addr_alias == test_addr);
+}
diff --git a/binutils-2.25/gold/testsuite/script_test_2.t b/binutils-2.25/gold/testsuite/script_test_2.t
new file mode 100644
index 00000000..81ed9aad
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_2.t
@@ -0,0 +1,69 @@
+/* script_test_2.t -- linker script test 2 for gold
+
+ Copyright 2008 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>.
+
+ 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. */
+
+test_addr_alias = test_addr;
+
+SECTIONS
+{
+ /* With luck this will work everywhere. */
+ . = 0x10000000;
+
+ /* With luck this will be enough to get the program working. */
+ .text : { *(.text) }
+ . += 0x100000;
+ . = ALIGN(0x100);
+ .data : { *(.data) }
+ .got : { *(.got .toc) }
+ .bss : { *(.bss) }
+
+ /* Now the real test. */
+ . = 0x20000001;
+ start_test_area = .;
+ .gold_test ALIGN(16) : SUBALIGN(32) {
+ start_test_area_1 = .;
+
+ /* No sections should wind up here, because of the EXCLUDE_FILE. */
+ *( EXCLUDE_FILE(script_test*) .gold_test)
+
+ /* This should match only script_test_2b.o. */
+ script_test_2b.o(.gold_test)
+
+ /* This should match the remaining sections. */
+ *(.gold_test)
+
+ . = 60;
+ start_data = .;
+ BYTE(1)
+ SHORT(2)
+ LONG(4)
+ QUAD(8)
+ end_data = .;
+
+ start_fill = .;
+ FILL(0x12345678);
+ . = . + 7;
+ BYTE(0)
+ end_fill = .;
+ }
+ end_test_area = .;
+ test_addr = ADDR(.gold_test);
+}
diff --git a/binutils-2.25/gold/testsuite/script_test_2a.cc b/binutils-2.25/gold/testsuite/script_test_2a.cc
new file mode 100644
index 00000000..6c665eb7
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_2a.cc
@@ -0,0 +1,24 @@
+// script_test_2a.cc -- linker script test 2, file 1 -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+char script_test_string_a[] __attribute__ ((section(".gold_test"))) =
+ "test aa";
diff --git a/binutils-2.25/gold/testsuite/script_test_2b.cc b/binutils-2.25/gold/testsuite/script_test_2b.cc
new file mode 100644
index 00000000..9b19eb02
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_2b.cc
@@ -0,0 +1,24 @@
+// script_test_2a.cc -- linker script test 2, file 2 -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+char script_test_string_b[] __attribute__ ((section(".gold_test"))) =
+ "test bb";
diff --git a/binutils-2.25/gold/testsuite/script_test_3.sh b/binutils-2.25/gold/testsuite/script_test_3.sh
new file mode 100755
index 00000000..d114edd1
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_3.sh
@@ -0,0 +1,102 @@
+#!/bin/sh
+
+# script_test_3.sh -- test PHDRS
+
+# Copyright 2008 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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 goes with script_test_3.t, which is a linker script which
+# uses a PHDRS clause. We run objdump -p on a program linked with
+# that linker script.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected segment in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check_count()
+{
+ if test "`grep -c "$2" "$1"`" != "$3"
+ then
+ echo "Did not find expected segment in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check_count script_test_3.stdout "^ INTERP" 1
+check_count script_test_3.stdout "^ LOAD" 3
+check_count script_test_3.stdout "^ DYNAMIC" 1
+
+# Make sure that the size of the INTERP segment is the same as the
+# size of the .interp section.
+section=`fgrep .interp script_test_3.stdout | grep PROGBITS`
+if test "$section" = ""; then
+ echo "Did not find .interp section"
+ echo ""
+ echo "Actual output below:"
+ cat script_test_3.stdout
+ exit 1
+fi
+# Remove the brackets around the section number, since they can give
+# an unpredictable number of fields.
+section=`echo "$section" | sed -e 's/[][]*//g'`
+section_size=`echo "$section" | awk '{ print $6; }'`
+
+segment=`grep '^ INTERP' script_test_3.stdout`
+# We already checked above that we have an INTERP segment.
+segment_size=`echo "$segment" | awk '{ print $5; }'`
+
+# Now $section_size looks like 000013 and $segment_size looks like
+# 0x00013. Both numbers are in hex.
+section_size=`echo "$section_size" | sed -e 's/^0*//'`
+segment_size=`echo "$segment_size" | sed -e 's/^0x//' -e 's/^0*//'`
+
+if test "$section_size" != "$segment_size"; then
+ echo ".interp size $section_size != PT_INTERP size $segment_size"
+ exit 1
+fi
+
+# At least one PT_LOAD segment should have an alignment >= 0x100000.
+found=no
+for a in `grep LOAD script_test_3.stdout | sed -e 's/^.* 0x/0x/'`; do
+ script="BEGIN { if ($a >= 0x100000) { print \"true\" } else { print \"false\" } }"
+ x=`awk "$script" < /dev/null`
+ if test "$x" = "true"; then
+ found=yes
+ fi
+done
+if test "$found" = "no"; then
+ echo "no LOAD segment has required alignment"
+ exit 1
+fi
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/script_test_3.t b/binutils-2.25/gold/testsuite/script_test_3.t
new file mode 100644
index 00000000..accd0559
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_3.t
@@ -0,0 +1,55 @@
+/* script_test_3.t -- linker script test 3 for gold
+
+ Copyright 2008, 2010 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>.
+
+ 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. */
+
+SECTIONS
+{
+ /* With luck this will work everywhere. */
+ . = 0x10000000;
+
+ /* With luck this will be enough to get the program working. */
+ .interp : { *(.interp) } :text :interp
+ .text : { *(.text) } :text
+ /* Required by the ARM target. */
+ .ARM.extab : { *(.ARM.extab*) }
+ .ARM.exidx : { *(.ARM.exidx*) }
+ . += 0x100000;
+ . = ALIGN(0x100);
+ .dynamic : { *(.dynamic) } :data :dynamic
+ .data : { *(.data) } :data
+ .got : { *(.got .toc) }
+ .got.plt : { *(.got.plt) }
+ .tdata : { *(.tdata*) } :data :tls
+ .tbss : { *(.tbss*) } :data :tls
+ . += 0x100000;
+ . = ALIGN(0x100000);
+ .bss : { *(.bss) } :bss
+}
+
+PHDRS
+{
+ text PT_LOAD FILEHDR PHDRS FLAGS(5);
+ interp PT_INTERP;
+ dynamic PT_DYNAMIC FLAGS(4);
+ data PT_LOAD;
+ bss PT_LOAD;
+ tls PT_TLS;
+}
diff --git a/binutils-2.25/gold/testsuite/script_test_4.sh b/binutils-2.25/gold/testsuite/script_test_4.sh
new file mode 100755
index 00000000..755d1a05
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_4.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# script_test_4.sh -- test load segment
+
+# Copyright 2008 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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 goes with script_test_4.t, which is a linker script which
+# starts the program at an unaligned address.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected segment in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check script_test_4.stdout "\\.interp[ ]*PROGBITS[ ]*0*10000400"
diff --git a/binutils-2.25/gold/testsuite/script_test_4.t b/binutils-2.25/gold/testsuite/script_test_4.t
new file mode 100644
index 00000000..3ba5e938
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_4.t
@@ -0,0 +1,45 @@
+/* script_test_4.t -- linker script test 4 for gold
+
+ Copyright 2008 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>.
+
+ 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 won't try to run this program, just ensure that it links
+ as expected. */
+
+SECTIONS
+{
+ . = 0x10000400;
+
+ /* With luck this will be enough to get the program working. */
+ .interp : { *(.interp) }
+ .text : { *(.text) }
+ /* Required by the ARM target. */
+ .ARM.extab : { *(.ARM.extab*) }
+ .ARM.exidx : { *(.ARM.exidx*) }
+ . += 0x100000;
+ . = ALIGN(0x100);
+ .dynamic : { *(.dynamic) }
+ .data : { *(.data) }
+ .got : { *(.got .toc) }
+ .got.plt : { *(.got.plt) }
+ . += 0x100000;
+ . = ALIGN(0x100);
+ .bss : { *(.bss) }
+}
diff --git a/binutils-2.25/gold/testsuite/script_test_5.cc b/binutils-2.25/gold/testsuite/script_test_5.cc
new file mode 100644
index 00000000..b5aec291
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_5.cc
@@ -0,0 +1,45 @@
+// script_test_5.cc -- a test case for gold
+
+// Copyright 2009 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 program checks that the default renaming of ".text.xxx"
+// sections does not take place in the presence of a linker script
+// with a SECTIONS clause.
+
+bool
+t1() __attribute__ ((section (".text.foo")));
+
+bool
+t1()
+{
+ return 1;
+}
+
+// Main function. Initialize variables and call test functions.
+
+int
+main()
+{
+ if (t1())
+ return 0;
+ else
+ return 1;
+}
diff --git a/binutils-2.25/gold/testsuite/script_test_5.sh b/binutils-2.25/gold/testsuite/script_test_5.sh
new file mode 100755
index 00000000..76e2e317
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_5.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# script_test_5.sh -- test linker script with uncovered sections
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# 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 goes with script_test_5.t, which is a linker script with
+# a SECTIONS clause that does not explicitly mention one of the input
+# sections in the test object file. We check to make sure that the
+# correct output section is generated.
+
+check_count()
+{
+ if test "`grep -c "$2" "$1"`" != "$3"
+ then
+ echo "Did not find expected number ($3) of '$2' sections in $1"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check_count script_test_5.stdout " .text " 1
+check_count script_test_5.stdout " .text.foo " 1
diff --git a/binutils-2.25/gold/testsuite/script_test_5.t b/binutils-2.25/gold/testsuite/script_test_5.t
new file mode 100644
index 00000000..4a7d13f6
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_5.t
@@ -0,0 +1,44 @@
+/* script_test_5.t -- linker script test 5 for gold
+
+ Copyright 2009 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@google.com>.
+
+ 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 won't try to run this program, just ensure that it links
+ as expected. */
+
+SECTIONS
+{
+ . = 0x10000000;
+
+ /* With luck this will be enough to get the program working. */
+ .interp : { *(.interp) }
+ .text : { *(.text) }
+ /* Required by the ARM target. */
+ .ARM.extab : { *(.ARM.extab*) }
+ .ARM.exidx : { *(.ARM.exidx*) }
+ . += 0x100000;
+ . = ALIGN(0x100);
+ .dynamic : { *(.dynamic) }
+ .data : { *(.data) }
+ .got : { *(.got .toc) }
+ . += 0x100000;
+ . = ALIGN(0x100);
+ .bss : { *(.bss) }
+}
diff --git a/binutils-2.25/gold/testsuite/script_test_6.sh b/binutils-2.25/gold/testsuite/script_test_6.sh
new file mode 100755
index 00000000..bbc96d8d
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_6.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# script_test_6.sh -- test for -Ttext, -Tdata and -Tbss with a script.
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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 goes with script_test_4.t, which is a linker script which
+# starts the program at an unaligned address.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected section in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check script_test_6.stdout "\\.text[ ]*PROGBITS[ ]*0*10001000"
+check script_test_6.stdout "\\.data[ ]*PROGBITS[ ]*0*10200000"
+check script_test_6.stdout "\\.bss[ ]*NOBITS[ ]*0*10400000"
diff --git a/binutils-2.25/gold/testsuite/script_test_6.t b/binutils-2.25/gold/testsuite/script_test_6.t
new file mode 100644
index 00000000..d3127e39
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_6.t
@@ -0,0 +1,45 @@
+/* script_test_5.t -- linker script test 5 for gold
+
+ Copyright 2009 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@google.com>.
+
+ 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 won't try to run this program, just ensure that it links
+ as expected. */
+
+SECTIONS
+{
+ . = 0x10000000;
+
+ /* With luck this will be enough to get the program working. */
+ .interp : { *(.interp) }
+ .text : { *(.text .text.*) }
+ .rodata : { *(.rodata .rodata.*) }
+ /* Required by the ARM target. */
+ .ARM.extab : { *(.ARM.extab*) }
+ .ARM.exidx : { *(.ARM.exidx*) }
+ . += 0x100000;
+ . = ALIGN(0x100);
+ .dynamic : { *(.dynamic) }
+ .data : { *(.data) }
+ .got : { *(.got .toc) }
+ . += 0x100000;
+ . = ALIGN(0x100);
+ .bss : { *(.bss) }
+}
diff --git a/binutils-2.25/gold/testsuite/script_test_7.sh b/binutils-2.25/gold/testsuite/script_test_7.sh
new file mode 100755
index 00000000..982a1c1a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_7.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# script_test_7.sh -- test for SEGMENT_START expressions.
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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 goes with script_test_4.t, which is a linker script which
+# starts the program at an unaligned address.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected section in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check script_test_7.stdout "\\.interp[ ]*PROGBITS[ ]*0*10000100"
+check script_test_7.stdout "\\.data[ ]*PROGBITS[ ]*0*10200000"
+check script_test_7.stdout "\\.bss[ ]*NOBITS[ ]*0*10400..."
diff --git a/binutils-2.25/gold/testsuite/script_test_7.t b/binutils-2.25/gold/testsuite/script_test_7.t
new file mode 100644
index 00000000..ab2bbeea
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_7.t
@@ -0,0 +1,45 @@
+/* script_test_5.t -- linker script test 5 for gold
+
+ Copyright 2009 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@google.com>.
+
+ 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 won't try to run this program, just ensure that it links
+ as expected. */
+
+SECTIONS
+{
+ . = SEGMENT_START(".text", 0x10000100);
+
+ /* With luck this will be enough to get the program working. */
+ .interp : { *(.interp) }
+ .text : { *(.text .text.*) }
+ .rodata : { *(.rodata .rodata.*) }
+ /* Required by the ARM target. */
+ .ARM.extab : { *(.ARM.extab*) }
+ .ARM.exidx : { *(.ARM.exidx*) }
+ .dynamic : { *(.dynamic) }
+
+ . = SEGMENT_START(".data", 0x10200000);
+ .data : { *(.data) }
+ .got : { *(.got .toc) }
+
+ . = SEGMENT_START(".bss", 0x10400000);
+ .bss : { *(.bss) }
+}
diff --git a/binutils-2.25/gold/testsuite/script_test_8.sh b/binutils-2.25/gold/testsuite/script_test_8.sh
new file mode 100755
index 00000000..83e8e725
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_8.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# script_test_8.sh -- test for SEGMENT_START expressions with
+# -Ttext, -Tdata and -Tbss in a script.
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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 goes with script_test_4.t, which is a linker script which
+# starts the program at an unaligned address.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected section in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check script_test_8.stdout "\\.interp[ ]*PROGBITS[ ]*0*20001000"
+check script_test_8.stdout "\\.data[ ]*PROGBITS[ ]*0*20200000"
+check script_test_8.stdout "\\.bss[ ]*NOBITS[ ]*0*2040...."
diff --git a/binutils-2.25/gold/testsuite/script_test_9.cc b/binutils-2.25/gold/testsuite/script_test_9.cc
new file mode 100644
index 00000000..84f12f6e
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_9.cc
@@ -0,0 +1,29 @@
+// script_test_9.cc -- a test case for gold
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Rafael Avila de Espindola <espindola@google.com>.
+
+// 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 program checks that the default renaming of ".text.xxx"
+// sections does not take place in the presence of a linker script
+// with a SECTIONS clause.
+
+int main() {
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/script_test_9.sh b/binutils-2.25/gold/testsuite/script_test_9.sh
new file mode 100755
index 00000000..9f9aba6f
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_9.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# script_test_9.sh -- Check that the script_test_9.t script has placed
+# .init and .text in the same segment.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Rafael Avila de Espindola <espindola@google.com>.
+
+# 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.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected section in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check script_test_9.stdout "LOAD .*R E "
+check script_test_9.stdout "LOAD .*RW "
+check script_test_9.stdout "00 .*\.text .init"
+check script_test_9.stdout "01 .*\.data "
diff --git a/binutils-2.25/gold/testsuite/script_test_9.t b/binutils-2.25/gold/testsuite/script_test_9.t
new file mode 100644
index 00000000..e7138b27
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/script_test_9.t
@@ -0,0 +1,28 @@
+PHDRS
+{
+ text PT_LOAD FLAGS(5);
+ data PT_LOAD FLAGS(6);
+ tls PT_TLS;
+}
+
+SECTIONS
+{
+ .init :
+ {
+ } :text
+ .text :
+ {
+ }
+ .data :
+ {
+ } :data
+ .got : { *(.got .toc) }
+ .tdata :
+ {
+ *(.tdata*)
+ } :data :tls
+ .tbss :
+ {
+ *(.tbss*)
+ } :data :tls
+}
diff --git a/binutils-2.25/gold/testsuite/searched_file_test.cc b/binutils-2.25/gold/testsuite/searched_file_test.cc
new file mode 100644
index 00000000..aa99e242
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/searched_file_test.cc
@@ -0,0 +1,36 @@
+// searched_file_test.cc -- test -l:foo.a for gold
+
+// Copyright 2009 Free Software Foundation, Inc.
+// Written by Chris Demetriou <cgd@google.com>.
+
+// 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 Linux kernel builds an object file using a linker script, and
+// then links against that object file using the -R option. This is a
+// test for that usage.
+
+#include <cstdlib>
+
+extern int zero_from_lib;
+
+int
+main(int, char**)
+{
+ exit(zero_from_lib);
+}
+
diff --git a/binutils-2.25/gold/testsuite/searched_file_test_lib.cc b/binutils-2.25/gold/testsuite/searched_file_test_lib.cc
new file mode 100644
index 00000000..0686e520
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/searched_file_test_lib.cc
@@ -0,0 +1,27 @@
+// searched_file_test_lib.cc -- test -l:foo.a for gold
+
+// Copyright 2009 Free Software Foundation, Inc.
+// Written by Chris Demetriou <cgd@google.com>.
+
+// 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 Linux kernel builds an object file using a linker script, and
+// then links against that object file using the -R option. This is a
+// test for that usage.
+
+int zero_from_lib = 0;
diff --git a/binutils-2.25/gold/testsuite/section_sorting_name.cc b/binutils-2.25/gold/testsuite/section_sorting_name.cc
new file mode 100644
index 00000000..e89c1ed3
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/section_sorting_name.cc
@@ -0,0 +1,59 @@
+// section_sorting_name.cc -- a test case for gold
+
+// Copyright 2013 Free Software Foundation, Inc.
+// Written by Alexander Ivchenko <alexander.ivchenko@intel.com>.
+
+// 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 goal of this program is to verify that when using --sort-section=name
+// option all .text, .data and .bss sections are sorted by name
+
+extern "C"
+__attribute__ ((section(".text.hot0001")))
+int hot_foo_0001()
+{
+ return 1;
+}
+
+int vdata_0003 __attribute__((section(".data.0003"))) = 3;
+int vbss_0003 __attribute__((section(".bss.0003"))) = 0;
+
+extern "C"
+__attribute__ ((section(".text.hot0003")))
+int hot_foo_0003()
+{
+ return 1;
+}
+
+int vdata_0001 __attribute__((section(".data.0001"))) = 1;
+int vbss_0001 __attribute__((section(".bss.0001"))) = 0;
+
+extern "C"
+__attribute__ ((section(".text.hot0002")))
+int hot_foo_0002()
+{
+ return 1;
+}
+
+int vdata_0002 __attribute__((section(".data.0002"))) = 2;
+int vbss_0002 __attribute__((section(".bss.0002"))) = 0;
+
+int main()
+{
+ return 1;
+}
diff --git a/binutils-2.25/gold/testsuite/section_sorting_name.sh b/binutils-2.25/gold/testsuite/section_sorting_name.sh
new file mode 100755
index 00000000..00b6994e
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/section_sorting_name.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+# section_sorting_name.sh -- test
+
+# Copyright 2013 Free Software Foundation, Inc.
+# Written by Alexander Ivchenko <alexander.ivchenko@intel.com>.
+
+# 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 goal of this program is to verify that when using --sort-section=name
+# option all .text, .data, and .bss sections are sorted by name
+
+set -e
+
+check()
+{
+ awk "
+BEGIN { saw1 = 0; saw2 = 0; err = 0; }
+/.*$2\$/ { saw1 = 1; }
+/.*$3\$/ {
+ saw2 = 1;
+ if (!saw1)
+ {
+ printf \"layout of $2 and $3 is not right\\n\";
+ err = 1;
+ exit 1;
+ }
+ }
+END {
+ if (!saw1 && !err)
+ {
+ printf \"did not see $2\\n\";
+ exit 1;
+ }
+ if (!saw2 && !err)
+ {
+ printf \"did not see $3\\n\";
+ exit 1;
+ }
+ }" $1
+}
+
+# addr (hot_foo_0001) < addr (hot_foo_0002) < addr (hot_foo_0003)
+check section_sorting_name.stdout "hot_foo_0001" "hot_foo_0002"
+check section_sorting_name.stdout "hot_foo_0002" "hot_foo_0003"
+
+check section_sorting_name.stdout "vdata_0001" "vdata_0002"
+check section_sorting_name.stdout "vdata_0002" "vdata_0003"
+
+check section_sorting_name.stdout "vbss_0001" "vbss_0002"
+check section_sorting_name.stdout "vbss_0002" "vbss_0003"
diff --git a/binutils-2.25/gold/testsuite/split_i386.sh b/binutils-2.25/gold/testsuite/split_i386.sh
new file mode 100755
index 00000000..e94fea2b
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/split_i386.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# split_i386.sh -- test -fstack-split for i386
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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.
+
+match()
+{
+ if ! egrep "$1" "$2" >/dev/null 2>&1; then
+ echo 1>&2 "could not find '$1' in $2"
+ exit 1
+ fi
+}
+
+nomatch()
+{
+ if egrep "$1" "$2" >/dev/null 2>&1; then
+ echo 1>&2 "found unexpected '$1' in $2"
+ exit 1
+ fi
+}
+
+match 'cmp.*+%gs:[^,]*,%esp' split_i386_1.stdout
+match 'call.*__morestack>?$' split_i386_1.stdout
+match 'lea.*-0x200\(%esp\),' split_i386_1.stdout
+
+match 'stc' split_i386_2.stdout
+match 'call.*__morestack_non_split>?$' split_i386_2.stdout
+nomatch 'call.*__morestack>?$' split_i386_2.stdout
+match 'lea.*-0x4200\(%esp\),' split_i386_2.stdout
+
+match 'failed to match' split_i386_3.stdout
+
+match 'call.*__morestack>?$' split_i386_4.stdout
+
+match 'cannot mix' split_i386_r.stdout
diff --git a/binutils-2.25/gold/testsuite/split_i386_1.s b/binutils-2.25/gold/testsuite/split_i386_1.s
new file mode 100644
index 00000000..9ac816ea
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/split_i386_1.s
@@ -0,0 +1,33 @@
+# split_i386_1.s: i386 specific test case for -fsplit-stack.
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ cmp %gs:0x30,%esp
+ jae 1f
+ call __morestack
+ ret
+1:
+ call fn2
+ ret
+
+ .size fn1,. - fn1
+
+ .global fn2
+ .type fn2,@function
+fn2:
+ lea -0x200(%esp),%ecx
+ cmp %gs:0x30,%ecx
+ jae 1f
+ call __morestack
+ ret
+1:
+ call fn1
+ ret
+
+ .size fn2,. - fn2
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/split_i386_2.s b/binutils-2.25/gold/testsuite/split_i386_2.s
new file mode 100644
index 00000000..b4a2f143
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/split_i386_2.s
@@ -0,0 +1,33 @@
+# split_i386_2.s: i386 specific, -fsplit-stack calling non-split
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ cmp %gs:0x30,%esp
+ jae 1f
+ call __morestack
+ ret
+1:
+ call fn3
+ ret
+
+ .size fn1,. - fn1
+
+ .global fn2
+ .type fn2,@function
+fn2:
+ lea -0x200(%esp),%ecx
+ cmp %gs:0x30,%ecx
+ jae 1f
+ call __morestack
+ ret
+1:
+ call fn3
+ ret
+
+ .size fn2,. - fn2
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/split_i386_3.s b/binutils-2.25/gold/testsuite/split_i386_3.s
new file mode 100644
index 00000000..fdde7a92
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/split_i386_3.s
@@ -0,0 +1,22 @@
+# split_i386_3.s: i386 specific, adjustment failure
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ push %ebp
+ mov %esp,%ebp
+ cmp %gs:0x30,%esp
+ jae 1f
+ call __morestack
+ ret
+1:
+ call fn3
+ leave
+ ret
+
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/split_i386_4.s b/binutils-2.25/gold/testsuite/split_i386_4.s
new file mode 100644
index 00000000..be774ae6
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/split_i386_4.s
@@ -0,0 +1,23 @@
+# split_i386_4.s: i386 specific, permitted adjustment failure
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ push %ebp
+ mov %esp,%ebp
+ cmp %gs:0x30,%esp
+ jae 1f
+ call __morestack
+ ret
+1:
+ call fn3
+ leave
+ ret
+
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
+ .section .note.GNU-no-split-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/split_i386_n.s b/binutils-2.25/gold/testsuite/split_i386_n.s
new file mode 100644
index 00000000..4d4e6e88
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/split_i386_n.s
@@ -0,0 +1,12 @@
+# split_i386_n.s: i386 specific, -fsplit-stack calling non-split
+
+ .text
+
+ .global fn3
+ .type fn3,@function
+fn3:
+ ret
+
+ .size fn3,. - fn3
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/split_x86_64.sh b/binutils-2.25/gold/testsuite/split_x86_64.sh
new file mode 100755
index 00000000..61544b29
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/split_x86_64.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# split_x86_64.sh -- test -fstack-split for x86_64
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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.
+
+match()
+{
+ if ! egrep "$1" "$2" >/dev/null 2>&1; then
+ echo 1>&2 "could not find '$1' in $2"
+ exit 1
+ fi
+}
+
+nomatch()
+{
+ if egrep "$1" "$2" >/dev/null 2>&1; then
+ echo 1>&2 "found unexpected '$1' in $2"
+ exit 1
+ fi
+}
+
+match 'cmp.*+%fs:[^,]*,%rsp' split_x86_64_1.stdout
+match 'callq.*__morestack>?$' split_x86_64_1.stdout
+match 'lea.*-0x200\(%rsp\),' split_x86_64_1.stdout
+
+match 'stc' split_x86_64_2.stdout
+match 'callq.*__morestack_non_split>?$' split_x86_64_2.stdout
+nomatch 'callq.*__morestack>?$' split_x86_64_2.stdout
+match 'lea.*-0x4200\(%rsp\),' split_x86_64_2.stdout
+
+match 'failed to match' split_x86_64_3.stdout
+
+match 'callq.*__morestack>?$' split_x86_64_4.stdout
+
+match 'cannot mix' split_x86_64_r.stdout
diff --git a/binutils-2.25/gold/testsuite/split_x86_64_1.s b/binutils-2.25/gold/testsuite/split_x86_64_1.s
new file mode 100644
index 00000000..e23ea7fe
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/split_x86_64_1.s
@@ -0,0 +1,33 @@
+# split_x86_64_1.s: x86_64 specific test case for -fsplit-stack.
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ cmp %fs:0x70,%rsp
+ jae 1f
+ callq __morestack
+ retq
+1:
+ callq fn2
+ retq
+
+ .size fn1,. - fn1
+
+ .global fn2
+ .type fn2,@function
+fn2:
+ lea -0x200(%rsp),%r10
+ cmp %fs:0x70,%r10
+ jae 1f
+ callq __morestack
+ retq
+1:
+ callq fn1
+ retq
+
+ .size fn2,. - fn2
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/split_x86_64_2.s b/binutils-2.25/gold/testsuite/split_x86_64_2.s
new file mode 100644
index 00000000..0559bbc0
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/split_x86_64_2.s
@@ -0,0 +1,33 @@
+# split_x86_64_2.s: x86_64 specific, -fsplit-stack calling non-split
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ cmp %fs:0x70,%rsp
+ jae 1f
+ callq __morestack
+ retq
+1:
+ callq fn3
+ retq
+
+ .size fn1,. - fn1
+
+ .global fn2
+ .type fn2,@function
+fn2:
+ lea -0x200(%rsp),%r10
+ cmp %fs:0x70,%r10
+ jae 1f
+ callq __morestack
+ retq
+1:
+ callq fn3
+ retq
+
+ .size fn2,. - fn2
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/split_x86_64_3.s b/binutils-2.25/gold/testsuite/split_x86_64_3.s
new file mode 100644
index 00000000..68ae6e35
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/split_x86_64_3.s
@@ -0,0 +1,22 @@
+# split_x86_64_3.s: x86_64 specific, adjustment failure
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ push %rbp
+ mov %rsp,%rbp
+ cmp %fs:0x70,%rsp
+ jae 1f
+ callq __morestack
+ retq
+1:
+ callq fn3
+ leaveq
+ retq
+
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/split_x86_64_4.s b/binutils-2.25/gold/testsuite/split_x86_64_4.s
new file mode 100644
index 00000000..653b917b
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/split_x86_64_4.s
@@ -0,0 +1,23 @@
+# split_x86_64_4.s: x86_64 specific, permitted adjustment failure
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ push %rbp
+ mov %rsp,%rbp
+ cmp %fs:0x70,%rsp
+ jae 1f
+ callq __morestack
+ retq
+1:
+ callq fn3
+ leaveq
+ retq
+
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
+ .section .note.GNU-no-split-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/split_x86_64_n.s b/binutils-2.25/gold/testsuite/split_x86_64_n.s
new file mode 100644
index 00000000..10436b15
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/split_x86_64_n.s
@@ -0,0 +1,12 @@
+# split_x86_64_n.s: x86_64 specific, -fsplit-stack calling non-split
+
+ .text
+
+ .global fn3
+ .type fn3,@function
+fn3:
+ retq
+
+ .size fn3,. - fn3
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/binutils-2.25/gold/testsuite/start_lib_test_1.c b/binutils-2.25/gold/testsuite/start_lib_test_1.c
new file mode 100644
index 00000000..024276a9
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/start_lib_test_1.c
@@ -0,0 +1,32 @@
+/* start_lib_test_1.c -- test --start-lib/--end-lib.
+
+ Copyright 2010 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@google.com>
+
+ 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 is a test of the --start-lib and --end-lib options. */
+
+extern void t1 (void);
+extern void t2 (void);
+
+void
+t1 (void)
+{
+ t2 ();
+}
diff --git a/binutils-2.25/gold/testsuite/start_lib_test_2.c b/binutils-2.25/gold/testsuite/start_lib_test_2.c
new file mode 100644
index 00000000..443a79cf
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/start_lib_test_2.c
@@ -0,0 +1,30 @@
+/* start_lib_test_2.c -- test --start-lib/--end-lib.
+
+ Copyright 2010 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@google.com>
+
+ 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 is a test of the --start-lib and --end-lib options. */
+
+extern void t2 (void);
+
+void
+t2 (void)
+{
+}
diff --git a/binutils-2.25/gold/testsuite/start_lib_test_3.c b/binutils-2.25/gold/testsuite/start_lib_test_3.c
new file mode 100644
index 00000000..79b467b7
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/start_lib_test_3.c
@@ -0,0 +1,25 @@
+/* start_lib_test_3.c -- test --start-lib/--end-lib.
+
+ Copyright 2010 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@google.com>
+
+ 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 is a test of the --start-lib and --end-lib options. */
+
+static char t3[] __attribute__ ((used)) = "t3";
diff --git a/binutils-2.25/gold/testsuite/start_lib_test_main.c b/binutils-2.25/gold/testsuite/start_lib_test_main.c
new file mode 100644
index 00000000..7809baa5
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/start_lib_test_main.c
@@ -0,0 +1,33 @@
+/* start_lib_test_main.c -- test --start-lib/--end-lib.
+
+ Copyright 2010 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@google.com>
+
+ 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 is a test of the --start-lib and --end-lib options. */
+
+extern void t1 (void);
+
+int
+main (int argc __attribute__ ((unused)),
+ char** argv __attribute__ ((unused)))
+{
+ t1 ();
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/strong_ref_weak_def.sh b/binutils-2.25/gold/testsuite/strong_ref_weak_def.sh
new file mode 100755
index 00000000..17afc5bd
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/strong_ref_weak_def.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# strong_ref_weak_def.sh -- test non-weak reference to a weak symbol defined
+# in a DSO.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# 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 checks that the reference to 'weak_def' have GLOBAL binding.
+
+check()
+{
+ file=$1
+ pattern=$2
+ found=`grep "$pattern" $file`
+ if test -z "$found"; then
+ echo "pattern \"$pattern\" not found in file $file."
+ echo $found
+ exit 1
+ fi
+}
+
+check strong_ref_weak_def.stdout ".* FUNC.* GLOBAL.* UND.* weak_def"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/strong_ref_weak_def_1.c b/binutils-2.25/gold/testsuite/strong_ref_weak_def_1.c
new file mode 100644
index 00000000..bc00e770
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/strong_ref_weak_def_1.c
@@ -0,0 +1,39 @@
+// strong_ref_weak_def_1.c -- test a strong reference to a weak definition
+// in a DSO.
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Doug Kwan <dougkwan@google.com>.
+
+// 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 test that we correctly deal with a non-weak reference to
+// a weak symbol in an DSO. We need to make sure that reference
+// is not turned into a weak one.
+
+// This source is used to build an executable that references a weak
+// symbol in a DSO.
+
+// Strong reference to a weak symbol.
+extern void weak_def (void);
+
+int
+main (void)
+{
+ weak_def ();
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/strong_ref_weak_def_2.c b/binutils-2.25/gold/testsuite/strong_ref_weak_def_2.c
new file mode 100644
index 00000000..4801f6d2
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/strong_ref_weak_def_2.c
@@ -0,0 +1,37 @@
+// strong_ref_weak_def_2.c -- test a strong reference to a weak definition
+// in a DSO.
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Doug Kwan <dougkwan@google.com>.
+
+// 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 test that we correctly deal with a non-weak reference to
+// a weak symbol in an DSO. We need to make sure that reference
+// is not turned into a weak one.
+
+// This source is used to build a shared library that defines a
+// weak symbol.
+
+void weak_def (void);
+
+void
+__attribute__((weak))
+weak_def (void)
+{
+}
diff --git a/binutils-2.25/gold/testsuite/test.cc b/binutils-2.25/gold/testsuite/test.cc
new file mode 100644
index 00000000..b08d6d77
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/test.cc
@@ -0,0 +1,107 @@
+// test.cc -- simplistic test framework for gold.
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include "gold.h"
+
+#include <cstdio>
+
+#include "test.h"
+
+namespace gold_testsuite
+{
+
+// Test_framework methods.
+
+// The current test being run.
+
+Test_report* Test_framework::current_report;
+
+// Run a test.
+
+void
+Test_framework::run(const char *name, bool (*pfn)(Test_report*))
+{
+ this->testname_ = name;
+ this->current_fail_ = false;
+
+ Test_report tr(this);
+ Test_framework::current_report = &tr;
+
+ if ((*pfn)(&tr) && !this->current_fail_)
+ {
+ printf("PASS: %s\n", name);
+ ++this->passes_;
+ }
+ else
+ {
+ printf("FAIL: %s\n", name);
+ ++this->failures_;
+ }
+
+ Test_framework::current_report = NULL;
+ this->testname_ = NULL;
+}
+
+// Report a failure.
+
+void
+Test_framework::fail(const char* filename, int lineno)
+{
+ printf("FAIL: %s: %s: %d\n", this->testname_, filename, lineno);
+ this->current_fail_ = true;
+}
+
+// Let a test report an error.
+
+void
+Test_framework::error(const char* message)
+{
+ printf("ERROR: %s: %s\n", this->testname_, message);
+ this->current_fail_ = true;
+}
+
+// Register_test methods.
+
+// Linked list of all registered tests.
+
+Register_test* Register_test::all_tests;
+
+// Register a test.
+
+Register_test::Register_test(const char* name, bool (*pfn)(Test_report*))
+ : name_(name), pfn_(pfn), next_(Register_test::all_tests)
+{
+ Register_test::all_tests = this;
+}
+
+// Run all registered tests.
+
+void
+Register_test::run_tests(Test_framework* tf)
+{
+ for (Register_test* p = Register_test::all_tests;
+ p != NULL;
+ p = p->next_)
+ tf->run(p->name_, p->pfn_);
+}
+
+} // End namespace gold_testsuite.
diff --git a/binutils-2.25/gold/testsuite/test.h b/binutils-2.25/gold/testsuite/test.h
new file mode 100644
index 00000000..37060d3a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/test.h
@@ -0,0 +1,145 @@
+// test.h -- simplistic test framework for gold unittests -*- C++ -*-
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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_TESTSUITE_TEST_H
+#define GOLD_TESTSUITE_TEST_H
+
+namespace gold_testsuite
+{
+
+class Test_report;
+
+// This class handles basic test framework functionality.
+
+class Test_framework
+{
+ public:
+ Test_framework()
+ : testname_(NULL), current_fail_(0), passes_(0), failures_(0)
+ { }
+
+ // Return number of failures.
+ unsigned int
+ failures() const
+ { return this->failures_; }
+
+ // Run a test.
+ void
+ run(const char* name, bool (*pfn)(Test_report*));
+
+ // Get the current Test_report. This is used by the test support
+ // macros.
+ static Test_report*
+ report()
+ { return Test_framework::current_report; }
+
+ private:
+ friend class Test_report;
+
+ // Cause the current test to fail.
+ void
+ fail(const char* filename, int lineno);
+
+ // Report an error from the current test.
+ void
+ error(const char* message);
+
+ // Current Test_report. This is a static variable valid while a
+ // test is being run.
+ static Test_report* current_report;
+
+ // Current test being run.
+ const char* testname_;
+ // Whether the current test is failing.
+ bool current_fail_;
+ // Total number of passeed tests.
+ unsigned int passes_;
+ // Total number of failed tests.
+ unsigned int failures_;
+};
+
+// An instance of this class is passed to each test function.
+
+class Test_report
+{
+public:
+ Test_report(Test_framework* tf)
+ : tf_(tf)
+ { }
+
+ // Mark the test as failing.
+ void
+ fail(const char* filename, int lineno)
+ { this->tf_->fail(filename, lineno); }
+
+ // Report an error.
+ void
+ error(const char* message)
+ { this->tf_->error(message); }
+
+private:
+ Test_framework* tf_;
+};
+
+// This class registers a test function so that the testsuite runs it.
+
+class Register_test
+{
+ public:
+ Register_test(const char* name, bool (*pfn)(Test_report*));
+
+ // Run all registered tests.
+ static void
+ run_tests(Test_framework*);
+
+ private:
+ // Linked list of all tests.
+ static Register_test* all_tests;
+
+ // Test name.
+ const char* name_;
+ // Function to call. It should return true if the test passes,
+ // false if it fails.
+ bool (*pfn_)(Test_report*);
+ // Next test in linked list.
+ Register_test* next_;
+};
+
+} // End namespace gold_testsuite.
+
+// These macros are for convenient use in tests.
+
+// Check that a condition is true. If it is false, report a failure.
+
+#define CHECK(cond) \
+ ((void) \
+ ((cond) \
+ ? 0 \
+ : (::gold_testsuite::Test_framework::report()->fail(__FILE__, \
+ __LINE__), \
+ 0)))
+
+// Report an error during a test.
+
+#define ERROR(msg) (::gold_testsuite::Test_framework::report()->error(msg))
+
+#endif // !defined(GOLD_TESTSUITE_TEST_H)
diff --git a/binutils-2.25/gold/testsuite/testfile.cc b/binutils-2.25/gold/testsuite/testfile.cc
new file mode 100644
index 00000000..f360e3d0
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/testfile.cc
@@ -0,0 +1,949 @@
+// testfile.cc -- Dummy ELF objects for testing purposes.
+
+// Copyright 2006, 2007, 2008, 2009, 2011, 2012 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// 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 "target.h"
+#include "target-select.h"
+
+#include "test.h"
+#include "testfile.h"
+
+namespace gold_testsuite
+{
+
+using namespace gold;
+
+// A Target used for testing purposes.
+
+template<int size, bool big_endian>
+class Target_test : public Sized_target<size, big_endian>
+{
+ public:
+ Target_test()
+ : Sized_target<size, big_endian>(&test_target_info)
+ { }
+
+ void
+ gc_process_relocs(Symbol_table*, Layout*,
+ Sized_relobj_file<size, big_endian>*,
+ unsigned int, unsigned int, const unsigned char*, size_t,
+ Output_section*, bool, size_t, const unsigned char*)
+ { ERROR("call to Target_test::gc_process_relocs"); }
+
+ void
+ scan_relocs(Symbol_table*, Layout*, Sized_relobj_file<size, big_endian>*,
+ unsigned int, unsigned int, const unsigned char*, size_t,
+ Output_section*, bool, size_t, const unsigned char*)
+ { ERROR("call to Target_test::scan_relocs"); }
+
+ void
+ relocate_section(const Relocate_info<size, big_endian>*, unsigned int,
+ const unsigned char*, size_t, Output_section*, bool,
+ unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
+ section_size_type, const Reloc_symbol_changes*)
+ { ERROR("call to Target_test::relocate_section"); }
+
+ void
+ scan_relocatable_relocs(Symbol_table*, Layout*,
+ Sized_relobj_file<size, big_endian>*, unsigned int,
+ unsigned int, const unsigned char*,
+ size_t, Output_section*, bool, size_t,
+ const unsigned char*, Relocatable_relocs*)
+ { ERROR("call to Target_test::scan_relocatable_relocs"); }
+
+ void
+ relocate_relocs(const Relocate_info<size, big_endian>*,
+ unsigned int, const unsigned char*, size_t,
+ Output_section*, typename elfcpp::Elf_types<size>::Elf_Off,
+ const Relocatable_relocs*, unsigned char*,
+ typename elfcpp::Elf_types<size>::Elf_Addr,
+ section_size_type, unsigned char*,
+ section_size_type)
+ { ERROR("call to Target_test::relocate_relocs"); }
+
+ static const Target::Target_info test_target_info;
+};
+
+template<int size, bool big_endian>
+const Target::Target_info Target_test<size, big_endian>::test_target_info =
+{
+ size, // size
+ big_endian, // is_big_endian
+ static_cast<elfcpp::EM>(0xffff), // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ false, // has_code_fill
+ false, // is_default_stack_executable
+ false, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/dummy", // dynamic_linker
+ 0x08000000, // default_text_segment_address
+ 0x1000, // abi_pagesize
+ 0x1000, // common_pagesize
+ false, // isolate_execinstr
+ 0, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0, // large_common_section_flags
+ NULL, // attributes_section
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
+};
+
+// The test targets.
+
+#ifdef HAVE_TARGET_32_LITTLE
+Target_test<32, false> target_test_32_little;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+Target_test<32, true> target_test_32_big;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+Target_test<64, false> target_test_64_little;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+Target_test<64, true> target_test_64_big;
+#endif
+
+// A pointer to the test targets. This is used in CHECKs.
+
+#ifdef HAVE_TARGET_32_LITTLE
+Target* target_test_pointer_32_little = &target_test_32_little;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+Target* target_test_pointer_32_big = &target_test_32_big;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+Target* target_test_pointer_64_little = &target_test_64_little;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+Target* target_test_pointer_64_big = &target_test_64_big;
+#endif
+
+// Select the test targets.
+
+template<int size, bool big_endian>
+class Target_selector_test : public Target_selector
+{
+ public:
+ Target_selector_test()
+ : Target_selector(0xffff, size, big_endian, NULL, NULL)
+ { }
+
+ virtual Target*
+ do_instantiate_target()
+ {
+ gold_unreachable();
+ return NULL;
+ }
+
+ virtual Target*
+ do_recognize(Input_file*, off_t, int, int, int)
+ {
+ if (size == 32)
+ {
+ if (!big_endian)
+ {
+#ifdef HAVE_TARGET_32_LITTLE
+ return &target_test_32_little;
+#endif
+ }
+ else
+ {
+#ifdef HAVE_TARGET_32_BIG
+ return &target_test_32_big;
+#endif
+ }
+ }
+ else
+ {
+ if (!big_endian)
+ {
+#ifdef HAVE_TARGET_64_LITTLE
+ return &target_test_64_little;
+#endif
+ }
+ else
+ {
+#ifdef HAVE_TARGET_64_BIG
+ return &target_test_64_big;
+#endif
+ }
+ }
+
+ return NULL;
+ }
+
+ virtual Target*
+ do_recognize_by_name(const char*)
+ { return NULL; }
+
+ virtual void
+ do_supported_names(std::vector<const char*>*)
+ { }
+};
+
+// Register the test target selectors. These don't need to be
+// conditionally compiled, as they will return NULL if there is no
+// support for them.
+
+Target_selector_test<32, false> target_selector_test_32_little;
+Target_selector_test<32, true> target_selector_test_32_big;
+Target_selector_test<64, false> target_selector_test_64_little;
+Target_selector_test<64, true> target_selector_test_64_big;
+
+// A simple ELF object with one empty section, named ".test" and one
+// globally visible symbol named "test".
+
+const unsigned char test_file_1_32_little[] =
+{
+ // Ehdr
+ // EI_MAG[0-3]
+ 0x7f, 'E', 'L', 'F',
+ // EI_CLASS: 32 bit.
+ 1,
+ // EI_DATA: little endian
+ 1,
+ // EI_VERSION
+ 1,
+ // EI_OSABI
+ 0,
+ // EI_ABIVERSION
+ 0,
+ // EI_PAD
+ 0, 0, 0, 0, 0, 0, 0,
+ // e_type: ET_REL
+ 1, 0,
+ // e_machine: a magic value used for testing.
+ 0xff, 0xff,
+ // e_version
+ 1, 0, 0, 0,
+ // e_entry
+ 0, 0, 0, 0,
+ // e_phoff
+ 0, 0, 0, 0,
+ // e_shoff: starts right after file header
+ 52, 0, 0, 0,
+ // e_flags
+ 0, 0, 0, 0,
+ // e_ehsize
+ 52, 0,
+ // e_phentsize
+ 32, 0,
+ // e_phnum
+ 0, 0,
+ // e_shentsize
+ 40, 0,
+ // e_shnum: dummy, .test, .symtab, .strtab, .shstrtab
+ 5, 0,
+ // e_shstrndx
+ 4, 0,
+
+ // Offset 52
+ // Shdr 0: dummy entry
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 92
+ // Shdr 1: .test
+ // sh_name: after initial null
+ 1, 0, 0, 0,
+ // sh_type: SHT_PROGBITS
+ 1, 0, 0, 0,
+ // sh_flags: SHF_ALLOC
+ 2, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0,
+ // sh_offset: after file header + 5 section headers
+ 252, 0, 0, 0,
+ // sh_size
+ 0, 0, 0, 0,
+ // sh_link
+ 0, 0, 0, 0,
+ // sh_info
+ 0, 0, 0, 0,
+ // sh_addralign
+ 1, 0, 0, 0,
+ // sh_entsize
+ 0, 0, 0, 0,
+
+ // Offset 132
+ // Shdr 2: .symtab
+ // sh_name: 1 null byte + ".test\0"
+ 7, 0, 0, 0,
+ // sh_type: SHT_SYMTAB
+ 2, 0, 0, 0,
+ // sh_flags
+ 0, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0,
+ // sh_offset: after file header + 5 section headers + empty section
+ 252, 0, 0, 0,
+ // sh_size: two symbols: dummy symbol + test symbol
+ 32, 0, 0, 0,
+ // sh_link: to .strtab
+ 3, 0, 0, 0,
+ // sh_info: one local symbol, the dummy symbol
+ 1, 0, 0, 0,
+ // sh_addralign
+ 4, 0, 0, 0,
+ // sh_entsize: size of symbol
+ 16, 0, 0, 0,
+
+ // Offset 172
+ // Shdr 3: .strtab
+ // sh_name: 1 null byte + ".test\0" + ".symtab\0"
+ 15, 0, 0, 0,
+ // sh_type: SHT_STRTAB
+ 3, 0, 0, 0,
+ // sh_flags
+ 0, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0,
+ // sh_offset: after .symtab section. 284 == 0x11c
+ 0x1c, 0x1, 0, 0,
+ // sh_size: 1 null byte + "test\0"
+ 6, 0, 0, 0,
+ // sh_link
+ 0, 0, 0, 0,
+ // sh_info
+ 0, 0, 0, 0,
+ // sh_addralign
+ 1, 0, 0, 0,
+ // sh_entsize
+ 0, 0, 0, 0,
+
+ // Offset 212
+ // Shdr 4: .shstrtab
+ // sh_name: 1 null byte + ".test\0" + ".symtab\0" + ".strtab\0"
+ 23, 0, 0, 0,
+ // sh_type: SHT_STRTAB
+ 3, 0, 0, 0,
+ // sh_flags
+ 0, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0,
+ // sh_offset: after .strtab section. 290 == 0x122
+ 0x22, 0x1, 0, 0,
+ // sh_size: all section names
+ 33, 0, 0, 0,
+ // sh_link
+ 0, 0, 0, 0,
+ // sh_info
+ 0, 0, 0, 0,
+ // sh_addralign
+ 1, 0, 0, 0,
+ // sh_entsize
+ 0, 0, 0, 0,
+
+ // Offset 252
+ // Contents of .symtab section
+ // Symbol 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 268
+ // Symbol 1
+ // st_name
+ 1, 0, 0, 0,
+ // st_value
+ 0, 0, 0, 0,
+ // st_size
+ 0, 0, 0, 0,
+ // st_info: STT_NOTYPE, STB_GLOBAL
+ 0x10,
+ // st_other
+ 0,
+ // st_shndx: In .test
+ 1, 0,
+
+ // Offset 284
+ // Contents of .strtab section
+ '\0',
+ 't', 'e', 's', 't', '\0',
+
+ // Offset 290
+ // Contents of .shstrtab section
+ '\0',
+ '.', 't', 'e', 's', 't', '\0',
+ '.', 's', 'y', 'm', 't', 'a', 'b', '\0',
+ '.', 's', 't', 'r', 't', 'a', 'b', '\0',
+ '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', '\0'
+};
+
+const unsigned int test_file_1_size_32_little = sizeof test_file_1_32_little;
+
+// 32-bit big-endian version of test_file_1_32_little.
+
+const unsigned char test_file_1_32_big[] =
+{
+ // Ehdr
+ // EI_MAG[0-3]
+ 0x7f, 'E', 'L', 'F',
+ // EI_CLASS: 32 bit.
+ 1,
+ // EI_DATA: big endian
+ 2,
+ // EI_VERSION
+ 1,
+ // EI_OSABI
+ 0,
+ // EI_ABIVERSION
+ 0,
+ // EI_PAD
+ 0, 0, 0, 0, 0, 0, 0,
+ // e_type: ET_REL
+ 0, 1,
+ // e_machine: a magic value used for testing.
+ 0xff, 0xff,
+ // e_version
+ 0, 0, 0, 1,
+ // e_entry
+ 0, 0, 0, 0,
+ // e_phoff
+ 0, 0, 0, 0,
+ // e_shoff: starts right after file header
+ 0, 0, 0, 52,
+ // e_flags
+ 0, 0, 0, 0,
+ // e_ehsize
+ 0, 52,
+ // e_phentsize
+ 0, 32,
+ // e_phnum
+ 0, 0,
+ // e_shentsize
+ 0, 40,
+ // e_shnum: dummy, .test, .symtab, .strtab, .shstrtab
+ 0, 5,
+ // e_shstrndx
+ 0, 4,
+
+ // Offset 52
+ // Shdr 0: dummy entry
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 92
+ // Shdr 1: .test
+ // sh_name: after initial null
+ 0, 0, 0, 1,
+ // sh_type: SHT_PROGBITS
+ 0, 0, 0, 1,
+ // sh_flags: SHF_ALLOC
+ 0, 0, 0, 2,
+ // sh_addr
+ 0, 0, 0, 0,
+ // sh_offset: after file header + 5 section headers
+ 0, 0, 0, 252,
+ // sh_size
+ 0, 0, 0, 0,
+ // sh_link
+ 0, 0, 0, 0,
+ // sh_info
+ 0, 0, 0, 0,
+ // sh_addralign
+ 0, 0, 0, 1,
+ // sh_entsize
+ 0, 0, 0, 0,
+
+ // Offset 132
+ // Shdr 2: .symtab
+ // sh_name: 1 null byte + ".test\0"
+ 0, 0, 0, 7,
+ // sh_type: SHT_SYMTAB
+ 0, 0, 0, 2,
+ // sh_flags
+ 0, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0,
+ // sh_offset: after file header + 5 section headers + empty section
+ 0, 0, 0, 252,
+ // sh_size: two symbols: dummy symbol + test symbol
+ 0, 0, 0, 32,
+ // sh_link: to .strtab
+ 0, 0, 0, 3,
+ // sh_info: one local symbol, the dummy symbol
+ 0, 0, 0, 1,
+ // sh_addralign
+ 0, 0, 0, 4,
+ // sh_entsize: size of symbol
+ 0, 0, 0, 16,
+
+ // Offset 172
+ // Shdr 3: .strtab
+ // sh_name: 1 null byte + ".test\0" + ".symtab\0"
+ 0, 0, 0, 15,
+ // sh_type: SHT_STRTAB
+ 0, 0, 0, 3,
+ // sh_flags
+ 0, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0,
+ // sh_offset: after .symtab section. 284 == 0x11c
+ 0, 0, 0x1, 0x1c,
+ // sh_size: 1 null byte + "test\0"
+ 0, 0, 0, 6,
+ // sh_link
+ 0, 0, 0, 0,
+ // sh_info
+ 0, 0, 0, 0,
+ // sh_addralign
+ 0, 0, 0, 1,
+ // sh_entsize
+ 0, 0, 0, 0,
+
+ // Offset 212
+ // Shdr 4: .shstrtab
+ // sh_name: 1 null byte + ".test\0" + ".symtab\0" + ".strtab\0"
+ 0, 0, 0, 23,
+ // sh_type: SHT_STRTAB
+ 0, 0, 0, 3,
+ // sh_flags
+ 0, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0,
+ // sh_offset: after .strtab section. 290 == 0x122
+ 0, 0, 0x1, 0x22,
+ // sh_size: all section names
+ 0, 0, 0, 33,
+ // sh_link
+ 0, 0, 0, 0,
+ // sh_info
+ 0, 0, 0, 0,
+ // sh_addralign
+ 0, 0, 0, 1,
+ // sh_entsize
+ 0, 0, 0, 0,
+
+ // Offset 252
+ // Contents of .symtab section
+ // Symbol 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 268
+ // Symbol 1
+ // st_name
+ 0, 0, 0, 1,
+ // st_value
+ 0, 0, 0, 0,
+ // st_size
+ 0, 0, 0, 0,
+ // st_info: STT_NOTYPE, STB_GLOBAL
+ 0x10,
+ // st_other
+ 0,
+ // st_shndx: In .test
+ 0, 1,
+
+ // Offset 284
+ // Contents of .strtab section
+ '\0',
+ 't', 'e', 's', 't', '\0',
+
+ // Offset 290
+ // Contents of .shstrtab section
+ '\0',
+ '.', 't', 'e', 's', 't', '\0',
+ '.', 's', 'y', 'm', 't', 'a', 'b', '\0',
+ '.', 's', 't', 'r', 't', 'a', 'b', '\0',
+ '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', '\0'
+};
+
+const unsigned int test_file_1_size_32_big = sizeof test_file_1_32_big;
+
+// 64-bit little-endian version of test_file_1_32_little.
+
+const unsigned char test_file_1_64_little[] =
+{
+ // Ehdr
+ // EI_MAG[0-3]
+ 0x7f, 'E', 'L', 'F',
+ // EI_CLASS: 64 bit.
+ 2,
+ // EI_DATA: little endian
+ 1,
+ // EI_VERSION
+ 1,
+ // EI_OSABI
+ 0,
+ // EI_ABIVERSION
+ 0,
+ // EI_PAD
+ 0, 0, 0, 0, 0, 0, 0,
+ // e_type: ET_REL
+ 1, 0,
+ // e_machine: a magic value used for testing.
+ 0xff, 0xff,
+ // e_version
+ 1, 0, 0, 0,
+ // e_entry
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // e_phoff
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // e_shoff: starts right after file header
+ 64, 0, 0, 0, 0, 0, 0, 0,
+ // e_flags
+ 0, 0, 0, 0,
+ // e_ehsize
+ 64, 0,
+ // e_phentsize
+ 56, 0,
+ // e_phnum
+ 0, 0,
+ // e_shentsize
+ 64, 0,
+ // e_shnum: dummy, .test, .symtab, .strtab, .shstrtab
+ 5, 0,
+ // e_shstrndx
+ 4, 0,
+
+ // Offset 64
+ // Shdr 0: dummy entry
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 128
+ // Shdr 1: .test
+ // sh_name: after initial null
+ 1, 0, 0, 0,
+ // sh_type: SHT_PROGBITS
+ 1, 0, 0, 0,
+ // sh_flags: SHF_ALLOC
+ 2, 0, 0, 0, 0, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_offset: after file header + 5 section headers. 384 == 0x180.
+ 0x80, 0x1, 0, 0, 0, 0, 0, 0,
+ // sh_size
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_link
+ 0, 0, 0, 0,
+ // sh_info
+ 0, 0, 0, 0,
+ // sh_addralign
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ // sh_entsize
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 192
+ // Shdr 2: .symtab
+ // sh_name: 1 null byte + ".test\0"
+ 7, 0, 0, 0,
+ // sh_type: SHT_SYMTAB
+ 2, 0, 0, 0,
+ // sh_flags
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_offset: after file header + 5 section headers + empty section
+ // 384 == 0x180.
+ 0x80, 0x1, 0, 0, 0, 0, 0, 0,
+ // sh_size: two symbols: dummy symbol + test symbol
+ 48, 0, 0, 0, 0, 0, 0, 0,
+ // sh_link: to .strtab
+ 3, 0, 0, 0,
+ // sh_info: one local symbol, the dummy symbol
+ 1, 0, 0, 0,
+ // sh_addralign
+ 8, 0, 0, 0, 0, 0, 0, 0,
+ // sh_entsize: size of symbol
+ 24, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 256
+ // Shdr 3: .strtab
+ // sh_name: 1 null byte + ".test\0" + ".symtab\0"
+ 15, 0, 0, 0,
+ // sh_type: SHT_STRTAB
+ 3, 0, 0, 0,
+ // sh_flags
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_offset: after .symtab section. 432 == 0x1b0
+ 0xb0, 0x1, 0, 0, 0, 0, 0, 0,
+ // sh_size: 1 null byte + "test\0"
+ 6, 0, 0, 0, 0, 0, 0, 0,
+ // sh_link
+ 0, 0, 0, 0,
+ // sh_info
+ 0, 0, 0, 0,
+ // sh_addralign
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ // sh_entsize
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 320
+ // Shdr 4: .shstrtab
+ // sh_name: 1 null byte + ".test\0" + ".symtab\0" + ".strtab\0"
+ 23, 0, 0, 0,
+ // sh_type: SHT_STRTAB
+ 3, 0, 0, 0,
+ // sh_flags
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_offset: after .strtab section. 438 == 0x1b6
+ 0xb6, 0x1, 0, 0, 0, 0, 0, 0,
+ // sh_size: all section names
+ 33, 0, 0, 0, 0, 0, 0, 0,
+ // sh_link
+ 0, 0, 0, 0,
+ // sh_info
+ 0, 0, 0, 0,
+ // sh_addralign
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ // sh_entsize
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 384
+ // Contents of .symtab section
+ // Symbol 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 408
+ // Symbol 1
+ // st_name
+ 1, 0, 0, 0,
+ // st_info: STT_NOTYPE, STB_GLOBAL
+ 0x10,
+ // st_other
+ 0,
+ // st_shndx: In .test
+ 1, 0,
+ // st_value
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // st_size
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 432
+ // Contents of .strtab section
+ '\0',
+ 't', 'e', 's', 't', '\0',
+
+ // Offset 438
+ // Contents of .shstrtab section
+ '\0',
+ '.', 't', 'e', 's', 't', '\0',
+ '.', 's', 'y', 'm', 't', 'a', 'b', '\0',
+ '.', 's', 't', 'r', 't', 'a', 'b', '\0',
+ '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', '\0'
+};
+
+const unsigned int test_file_1_size_64_little = sizeof test_file_1_64_little;
+
+// 64-bit big-endian version of test_file_1_32_little.
+
+const unsigned char test_file_1_64_big[] =
+{
+ // Ehdr
+ // EI_MAG[0-3]
+ 0x7f, 'E', 'L', 'F',
+ // EI_CLASS: 64 bit.
+ 2,
+ // EI_DATA: big endian
+ 2,
+ // EI_VERSION
+ 1,
+ // EI_OSABI
+ 0,
+ // EI_ABIVERSION
+ 0,
+ // EI_PAD
+ 0, 0, 0, 0, 0, 0, 0,
+ // e_type: ET_REL
+ 0, 1,
+ // e_machine: a magic value used for testing.
+ 0xff, 0xff,
+ // e_version
+ 0, 0, 0, 1,
+ // e_entry
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // e_phoff
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // e_shoff: starts right after file header
+ 0, 0, 0, 0, 0, 0, 0, 64,
+ // e_flags
+ 0, 0, 0, 0,
+ // e_ehsize
+ 0, 64,
+ // e_phentsize
+ 0, 56,
+ // e_phnum
+ 0, 0,
+ // e_shentsize
+ 0, 64,
+ // e_shnum: dummy, .test, .symtab, .strtab, .shstrtab
+ 0, 5,
+ // e_shstrndx
+ 0, 4,
+
+ // Offset 64
+ // Shdr 0: dummy entry
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 128
+ // Shdr 1: .test
+ // sh_name: after initial null
+ 0, 0, 0, 1,
+ // sh_type: SHT_PROGBITS
+ 0, 0, 0, 1,
+ // sh_flags: SHF_ALLOC
+ 0, 0, 0, 0, 0, 0, 0, 2,
+ // sh_addr
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_offset: after file header + 5 section headers. 384 == 0x180.
+ 0, 0, 0, 0, 0, 0, 0x1, 0x80,
+ // sh_size
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_link
+ 0, 0, 0, 0,
+ // sh_info
+ 0, 0, 0, 0,
+ // sh_addralign
+ 0, 0, 0, 0, 0, 0, 0, 1,
+ // sh_entsize
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 192
+ // Shdr 2: .symtab
+ // sh_name: 1 null byte + ".test\0"
+ 0, 0, 0, 7,
+ // sh_type: SHT_SYMTAB
+ 0, 0, 0, 2,
+ // sh_flags
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_offset: after file header + 5 section headers + empty section
+ // 384 == 0x180.
+ 0, 0, 0, 0, 0, 0, 0x1, 0x80,
+ // sh_size: two symbols: dummy symbol + test symbol
+ 0, 0, 0, 0, 0, 0, 0, 48,
+ // sh_link: to .strtab
+ 0, 0, 0, 3,
+ // sh_info: one local symbol, the dummy symbol
+ 0, 0, 0, 1,
+ // sh_addralign
+ 0, 0, 0, 0, 0, 0, 0, 8,
+ // sh_entsize: size of symbol
+ 0, 0, 0, 0, 0, 0, 0, 24,
+
+ // Offset 256
+ // Shdr 3: .strtab
+ // sh_name: 1 null byte + ".test\0" + ".symtab\0"
+ 0, 0, 0, 15,
+ // sh_type: SHT_STRTAB
+ 0, 0, 0, 3,
+ // sh_flags
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_offset: after .symtab section. 432 == 0x1b0
+ 0, 0, 0, 0, 0, 0, 0x1, 0xb0,
+ // sh_size: 1 null byte + "test\0"
+ 0, 0, 0, 0, 0, 0, 0, 6,
+ // sh_link
+ 0, 0, 0, 0,
+ // sh_info
+ 0, 0, 0, 0,
+ // sh_addralign
+ 0, 0, 0, 0, 0, 0, 0, 1,
+ // sh_entsize
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 320
+ // Shdr 4: .shstrtab
+ // sh_name: 1 null byte + ".test\0" + ".symtab\0" + ".strtab\0"
+ 0, 0, 0, 23,
+ // sh_type: SHT_STRTAB
+ 0, 0, 0, 3,
+ // sh_flags
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_addr
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // sh_offset: after .strtab section. 438 == 0x1b6
+ 0, 0, 0, 0, 0, 0, 0x1, 0xb6,
+ // sh_size: all section names
+ 0, 0, 0, 0, 0, 0, 0, 33,
+ // sh_link
+ 0, 0, 0, 0,
+ // sh_info
+ 0, 0, 0, 0,
+ // sh_addralign
+ 0, 0, 0, 0, 0, 0, 0, 1,
+ // sh_entsize
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 384
+ // Contents of .symtab section
+ // Symbol 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 408
+ // Symbol 1
+ // st_name
+ 0, 0, 0, 1,
+ // st_info: STT_NOTYPE, STB_GLOBAL
+ 0x10,
+ // st_other
+ 0,
+ // st_shndx: In .test
+ 0, 1,
+ // st_value
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ // st_size
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // Offset 432
+ // Contents of .strtab section
+ '\0',
+ 't', 'e', 's', 't', '\0',
+
+ // Offset 438
+ // Contents of .shstrtab section
+ '\0',
+ '.', 't', 'e', 's', 't', '\0',
+ '.', 's', 'y', 'm', 't', 'a', 'b', '\0',
+ '.', 's', 't', 'r', 't', 'a', 'b', '\0',
+ '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', '\0'
+};
+
+const unsigned int test_file_1_size_64_big = sizeof test_file_1_64_big;
+
+} // End namespace gold_testsuite.
diff --git a/binutils-2.25/gold/testsuite/testfile.h b/binutils-2.25/gold/testsuite/testfile.h
new file mode 100644
index 00000000..91781797
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/testfile.h
@@ -0,0 +1,49 @@
+// testfile.h -- test input files -*- C++ -*-
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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_TESTSUITE_TESTFILE_H
+#define GOLD_TESTSUITE_TESTFILE_H
+
+namespace gold
+{
+class Target;
+}
+
+namespace gold_testsuite
+{
+
+extern gold::Target* target_test_pointer_32_little;
+extern gold::Target* target_test_pointer_32_big;
+extern gold::Target* target_test_pointer_64_little;
+extern gold::Target* target_test_pointer_64_big;
+extern const unsigned char test_file_1_32_little[];
+extern const unsigned int test_file_1_size_32_little;
+extern const unsigned char test_file_1_32_big[];
+extern const unsigned int test_file_1_size_32_big;
+extern const unsigned char test_file_1_64_little[];
+extern const unsigned int test_file_1_size_64_little;
+extern const unsigned char test_file_1_64_big[];
+extern const unsigned int test_file_1_size_64_big;
+
+}; // End namespace gold_testsuite.
+
+#endif // !defined(GOLD_TESTSUITE_TESTFILE_H)
diff --git a/binutils-2.25/gold/testsuite/testmain.cc b/binutils-2.25/gold/testsuite/testmain.cc
new file mode 100644
index 00000000..ac99000e
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/testmain.cc
@@ -0,0 +1,40 @@
+// testmain.cc -- main function for simplisitic gold test framework.
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cstdlib>
+
+#include "test.h"
+
+using namespace gold_testsuite;
+
+int
+main(int, char** argv)
+{
+ gold::program_name = argv[0];
+
+ Test_framework tf;
+ Register_test::run_tests(&tf);
+
+ exit(tf.failures());
+}
diff --git a/binutils-2.25/gold/testsuite/text_section_grouping.cc b/binutils-2.25/gold/testsuite/text_section_grouping.cc
new file mode 100644
index 00000000..5a3a809f
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/text_section_grouping.cc
@@ -0,0 +1,72 @@
+// text_section_grouping.cc -- a test case for gold
+
+// Copyright 2012 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// 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 goal of this program is to verify if .text sections are grouped
+// according to prefix. .text.unlikely, .text.startup and .text.hot should
+// be grouped and placed together.
+
+extern "C"
+__attribute__ ((section(".text.hot.foo")))
+int hot_foo()
+{
+ return 1;
+}
+
+extern "C"
+__attribute__ ((section(".text.startup.foo")))
+int startup_foo()
+{
+ return 1;
+}
+
+extern "C"
+__attribute__ ((section(".text.unlikely.foo")))
+int unlikely_foo()
+{
+ return 1;
+}
+
+extern "C"
+__attribute__ ((section(".text.hot.bar")))
+int hot_bar()
+{
+ return 1;
+}
+
+extern "C"
+__attribute__ ((section(".text.startup.bar")))
+int startup_bar()
+{
+ return 1;
+}
+
+extern "C"
+__attribute__ ((section(".text.unlikely.bar")))
+int unlikely_bar()
+{
+ return 1;
+}
+
+int main()
+{
+ return 1;
+}
diff --git a/binutils-2.25/gold/testsuite/text_section_grouping.sh b/binutils-2.25/gold/testsuite/text_section_grouping.sh
new file mode 100755
index 00000000..84ebe4c9
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/text_section_grouping.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+# text_section_grouping.sh -- test
+
+# Copyright 2012 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# 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 goal of this program is to verify if .text sections are grouped
+# according to prefix. .text.unlikely, .text.startup and .text.hot should
+# be grouped and placed together.
+
+# Also check if the functions do not get grouped with option --no-text-reorder.
+
+set -e
+
+check()
+{
+ awk "
+BEGIN { saw1 = 0; saw2 = 0; err = 0; }
+/.*$2\$/ { saw1 = 1; }
+/.*$3\$/ {
+ saw2 = 1;
+ if (!saw1)
+ {
+ printf \"layout of $2 and $3 is not right\\n\";
+ err = 1;
+ exit 1;
+ }
+ }
+END {
+ if (!saw1 && !err)
+ {
+ printf \"did not see $2\\n\";
+ exit 1;
+ }
+ if (!saw2 && !err)
+ {
+ printf \"did not see $3\\n\";
+ exit 1;
+ }
+ }" $1
+}
+
+# addr (unlikely_*) < addr (startup_*) < addr (hot_*)
+check text_section_grouping.stdout "unlikely_foo" "startup_foo"
+check text_section_grouping.stdout "startup_foo" "hot_foo"
+check text_section_grouping.stdout "unlikely_bar" "startup_bar"
+check text_section_grouping.stdout "startup_bar" "hot_bar"
+check text_section_grouping.stdout "unlikely_foo" "startup_bar"
+check text_section_grouping.stdout "startup_foo" "hot_bar"
+
+check text_section_no_grouping.stdout "hot_foo" "startup_foo"
+check text_section_no_grouping.stdout "startup_foo" "unlikely_foo"
+check text_section_no_grouping.stdout "unlikely_foo" "hot_bar"
+check text_section_no_grouping.stdout "hot_bar" "startup_bar"
+check text_section_no_grouping.stdout "startup_bar" "unlikely_bar"
diff --git a/binutils-2.25/gold/testsuite/thin_archive_main.cc b/binutils-2.25/gold/testsuite/thin_archive_main.cc
new file mode 100644
index 00000000..6c38715c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/thin_archive_main.cc
@@ -0,0 +1,39 @@
+// thin_archive_main.cc -- a test case for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 is the main program for the thin archive tests. It calls a single
+// routine, t1, defined in libthin1.a or libthin3.a, which then references
+// other routines in the same and other libraries, to make sure that all
+// archive members are linked properly.
+
+#include <cassert>
+
+extern int t1();
+
+// Main function. Call the test function.
+
+int
+main()
+{
+ assert(t1() == 0x4321);
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/thin_archive_test_1.cc b/binutils-2.25/gold/testsuite/thin_archive_test_1.cc
new file mode 100644
index 00000000..db239376
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/thin_archive_test_1.cc
@@ -0,0 +1,37 @@
+// thin_archive_test_1.cc -- part of a test case for thin archives
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 tests references between files and archives. This is file 1 of 4.
+// Each of the first three files contains a reference to the next.
+// We test the archives as follows:
+
+// Files 1 and 2 in libthin1.a, files 3 and 4 in libthin2.a.
+// Files 1 and 4 in libthin3.a, files 2 and 3 in libthin4.a, with
+// libthin3.a and libthin4.a nested inside libthinall.a.
+
+extern int t2();
+
+int
+t1()
+{
+ return (t2() << 4) | 1;
+}
diff --git a/binutils-2.25/gold/testsuite/thin_archive_test_2.cc b/binutils-2.25/gold/testsuite/thin_archive_test_2.cc
new file mode 100644
index 00000000..2c1ee313
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/thin_archive_test_2.cc
@@ -0,0 +1,37 @@
+// thin_archive_test_2.cc -- part of a test case for thin archives
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 tests references between files and archives. This is file 2 of 4.
+// Each of the first three files contains a reference to the next.
+// We test the archives as follows:
+
+// Files 1 and 2 in libthin1.a, files 3 and 4 in libthin2.a.
+// Files 1 and 4 in libthin3.a, files 2 and 3 in libthin4.a, with
+// libthin3.a and libthin4.a nested inside libthinall.a.
+
+extern int t3();
+
+int
+t2()
+{
+ return (t3() << 4) | 2;
+}
diff --git a/binutils-2.25/gold/testsuite/thin_archive_test_3.cc b/binutils-2.25/gold/testsuite/thin_archive_test_3.cc
new file mode 100644
index 00000000..b58c59fa
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/thin_archive_test_3.cc
@@ -0,0 +1,37 @@
+// thin_archive_test_3.cc -- part of a test case for thin archives
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 tests references between files and archives. This is file 3 of 4.
+// Each of the first three files contains a reference to the next.
+// We test the archives as follows:
+
+// Files 1 and 2 in libthin1.a, files 3 and 4 in libthin2.a.
+// Files 1 and 4 in libthin3.a, files 2 and 3 in libthin4.a, with
+// libthin3.a and libthin4.a nested inside libthinall.a.
+
+extern int t4();
+
+int
+t3()
+{
+ return (t4() << 4) | 3;
+}
diff --git a/binutils-2.25/gold/testsuite/thin_archive_test_4.cc b/binutils-2.25/gold/testsuite/thin_archive_test_4.cc
new file mode 100644
index 00000000..1b67c94a
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/thin_archive_test_4.cc
@@ -0,0 +1,35 @@
+// thin_archive_test_4.cc -- part of a test case for thin archives
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 tests references between files and archives. This is file 4 of 4.
+// Each of the first three files contains a reference to the next.
+// We test the archives as follows:
+
+// Files 1 and 2 in libthin1.a, files 3 and 4 in libthin2.a.
+// Files 1 and 4 in libthin3.a, files 2 and 3 in libthin4.a, with
+// libthin3.a and libthin4.a nested inside libthinall.a.
+
+int
+t4()
+{
+ return 4;
+}
diff --git a/binutils-2.25/gold/testsuite/thumb2_branch_range.t b/binutils-2.25/gold/testsuite/thumb2_branch_range.t
new file mode 100644
index 00000000..8fdc7836
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/thumb2_branch_range.t
@@ -0,0 +1,36 @@
+/* thumb2_banch_range.t -- linker script to test THUMB-2 branch range.
+
+ Copyright 2010 Free Software Foundation, Inc.
+ Written by Doug Kwan <dougkwan@google.com>.
+
+ 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. */
+
+SECTIONS
+{
+ . = 0x1000000;
+
+ .text.pre : { *(.text.pre) }
+ . = ALIGN(0x1000000);
+ .text : { *(.text) }
+ . = ALIGN(0x1000000);
+ .text.post : { *(.text.post) }
+ . += 0x1000;
+ .data : { *(.data) }
+ .bss : { *(.bss) }
+ .ARM.attributes : { *(.ARM.attributes) }
+}
diff --git a/binutils-2.25/gold/testsuite/thumb_bl_in_range.s b/binutils-2.25/gold/testsuite/thumb_bl_in_range.s
new file mode 100644
index 00000000..4a40ae20
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/thumb_bl_in_range.s
@@ -0,0 +1,56 @@
+# thumb_bl_in_range.s
+# Test THUMB/THUMB-2 bl instructions just within the branch range limits.
+ .syntax unified
+
+ .section .text.pre,"x"
+
+# Add padding so that target is just in branch range.
+ .space 8
+
+ .global _backward_target
+ .code 16
+ .thumb_func
+ .type _backword_target, %function
+_backward_target:
+ bx lr
+ .size _backward_target, .-_backward_target
+
+ .text
+
+# Define _start so that linker does not complain.
+ .global _start
+ .code 32
+ .align 2
+ .type _start, %function
+_start:
+ bx lr
+ .size _start, .-_start
+
+ .global _backward_test
+ .code 16
+ .thumb_func
+ .type _backward_test, %function
+_backward_test:
+ bl _backward_target
+ .size _backward_test, .-_backward_test
+
+ .global _forward_test
+ .code 16
+ .thumb_func
+ .type _forward_test, %function
+_forward_test:
+ bl _forward_target
+ .size _forward_test, .-_forward_test
+
+ .section .text.post,"x"
+
+# Add padding so that target is just in branch range.
+ .space 10
+
+ .global _forward_target
+ .code 16
+ .thumb_func
+ .type _forward_target, %function
+_forward_target:
+ bx lr
+ .size _forward_target, .-_forward_target
diff --git a/binutils-2.25/gold/testsuite/thumb_bl_out_of_range.s b/binutils-2.25/gold/testsuite/thumb_bl_out_of_range.s
new file mode 100644
index 00000000..d0906d9d
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/thumb_bl_out_of_range.s
@@ -0,0 +1,62 @@
+# thumb_bl_out_of_range.s
+# Test THUMB/THUMB-2 bl instructions just out of the branch range limits.
+ .syntax unified
+
+ .section .text.pre,"x"
+
+# Add padding so that target is just output of branch range.
+ .space 6
+
+ .global _backward_target
+ .code 16
+ .thumb_func
+ .type _backword_target, %function
+_backward_target:
+ bx lr
+ .size _backward_target, .-_backward_target
+
+ .text
+# Use 256-byte alignment so that we know where the stubs start.
+ .align 8
+
+# Define _start so that linker does not complain.
+ .global _start
+ .code 32
+ .align 2
+ .type _start, %function
+_start:
+ bx lr
+ .size _start, .-_start
+
+ .global _backward_test
+ .code 16
+ .thumb_func
+ .type _backward_test, %function
+_backward_test:
+ bl _backward_target
+ .size _backward_test, .-_backward_test
+
+ .global _forward_test
+ .code 16
+ .thumb_func
+ .type _forward_test, %function
+_forward_test:
+ bl _forward_target
+ .size _forward_test, .-_forward_test
+
+# switch back to ARM mode so that stubs are disassembled correctly.
+ .code 32
+ nop
+
+ .section .text.post,"x"
+
+# Add padding so that target is just out of branch range.
+ .space 12
+
+ .global _forward_target
+ .code 16
+ .thumb_func
+ .type _forward_target, %function
+_forward_target:
+ bx lr
+ .size _forward_target, .-_forward_target
diff --git a/binutils-2.25/gold/testsuite/thumb_bl_out_of_range_local.s b/binutils-2.25/gold/testsuite/thumb_bl_out_of_range_local.s
new file mode 100644
index 00000000..48de1e14
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/thumb_bl_out_of_range_local.s
@@ -0,0 +1,61 @@
+# thumb_bl_out_of_range_local.s
+# Test THUMB/THUMB-2 bl instructions just out of the branch range limits
+# and with local branch targets.
+ .syntax unified
+
+ .section .text.pre,"x"
+
+# Add padding so that target is just output of branch range.
+ .space 6
+
+ .code 16
+ .thumb_func
+ .type .Lbackward_target, %function
+.Lbackward_target:
+ bx lr
+ .size .Lbackward_target, .-.Lbackward_target
+
+ .text
+# Use 256-byte alignment so that we know where the stubs start.
+ .align 8
+
+# Define _start so that linker does not complain.
+ .global _start
+ .code 32
+ .align 2
+ .type _start, %function
+_start:
+ bx lr
+ .size _start, .-_start
+
+ .global _backward_test
+ .code 16
+ .thumb_func
+ .type _backward_test, %function
+_backward_test:
+ bl .Lbackward_target
+ .size _backward_test, .-_backward_test
+
+ .global _forward_test
+ .code 16
+ .thumb_func
+ .type _forward_test, %function
+_forward_test:
+ bl .Lforward_target
+ .size _forward_test, .-_forward_test
+
+# Switch back to ARM mode so that we can see stubs
+ .code 32
+ nop
+
+ .section .text.post,"x"
+
+# Add padding so that target is just out of branch range.
+ .space 12
+
+ .code 16
+ .thumb_func
+ .type .Lforward_target, %function
+.Lforward_target:
+ bx lr
+ .size .Lforward_target, .-.Lforward_target
diff --git a/binutils-2.25/gold/testsuite/thumb_blx_in_range.s b/binutils-2.25/gold/testsuite/thumb_blx_in_range.s
new file mode 100644
index 00000000..bd2d060b
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/thumb_blx_in_range.s
@@ -0,0 +1,64 @@
+# thumb_blx_in_range.s
+#
+# Test THUMB/THUMB-2 blx instructions just within the branch range limits.
+# Because bit 1 of the branch target comes from the branch instruction
+# address, the branch range from PC (branch instruction address + 4) is
+# acutally -((1<<22) + 2) to ((1<<22) - 4) for THUMB and -((1<<24) + 2) to
+# ((1<<24) - 4) from THUMB2.
+
+ .syntax unified
+ .section .text.pre,"x"
+
+# Add padding so that target is just in branch range.
+ .space 8
+
+ .align 2
+ .global _backward_target
+ .code 32
+ .type _backword_target, %function
+_backward_target:
+ bx lr
+ .size _backward_target, .-_backward_target
+
+ .text
+
+# Define _start so that linker does not complain.
+ .global _start
+ .code 32
+ .align 2
+ .type _start, %function
+_start:
+ bx lr
+ .size _start, .-_start
+
+ .global _backward_test
+ .code 16
+ .thumb_func
+ .type _backward_test, %function
+_backward_test:
+ nop.n
+ blx _backward_target
+ .size _backward_test, .-_backward_test
+
+ .align 2
+ .global _forward_test
+ .code 16
+ .thumb_func
+ .type _forward_test, %function
+_forward_test:
+ blx _forward_target
+ .size _forward_test, .-_forward_test
+ .code 32
+
+ .section .text.post,"x"
+
+# Add padding so that target is just in branch range.
+ .space 12
+
+ .align 2
+ .global _forward_target
+ .code 32
+ .type _forward_target, %function
+_forward_target:
+ bx lr
+ .size _forward_target, .-_forward_target
diff --git a/binutils-2.25/gold/testsuite/thumb_blx_out_of_range.s b/binutils-2.25/gold/testsuite/thumb_blx_out_of_range.s
new file mode 100644
index 00000000..c4f87e0f
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/thumb_blx_out_of_range.s
@@ -0,0 +1,66 @@
+# thumb_blx_out_of_range.s
+# Test THUMB/THUMB-2 blx instructions just out of the branch range limits.
+ .syntax unified
+
+ .section .text.pre,"x"
+
+# Add padding so that target is just output of branch range.
+ .space 4
+
+ .global _forward_target
+ .global _backward_target
+ .type _backword_target, %function
+_backward_target:
+ bx lr
+ .size _backward_target, .-_backward_target
+
+ .text
+# Use 256-byte alignment so that we know where the stubs start.
+ .align 8
+
+# Define _start so that linker does not complain.
+ .align 2
+ .global _start
+ .code 32
+ .type _start, %function
+_start:
+ bx lr
+ .size _start, .-_start
+
+ .global _backward_test
+ .code 16
+ .thumb_func
+ .type _backward_test, %function
+_backward_test:
+ bl _backward_target
+ .size _backward_test, .-_backward_test
+
+ .align 2
+ .global _forward_test
+ .code 16
+ .thumb_func
+ .type _forward_test, %function
+_forward_test:
+ # Bit 1 of the BLX target comes from bit 1 of branch base address,
+ # which is BLX instruction's address + 4. We intentionally put this
+ # forward BLX at an address n*4 + 2 so that the branch offset is
+ # bumped up by 2.
+ nop.n
+ bl _forward_target
+ .size _forward_test, .-_forward_test
+
+# switch back to ARM mode so that stubs are disassembled correctly.
+ .code 32
+ nop
+
+ .section .text.post,"x"
+
+# Add padding so that target is just out of branch range.
+ .space 12
+ .align 2
+ .code 32
+ .global _forward_target
+ .type _forward_target, %function
+_forward_target:
+ bx lr
+ .size _forward_target, .-_forward_target
diff --git a/binutils-2.25/gold/testsuite/thumb_branch_range.t b/binutils-2.25/gold/testsuite/thumb_branch_range.t
new file mode 100644
index 00000000..fa858b55
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/thumb_branch_range.t
@@ -0,0 +1,36 @@
+/* thumb_banch_range.t -- linker script to test ARM branch range.
+
+ Copyright 2010 Free Software Foundation, Inc.
+ Written by Doug Kwan <dougkwan@google.com>.
+
+ 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. */
+
+SECTIONS
+{
+ . = 0x400000;
+
+ .text.pre : { *(.text.pre) }
+ . = ALIGN(0x400000);
+ .text : { *(.text) }
+ . = ALIGN(0x400000);
+ .text.post : { *(.text.post) }
+ . += 0x1000;
+ .data : { *(.data) }
+ .bss : { *(.bss) }
+ .ARM.attributes : { *(.ARM.attributes) }
+}
diff --git a/binutils-2.25/gold/testsuite/tls_test.cc b/binutils-2.25/gold/testsuite/tls_test.cc
new file mode 100644
index 00000000..c8757529
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/tls_test.cc
@@ -0,0 +1,224 @@
+// tls_test.cc -- test TLS variables for gold
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 provides a set of test functions for TLS variables. The
+// functions are called by a main function in tls_test_main.cc. This
+// lets us test TLS access from a shared library. We currently don't
+// bother to test TLS access between two different files, on the
+// theory that that is no more complicated than ordinary variable
+// access between files.
+
+// We start two threads, and stop the second one. Then we run the
+// first thread through the following cases. Then we let the second
+// thread continue, and run it through the same set of cases. All the
+// actual thread manipulation is in tls_test_main.cc.
+
+// 1 Access to an uninitialized global thread variable.
+// 2 Access to an uninitialized static thread variable.
+// 3 Access to an initialized global thread variable.
+// 4 Access to an initialized static thread variable.
+// 5 Taking the address of a global thread variable.
+// 6 Taking the address of a static thread variable.
+// 8 Like test 1, but with the thread variable defined in another file.
+// 9 Like test 3, but with the thread variable defined in another file.
+// 10 Like test 5, but with the thread variable defined in another file.
+// last Verify that the above tests left the variables set correctly.
+
+
+#include "config.h"
+#include <cstdio>
+#include "tls_test.h"
+
+#define CHECK_EQ_OR_RETURN(var, expected) \
+ do \
+ { \
+ if ((var) != (expected)) \
+ { \
+ printf(#var ": expected %d, found %d\n", expected, var); \
+ return false; \
+ } \
+ } \
+ while (0)
+
+__thread int v1;
+static __thread int v2;
+
+// We don't use these pointers, but putting them in tests alignment on
+// a 64-bit target.
+__thread char* p1;
+char dummy;
+__thread char* p2 = &dummy;
+
+__thread int v3 = 3;
+static __thread int v4 = 4;
+__thread int v5;
+static __thread int v6;
+
+struct int128
+{
+ long long hi;
+ long long lo;
+};
+
+static __thread struct int128 v12 = { 115, 125 };
+
+bool
+t1()
+{
+ CHECK_EQ_OR_RETURN(v1, 0);
+ v1 = 10;
+ return true;
+}
+
+bool
+t2()
+{
+ CHECK_EQ_OR_RETURN(v2, 0);
+ v2 = 20;
+ return true;
+}
+
+bool
+t3()
+{
+ CHECK_EQ_OR_RETURN(v3, 3);
+ v3 = 30;
+ return true;
+}
+
+bool
+t4()
+{
+ CHECK_EQ_OR_RETURN(v4, 4);
+ v4 = 40;
+ return true;
+}
+
+// For test 5 the main function calls f5b(f5a()), then calls t5().
+
+int*
+f5a()
+{
+ return &v5;
+}
+
+void
+f5b(int* p)
+{
+ *p = 50;
+}
+
+bool
+t5()
+{
+ CHECK_EQ_OR_RETURN(v5, 50);
+ return true;
+}
+
+// For test 6 the main function calls f6b(f6a()), then calls t6().
+
+int*
+f6a()
+{
+ return &v6;
+}
+
+void
+f6b(int* p)
+{
+ *p = 60;
+}
+
+bool
+t6()
+{
+ CHECK_EQ_OR_RETURN(v6, 60);
+ return true;
+}
+
+// The slot for t7() is unused.
+
+bool
+t8()
+{
+ CHECK_EQ_OR_RETURN(o1, 0);
+ o1 = -10;
+ return true;
+}
+
+bool
+t9()
+{
+ CHECK_EQ_OR_RETURN(o2, -2);
+ o2 = -20;
+ return true;
+}
+
+// For test 10 the main function calls f10b(f10a()), then calls t10().
+
+int*
+f10a()
+{
+ return &o3;
+}
+
+void
+f10b(int* p)
+{
+ *p = -30;
+}
+
+bool
+t10()
+{
+ CHECK_EQ_OR_RETURN(o3, -30);
+ return true;
+}
+
+bool
+t12()
+{
+ struct int128 newval = { 335, 345 };
+ CHECK_EQ_OR_RETURN((int) v12.hi, 115);
+ CHECK_EQ_OR_RETURN((int) v12.lo, 125);
+ v12 = newval;
+ return true;
+}
+
+bool
+t_last()
+{
+ CHECK_EQ_OR_RETURN(v1, 10);
+ CHECK_EQ_OR_RETURN(v2, 20);
+ CHECK_EQ_OR_RETURN(v3, 30);
+ CHECK_EQ_OR_RETURN(v4, 40);
+ CHECK_EQ_OR_RETURN(v5, 50);
+ CHECK_EQ_OR_RETURN(v6, 60);
+ CHECK_EQ_OR_RETURN((int) v12.hi, 335);
+ CHECK_EQ_OR_RETURN((int) v12.lo, 345);
+ CHECK_EQ_OR_RETURN(o1, -10);
+ CHECK_EQ_OR_RETURN(o2, -20);
+ CHECK_EQ_OR_RETURN(o3, -30);
+ int check = t11_last();
+ CHECK_EQ_OR_RETURN(check, 1);
+ return true;
+}
diff --git a/binutils-2.25/gold/testsuite/tls_test.h b/binutils-2.25/gold/testsuite/tls_test.h
new file mode 100644
index 00000000..1c98b176
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/tls_test.h
@@ -0,0 +1,56 @@
+// tls_test.h -- test TLS variables for gold, header file -*- C++ -*-
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 is the header file for the TLS test. See tls_test.cc for more
+// information.
+
+extern bool t1();
+extern bool t2();
+extern bool t3();
+extern bool t4();
+
+extern int* f5a();
+extern void f5b(int*);
+extern bool t5();
+
+extern int* f6a();
+extern void f6b(int*);
+extern bool t6();
+
+extern bool t8();
+extern bool t9();
+
+extern int* f10a();
+extern void f10b(int*);
+extern bool t10();
+
+extern "C" int t11();
+extern "C" int t11_last();
+
+extern bool t12();
+
+extern bool t_last();
+
+// These variables are defined in tls_test_file2.cc
+extern __thread int o1;
+extern __thread int o2;
+extern __thread int o3;
diff --git a/binutils-2.25/gold/testsuite/tls_test_c.c b/binutils-2.25/gold/testsuite/tls_test_c.c
new file mode 100644
index 00000000..896191fa
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/tls_test_c.c
@@ -0,0 +1,65 @@
+/* tls_test_c.c -- test TLS common symbol
+
+ Copyright 2008 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>
+
+ 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 only way I know to get gcc to generate a TLS common symbol is
+ to use a C file and an OpenMP directive. */
+
+#include "config.h"
+#include <stdio.h>
+
+#define CHECK_EQ_OR_RETURN(var, expected) \
+ do \
+ { \
+ if ((var) != (expected)) \
+ { \
+ printf(#var ": expected %d, found %d\n", expected, var); \
+ return 0; \
+ } \
+ } \
+ while (0)
+
+#ifdef HAVE_OMP_SUPPORT
+int v7;
+#pragma omp threadprivate (v7)
+#endif
+
+int t11(void);
+int t11_last(void);
+
+int
+t11(void)
+{
+#ifdef HAVE_OMP_SUPPORT
+ CHECK_EQ_OR_RETURN(v7, 0);
+ v7 = 70;
+#endif
+ return 1;
+}
+
+int
+t11_last(void)
+{
+#ifdef HAVE_OMP_SUPPORT
+ CHECK_EQ_OR_RETURN(v7, 70);
+#endif
+ return 1;
+}
diff --git a/binutils-2.25/gold/testsuite/tls_test_file2.cc b/binutils-2.25/gold/testsuite/tls_test_file2.cc
new file mode 100644
index 00000000..b02a7bdc
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/tls_test_file2.cc
@@ -0,0 +1,30 @@
+// tls_test.cc -- test TLS variables for gold
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 is the definition of a thread-local variable in another file.
+// See tls_test.cc for more information.
+
+#include "tls_test.h"
+
+__thread int o1;
+__thread int o2 = -2;
+__thread int o3;
diff --git a/binutils-2.25/gold/testsuite/tls_test_main.cc b/binutils-2.25/gold/testsuite/tls_test_main.cc
new file mode 100644
index 00000000..d781a150
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/tls_test_main.cc
@@ -0,0 +1,173 @@
+// tls_test.cc -- test TLS variables for gold, main function
+
+// Copyright 2006, 2007, 2008, 2011 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 is the main function for the TLS test. See tls_test.cc for
+// more information.
+
+#include <cassert>
+#include <cstdio>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include "tls_test.h"
+
+// We make these macros so the assert() will give useful line-numbers.
+#define safe_lock(semptr) \
+ do \
+ { \
+ int err = sem_wait(semptr); \
+ assert(err == 0); \
+ } \
+ while (0)
+
+#define safe_unlock(semptr) \
+ do \
+ { \
+ int err = sem_post(semptr); \
+ assert(err == 0); \
+ } \
+ while (0)
+
+struct Sem_set
+{
+ sem_t sem1;
+ sem_t sem2;
+ sem_t sem3;
+};
+
+Sem_set sems1;
+Sem_set sems2;
+
+bool failed = false;
+
+void
+check(const char* name, bool val)
+{
+ if (!val)
+ {
+ fprintf(stderr, "Test %s failed\n", name);
+ failed = true;
+ }
+}
+
+// The body of the thread function. This acquires the first
+// semaphore, runs the tests, and then releases the second semaphore.
+// Then it acquires the third semaphore, and the runs the verification
+// test again.
+
+void*
+thread_routine(void* arg)
+{
+ Sem_set* pms = static_cast<Sem_set*>(arg);
+
+ // Acquire the first semaphore.
+ if (pms)
+ safe_lock(&pms->sem1);
+
+ // Run the tests.
+ check("t1", t1());
+ check("t2", t2());
+ check("t3", t3());
+ check("t4", t4());
+ f5b(f5a());
+ check("t5", t5());
+ f6b(f6a());
+ check("t6", t6());
+ check("t8", t8());
+ check("t9", t9());
+ f10b(f10a());
+ check("t10", t10());
+ check("t11", t11() != 0);
+ check("t12", t12());
+ check("t_last", t_last());
+
+ // Release the second semaphore.
+ if (pms)
+ safe_unlock(&pms->sem2);
+
+ // Acquire the third semaphore.
+ if (pms)
+ safe_lock(&pms->sem3);
+
+ check("t_last", t_last());
+
+ return 0;
+}
+
+// The main function.
+
+int
+main()
+{
+ // First, as a sanity check, run through the tests in the "main" thread.
+ thread_routine(0);
+
+ // Set up the semaphores. We want the first thread to start right
+ // away, tell us when it is done with the first part, and wait for
+ // us to release it. We want the second thread to wait to start,
+ // tell us when it is done with the first part, and wait for us to
+ // release it.
+ sem_init(&sems1.sem1, 0, 1);
+ sem_init(&sems1.sem2, 0, 0);
+ sem_init(&sems1.sem3, 0, 0);
+
+ sem_init(&sems2.sem1, 0, 0);
+ sem_init(&sems2.sem2, 0, 0);
+ sem_init(&sems2.sem3, 0, 0);
+
+ pthread_t thread1;
+ int err = pthread_create(&thread1, NULL, thread_routine, &sems1);
+ assert(err == 0);
+
+ pthread_t thread2;
+ err = pthread_create(&thread2, NULL, thread_routine, &sems2);
+ assert(err == 0);
+
+ // Wait for the first thread to complete the first part.
+ safe_lock(&sems1.sem2);
+
+ // Tell the second thread to start.
+ safe_unlock(&sems2.sem1);
+
+ // Wait for the second thread to complete the first part.
+ safe_lock(&sems2.sem2);
+
+ // Tell the first thread to continue and finish.
+ safe_unlock(&sems1.sem3);
+
+ // Wait for the first thread to finish.
+ void* thread_val;
+ err = pthread_join(thread1, &thread_val);
+ assert(err == 0);
+ assert(thread_val == 0);
+
+ // Tell the second thread to continue and finish.
+ safe_unlock(&sems2.sem3);
+
+ // Wait for the second thread to finish.
+ err = pthread_join(thread2, &thread_val);
+ assert(err == 0);
+ assert(thread_val == 0);
+
+ // All done.
+ return failed ? 1 : 0;
+}
diff --git a/binutils-2.25/gold/testsuite/two_file_shared.sh b/binutils-2.25/gold/testsuite/two_file_shared.sh
new file mode 100755
index 00000000..62403114
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/two_file_shared.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+# two_file_shared.sh -- check that debug info gets symbol addresses
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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.
+
+addrs=`grep DW_OP_addr two_file_shared.dbg | fgrep '(DW_OP_addr: 0)'`
+if test -n "$addrs"; then
+ echo "Found variables with address zero"
+ echo $addrs
+ exit 1
+fi
diff --git a/binutils-2.25/gold/testsuite/two_file_test.h b/binutils-2.25/gold/testsuite/two_file_test.h
new file mode 100644
index 00000000..d89f050c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/two_file_test.h
@@ -0,0 +1,78 @@
+// two_file_test.h -- a two file test case for gold, header file -*- C++ -*-
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 tests references between files. This is the shared header
+// file. See two_file_test_1.cc for details.
+
+extern bool t1();
+extern bool t1a();
+extern int t1_2();
+
+extern bool t2();
+extern int v2;
+
+extern bool t3();
+extern int v3;
+
+extern bool t4();
+extern char v4[];
+
+extern bool t5();
+extern char v5[];
+
+extern bool t6();
+
+extern bool t7();
+
+extern bool t8();
+
+extern bool t9();
+
+extern bool t10();
+extern int f10();
+
+extern bool t11();
+extern int f11a();
+extern int f11b(int (*)());
+
+extern bool t12();
+extern bool (*f12())();
+
+extern bool t13();
+inline void f13i() { }
+extern void (*f13())();
+
+#define TEST_STRING_CONSTANT "test string constant"
+extern const char* f14();
+
+#define TEST_WIDE_STRING_CONSTANT L"test wide string constant"
+extern const wchar_t* f15();
+
+extern bool t16();
+extern bool t16a();
+
+extern bool t17();
+extern const char* t17data[];
+#define T17_COUNT 5
+
+extern bool t18();
+extern const char* f18(int);
diff --git a/binutils-2.25/gold/testsuite/two_file_test_1.cc b/binutils-2.25/gold/testsuite/two_file_test_1.cc
new file mode 100644
index 00000000..8b4c8ad4
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/two_file_test_1.cc
@@ -0,0 +1,238 @@
+// two_file_test_1.cc -- a two file test case for gold, file 1 of 2
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 tests references between files. This is file 1, and
+// two_file_test_2.cc is file 2. We test in several different ways:
+
+// Files 1 and 2 linked together in executable.
+// File 1 in executable, file 2 in shared library.
+// File 1 in shared library, file 2 in executable.
+// Files 1 and 2 linked together in shared library.
+// Files 1 and 2 in different shared libraries.
+
+// We test the following cases.
+
+// 1 Code in file 1 calls code in file 2.
+// 2 Code in file 1 refers to global data in file 2.
+// 3 Code in file 1 referes to common symbol in file 2.
+// 4 Code in file 1 refers to offset within global data in file 2.
+// 5 Code in file 1 refers to offset within common symbol in file 2.
+// 6 Data in file 1 refers to global data in file 2.
+// 7 Data in file 1 refers to common symbol in file 2.
+// 8 Data in file 1 refers to offset within global data in file 2.
+// 9 Data in file 1 refers to offset within common symbol in file 2.
+// 10 Data in file 1 refers to function in file 2.
+// 11 Pass function pointer from file 1 to file 2.
+// 12 Compare address of function for equality in both files.
+// 13 Compare address of inline function for equality in both files.
+// 14 Compare string constants in file 1 and file 2.
+// 15 Compare wide string constants in file 1 and file 2.
+// 16 Call a function directly after its address has been taken.
+// 17 File 1 checks array of string constants defined in file 2.
+// 18 File 1 checks string constants referenced in code in file 2.
+
+#include "two_file_test.h"
+
+// 1 Code in file 1 calls code in file 2.
+
+bool
+t1()
+{
+ return t1_2() == 123;
+}
+
+// 2 Code in file 1 refers to global data in file 2.
+
+bool
+t2()
+{
+ return v2 == 456;
+}
+
+// 3 Code in file 1 referes to common symbol in file 2.
+
+bool
+t3()
+{
+ return v3 == 789;
+}
+
+// 4 Code in file 1 refers to offset within global data in file 2.
+
+bool
+t4()
+{
+ return v4[5] == ',';
+}
+
+// 5 Code in file 1 refers to offset within common symbol in file 2.
+
+bool
+t5()
+{
+ return v5[7] == 'w';
+}
+
+// 6 Data in file 1 refers to global data in file 2.
+
+int* p6 = &v2;
+
+bool
+t6()
+{
+ return *p6 == 456;
+}
+
+// 7 Data in file 1 refers to common symbol in file 2.
+
+int* p7 = &v3;
+
+bool
+t7()
+{
+ return *p7 == 789;
+}
+
+// 8 Data in file 1 refers to offset within global data in file 2.
+
+char* p8 = &v4[6];
+
+bool
+t8()
+{
+ return *p8 == ' ';
+}
+
+// 9 Data in file 1 refers to offset within common symbol in file 2.
+
+char* p9 = &v5[8];
+
+bool
+t9()
+{
+ return *p9 == 'o';
+}
+
+// 10 Data in file 1 refers to function in file 2.
+
+int (*pfn)() = &f10;
+
+bool
+t10()
+{
+ return (*pfn)() == 135;
+}
+
+// 11 Pass function pointer from file 1 to file 2.
+
+int
+f11a()
+{
+ return 246;
+}
+
+bool
+t11()
+{
+ return f11b(&f11a) == 246;
+}
+
+// 12 Compare address of function for equality in both files.
+
+bool
+t12()
+{
+ return &t12 == f12();
+}
+
+// 13 Compare address of inline function for equality in both files.
+
+bool
+t13()
+{
+ return &f13i == f13();
+}
+
+// 14 Compare string constants in file 1 and file 2.
+
+bool
+t14()
+{
+ const char* s1 = TEST_STRING_CONSTANT;
+ const char* s2 = f14();
+ while (*s1 != '\0')
+ if (*s1++ != *s2++)
+ return false;
+ return *s2 == '\0';
+}
+
+// 15 Compare wide string constants in file 1 and file 2.
+
+bool
+t15()
+{
+ const wchar_t* s1 = TEST_WIDE_STRING_CONSTANT;
+ const wchar_t* s2 = f15();
+ while (*s1 != '\0')
+ if (*s1++ != *s2++)
+ return false;
+ return *s2 == '\0';
+}
+
+// 16 Call a function directly after its address has been taken.
+
+bool
+t16()
+{
+ return f10() == 135;
+}
+
+// 17 File 1 checks array of string constants defined in file 2.
+
+bool
+t17()
+{
+ char c = 'a';
+ for (int i = 0; i < T17_COUNT; ++i)
+ {
+ if (t17data[i][0] != c || t17data[i][1] != '\0')
+ return false;
+ ++c;
+ }
+ return true;
+}
+
+// 18 File 1 checks string constants referenced in code in file 2.
+
+bool
+t18()
+{
+ char c = 'a';
+ for (int i = 0; i < T17_COUNT; ++i)
+ {
+ const char* s = f18(i);
+ if (s[0] != c || s[1] != '\0')
+ return false;
+ ++c;
+ }
+ return true;
+}
diff --git a/binutils-2.25/gold/testsuite/two_file_test_1_v1.cc b/binutils-2.25/gold/testsuite/two_file_test_1_v1.cc
new file mode 100644
index 00000000..2a236540
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/two_file_test_1_v1.cc
@@ -0,0 +1,236 @@
+// two_file_test_1_v1.cc -- a two file test case for gold, file 1 of 2
+
+// Copyright 2006, 2007, 2008, 2011 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 is an alternate version of the source file two_file_test_1.cc,
+// used to test incremental linking. We build a binary first using this
+// source file, then do an incremental link with the primary version of
+// the file.
+
+// This tests references between files. This is file 1, and
+// two_file_test_2.cc is file 2. We test in several different ways:
+
+// Files 1 and 2 linked together in executable.
+// File 1 in executable, file 2 in shared library.
+// File 1 in shared library, file 2 in executable.
+// Files 1 and 2 linked together in shared library.
+// Files 1 and 2 in different shared libraries.
+
+// We test the following cases.
+
+// 1 Code in file 1 calls code in file 2.
+// 2 Code in file 1 refers to global data in file 2.
+// 3 Code in file 1 referes to common symbol in file 2.
+// 4 Code in file 1 refers to offset within global data in file 2.
+// 5 Code in file 1 refers to offset within common symbol in file 2.
+// 6 Data in file 1 refers to global data in file 2.
+// 7 Data in file 1 refers to common symbol in file 2.
+// 8 Data in file 1 refers to offset within global data in file 2.
+// 9 Data in file 1 refers to offset within common symbol in file 2.
+// 10 Data in file 1 refers to function in file 2.
+// 11 Pass function pointer from file 1 to file 2.
+// 12 Compare address of function for equality in both files.
+// 13 Compare address of inline function for equality in both files.
+// 14 Compare string constants in file 1 and file 2.
+// 15 Compare wide string constants in file 1 and file 2.
+// 16 Call a function directly after its address has been taken.
+// 17 File 1 checks array of string constants defined in file 2.
+// 18 File 1 checks string constants referenced in code in file 2.
+
+#include "two_file_test.h"
+
+// 1 Code in file 1 calls code in file 2.
+
+bool
+t1()
+{
+ return t1_2() == 0; // Intentionally wrong.
+}
+
+// 2 Code in file 1 refers to global data in file 2.
+
+bool
+t2()
+{
+ return v2 == 0; // Intentionally wrong.
+}
+
+// 3 Code in file 1 referes to common symbol in file 2.
+
+bool
+t3()
+{
+ return v3 == 0; // Intentionally wrong.
+}
+
+// 4 Code in file 1 refers to offset within global data in file 2.
+
+bool
+t4()
+{
+ return v4[5] == ',';
+}
+
+// 5 Code in file 1 refers to offset within common symbol in file 2.
+
+bool
+t5()
+{
+ return v5[7] == 'w';
+}
+
+// 6 Data in file 1 refers to global data in file 2.
+
+int* p6 = &v2;
+
+bool
+t6()
+{
+ return *p6 == 456;
+}
+
+// 7 Data in file 1 refers to common symbol in file 2.
+
+int* p7 = &v3;
+
+bool
+t7()
+{
+ return *p7 == 789;
+}
+
+// 8 Data in file 1 refers to offset within global data in file 2.
+
+char* p8 = &v4[6];
+
+bool
+t8()
+{
+ return *p8 == ' ';
+}
+
+// 9 Data in file 1 refers to offset within common symbol in file 2.
+
+char* p9 = &v5[8];
+
+bool
+t9()
+{
+ return *p9 == 'o';
+}
+
+// 10 Data in file 1 refers to function in file 2.
+
+int (*pfn)() = &f10;
+
+bool
+t10()
+{
+ return (*pfn)() == 135;
+}
+
+// 11 Pass function pointer from file 1 to file 2.
+
+int
+f11a()
+{
+ return 246;
+}
+
+bool
+t11()
+{
+ return f11b(&f11a) == 246;
+}
+
+// 12 Compare address of function for equality in both files.
+
+bool
+t12()
+{
+ return &t12 == f12();
+}
+
+// 13 Compare address of inline function for equality in both files.
+
+bool
+t13()
+{
+ return &f13i == f13();
+}
+
+// 14 Compare string constants in file 1 and file 2.
+
+bool
+t14()
+{
+ const char* s1 = TEST_STRING_CONSTANT;
+ const char* s2 = f14();
+ while (*s1 != '\0')
+ if (*s1++ != *s2++)
+ return false;
+ return *s2 == '\0';
+}
+
+// 15 Compare wide string constants in file 1 and file 2.
+
+bool
+t15()
+{
+ const wchar_t* s1 = TEST_WIDE_STRING_CONSTANT;
+ const wchar_t* s2 = f15();
+ while (*s1 != '\0')
+ if (*s1++ != *s2++)
+ return false;
+ return *s2 == '\0';
+}
+
+// 16 Call a function directly after its address has been taken.
+
+bool
+t16()
+{
+ return f10() == 135;
+}
+
+// 17 File 1 checks array of string constants defined in file 2.
+
+bool
+t17()
+{
+ char c = 'a';
+ for (int i = 0; i < T17_COUNT; ++i)
+ {
+ if (t17data[i][0] != c || t17data[i][1] != '\0')
+ return false;
+ ++c;
+ }
+ return true;
+}
+
+// 18 File 1 checks string constants referenced in code in file 2.
+
+bool
+t18()
+{
+ // Stubbed out; full implementation in two_file_test_1.cc.
+ return true;
+}
diff --git a/binutils-2.25/gold/testsuite/two_file_test_1b.cc b/binutils-2.25/gold/testsuite/two_file_test_1b.cc
new file mode 100644
index 00000000..8f6d4e65
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/two_file_test_1b.cc
@@ -0,0 +1,41 @@
+// two_file_test_1b.cc -- supplementary file for a three-file test case
+// for gold.
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 used as part of a mixed PIC/non-PIC test.
+// Files 1 and 1b are linked together in a shared library.
+// File 1 is compiled non-PIC, and file 1a is compiled PIC.
+// File 2 is compiled PIC and linked in a second shared library.
+// This tests that a non-PIC call does not accidentally get
+// bound to a PIC PLT entry.
+
+// We test the following cases.
+
+#include "two_file_test.h"
+
+// 16 Call a function directly after its address has been taken.
+
+bool
+t16a()
+{
+ return f10() == 135;
+}
diff --git a/binutils-2.25/gold/testsuite/two_file_test_1b_v1.cc b/binutils-2.25/gold/testsuite/two_file_test_1b_v1.cc
new file mode 100644
index 00000000..0adaf845
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/two_file_test_1b_v1.cc
@@ -0,0 +1,46 @@
+// two_file_test_1b_v1.cc -- supplementary file for a three-file test case
+// for gold.
+
+// Copyright 2008, 2011 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 is an alternate version of the source file two_file_test_1b.cc,
+// used to test incremental linking. We build a binary first using this
+// source file, then do an incremental link with the primary version of
+// the file.
+
+// This file is used as part of a mixed PIC/non-PIC test.
+// Files 1 and 1b are linked together in a shared library.
+// File 1 is compiled non-PIC, and file 1a is compiled PIC.
+// File 2 is compiled PIC and linked in a second shared library.
+// This tests that a non-PIC call does not accidentally get
+// bound to a PIC PLT entry.
+
+// We test the following cases.
+
+#include "two_file_test.h"
+
+// 16 Call a function directly after its address has been taken.
+
+bool
+t16a()
+{
+ return f10() == 125;
+}
diff --git a/binutils-2.25/gold/testsuite/two_file_test_2.cc b/binutils-2.25/gold/testsuite/two_file_test_2.cc
new file mode 100644
index 00000000..e1aeaf48
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/two_file_test_2.cc
@@ -0,0 +1,145 @@
+// two_file_test_2.cc -- a two file test case for gold, file 2 of 2
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 tests references between files. This is file 2, and
+// two_file_test_1.cc is file 1. See file 1 for details.
+
+#include "two_file_test.h"
+
+// 1 Code in file 1 calls code in file 2.
+
+int
+t1_2()
+{
+ return 123;
+}
+
+bool
+t1a()
+{
+ return t1_2() == 123;
+}
+
+// 2 Code in file 1 refers to global data in file 2.
+
+int v2 = 456;
+
+// 3 Code in file 1 referes to common symbol in file 2. This is
+// initialized at runtime to 789.
+
+int v3;
+
+// 4 Code in file 1 refers to offset within global data in file 2.
+
+char v4[] = "Hello, world";
+
+// 5 Code in file 1 refers to offset within common symbol in file 2.
+// This is initialized at runtime to a copy of v4.
+
+char v5[13];
+
+// 6 Data in file 1 refers to global data in file 2. This reuses v2.
+
+// 7 Data in file 1 refers to common symbol in file 2. This reuses v3.
+
+// 8 Data in file 1 refers to offset within global data in file 2.
+// This reuses v4.
+
+// 9 Data in file 1 refers to offset within common symbol in file 2.
+// This reuses v5.
+
+// 10 Data in file 1 refers to function in file 2.
+
+int
+f10()
+{
+ return 135;
+}
+
+// 11 Pass function pointer from file 1 to file 2.
+
+int
+f11b(int (*pfn)())
+{
+ return (*pfn)();
+}
+
+// 12 Compare address of function for equality in both files.
+
+bool
+(*f12())()
+{
+ return &t12;
+}
+
+// 13 Compare address of inline function for equality in both files.
+
+void
+(*f13())()
+{
+ return &f13i;
+}
+
+// 14 Compare string constants in file 1 and file 2.
+
+const char*
+f14()
+{
+ return TEST_STRING_CONSTANT;
+}
+
+// 15 Compare wide string constants in file 1 and file 2.
+
+const wchar_t*
+f15()
+{
+ return TEST_WIDE_STRING_CONSTANT;
+}
+
+// 17 File 1 checks array of string constants defined in file 2.
+
+const char* t17data[T17_COUNT] =
+{
+ "a", "b", "c", "d", "e"
+};
+
+// 18 File 1 checks string constants referenced directly in file 2.
+
+const char*
+f18(int i)
+{
+ switch (i)
+ {
+ case 0:
+ return "a";
+ case 1:
+ return "b";
+ case 2:
+ return "c";
+ case 3:
+ return "d";
+ case 4:
+ return "e";
+ default:
+ return 0;
+ }
+}
diff --git a/binutils-2.25/gold/testsuite/two_file_test_2_tls.cc b/binutils-2.25/gold/testsuite/two_file_test_2_tls.cc
new file mode 100644
index 00000000..6c74c698
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/two_file_test_2_tls.cc
@@ -0,0 +1,147 @@
+// two_file_test_2_tls.cc -- a two file test case for gold, with a TLS symbol
+
+// Copyright 2006, 2007, 2008, 2013 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 tests references between files. This is file 2, and
+// two_file_test_1.cc is file 1. See file 1 for details.
+
+#include "two_file_test.h"
+
+// 1 Code in file 1 calls code in file 2.
+
+__thread int tls1 = 123;
+
+int
+t1_2()
+{
+ return tls1;
+}
+
+bool
+t1a()
+{
+ return t1_2() == 123;
+}
+
+// 2 Code in file 1 refers to global data in file 2.
+
+int v2 = 456;
+
+// 3 Code in file 1 referes to common symbol in file 2. This is
+// initialized at runtime to 789.
+
+int v3;
+
+// 4 Code in file 1 refers to offset within global data in file 2.
+
+char v4[] = "Hello, world";
+
+// 5 Code in file 1 refers to offset within common symbol in file 2.
+// This is initialized at runtime to a copy of v4.
+
+char v5[13];
+
+// 6 Data in file 1 refers to global data in file 2. This reuses v2.
+
+// 7 Data in file 1 refers to common symbol in file 2. This reuses v3.
+
+// 8 Data in file 1 refers to offset within global data in file 2.
+// This reuses v4.
+
+// 9 Data in file 1 refers to offset within common symbol in file 2.
+// This reuses v5.
+
+// 10 Data in file 1 refers to function in file 2.
+
+int
+f10()
+{
+ return 135;
+}
+
+// 11 Pass function pointer from file 1 to file 2.
+
+int
+f11b(int (*pfn)())
+{
+ return (*pfn)();
+}
+
+// 12 Compare address of function for equality in both files.
+
+bool
+(*f12())()
+{
+ return &t12;
+}
+
+// 13 Compare address of inline function for equality in both files.
+
+void
+(*f13())()
+{
+ return &f13i;
+}
+
+// 14 Compare string constants in file 1 and file 2.
+
+const char*
+f14()
+{
+ return TEST_STRING_CONSTANT;
+}
+
+// 15 Compare wide string constants in file 1 and file 2.
+
+const wchar_t*
+f15()
+{
+ return TEST_WIDE_STRING_CONSTANT;
+}
+
+// 17 File 1 checks array of string constants defined in file 2.
+
+const char* t17data[T17_COUNT] =
+{
+ "a", "b", "c", "d", "e"
+};
+
+// 18 File 1 checks string constants referenced directly in file 2.
+
+const char*
+f18(int i)
+{
+ switch (i)
+ {
+ case 0:
+ return "a";
+ case 1:
+ return "b";
+ case 2:
+ return "c";
+ case 3:
+ return "d";
+ case 4:
+ return "e";
+ default:
+ return 0;
+ }
+}
diff --git a/binutils-2.25/gold/testsuite/two_file_test_2_v1.cc b/binutils-2.25/gold/testsuite/two_file_test_2_v1.cc
new file mode 100644
index 00000000..ea26c66f
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/two_file_test_2_v1.cc
@@ -0,0 +1,150 @@
+// two_file_test_2_v1.cc -- a two file test case for gold, file 2 of 2
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 is an alternate version of the source file two_file_test_2.cc,
+// used to test incremental linking. We build a binary first using this
+// source file, then do an incremental link with the primary version of
+// the file.
+
+// This tests references between files. This is file 2, and
+// two_file_test_1.cc is file 1. See file 1 for details.
+
+#include "two_file_test.h"
+
+// 1 Code in file 1 calls code in file 2.
+
+int
+t1_2()
+{
+ return 0;
+}
+
+bool
+t1a()
+{
+ return t1_2() == 0;
+}
+
+// 2 Code in file 1 refers to global data in file 2.
+
+int v2 = 1;
+
+// 3 Code in file 1 referes to common symbol in file 2. This is
+// initialized at runtime to 789.
+
+int v3;
+
+// 4 Code in file 1 refers to offset within global data in file 2.
+
+char v4[] = "World, hello";
+
+// 5 Code in file 1 refers to offset within common symbol in file 2.
+// This is initialized at runtime to a copy of v4.
+
+char v5[13];
+
+// 6 Data in file 1 refers to global data in file 2. This reuses v2.
+
+// 7 Data in file 1 refers to common symbol in file 2. This reuses v3.
+
+// 8 Data in file 1 refers to offset within global data in file 2.
+// This reuses v4.
+
+// 9 Data in file 1 refers to offset within common symbol in file 2.
+// This reuses v5.
+
+// 10 Data in file 1 refers to function in file 2.
+
+int
+f10()
+{
+ return 0;
+}
+
+// 11 Pass function pointer from file 1 to file 2.
+
+int
+f11b(int (*pfn)())
+{
+ return (*pfn)();
+}
+
+// 12 Compare address of function for equality in both files.
+
+bool
+(*f12())()
+{
+ return &t12;
+}
+
+// 13 Compare address of inline function for equality in both files.
+
+void
+(*f13())()
+{
+ return &f13i;
+}
+
+// 14 Compare string constants in file 1 and file 2.
+
+const char*
+f14()
+{
+ return TEST_STRING_CONSTANT;
+}
+
+// 15 Compare wide string constants in file 1 and file 2.
+
+const wchar_t*
+f15()
+{
+ return TEST_WIDE_STRING_CONSTANT;
+}
+
+// 17 File 1 checks array of string constants defined in file 2.
+
+const char* t17data[T17_COUNT] =
+{
+ "0", "1", "2", "3", "4"
+};
+
+// 18 File 1 checks string constants referenced directly in file 2.
+
+const char*
+f18(int i)
+{
+ switch (i)
+ {
+ case 0:
+ return "0";
+ case 1:
+ return "1";
+ case 2:
+ return "2";
+ case 3:
+ return "3";
+ case 4:
+ return "4";
+ default:
+ return 0;
+ }
+}
diff --git a/binutils-2.25/gold/testsuite/two_file_test_main.cc b/binutils-2.25/gold/testsuite/two_file_test_main.cc
new file mode 100644
index 00000000..b7e38385
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/two_file_test_main.cc
@@ -0,0 +1,57 @@
+// two_file_test_main.cc -- a two file test case for gold, main function
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 tests references between files. This is the main file. See
+// two_file_test_1.cc for details.
+
+#include <cassert>
+
+#include "two_file_test.h"
+
+int
+main()
+{
+ // Initialize common data.
+ v3 = 789;
+ for (int i = 0; i < 13; ++i)
+ v5[i] = v4[i];
+
+ assert(t1());
+ assert(t1a());
+ assert(t2());
+ assert(t3());
+ assert(t4());
+ assert(t5());
+ assert(t6());
+ assert(t7());
+ assert(t8());
+ assert(t9());
+ assert(t10());
+ assert(t11());
+ assert(t12());
+ assert(t13());
+ assert(t16());
+ assert(t16a());
+ assert(t17());
+ assert(t18());
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/two_file_test_tls.cc b/binutils-2.25/gold/testsuite/two_file_test_tls.cc
new file mode 100644
index 00000000..d9a1c39d
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/two_file_test_tls.cc
@@ -0,0 +1,60 @@
+// two_file_test_tls.cc -- a two file test case for gold, main function, with TLS
+
+// Copyright 2006, 2007, 2008, 2013 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 tests references between files. This is the main file. See
+// two_file_test_1.cc for details.
+
+#include <cassert>
+
+#include "two_file_test.h"
+
+extern __thread int tls1;
+
+int
+main()
+{
+ // Initialize common data.
+ v3 = 789;
+ for (int i = 0; i < 13; ++i)
+ v5[i] = v4[i];
+
+ assert(tls1 == 123);
+ assert(t1());
+ assert(t1a());
+ assert(t2());
+ assert(t3());
+ assert(t4());
+ assert(t5());
+ assert(t6());
+ assert(t7());
+ assert(t8());
+ assert(t9());
+ assert(t10());
+ assert(t11());
+ assert(t12());
+ assert(t13());
+ assert(t16());
+ assert(t16a());
+ assert(t17());
+ assert(t18());
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/undef_symbol.cc b/binutils-2.25/gold/testsuite/undef_symbol.cc
new file mode 100644
index 00000000..e35b2b24
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/undef_symbol.cc
@@ -0,0 +1,40 @@
+// undef_symbol.cc -- a test case for undefined references
+
+// Copyright 2007, 2008, 2013 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 constructed to have an undefined reference to the
+// global variable a. We should get an error when we link.
+
+extern int a;
+
+class Foo
+{
+ public:
+ Foo()
+ : a_(a)
+ { }
+ int get_a()
+ { return a_; }
+ private:
+ int a_;
+};
+
+static Foo foo;
diff --git a/binutils-2.25/gold/testsuite/undef_symbol.sh b/binutils-2.25/gold/testsuite/undef_symbol.sh
new file mode 100755
index 00000000..b689edce
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/undef_symbol.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# undef_symbol.sh -- a test case for undefined symbols in shared libraries
+
+# Copyright 2007, 2008 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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 goes with debug_msg.cc, a C++ source file constructed to
+# have undefined references. We compile that file with debug
+# information and then try to link it, and make sure the proper errors
+# are displayed. The errors will be found in debug_msg.err.
+
+check()
+{
+ if ! grep -q "$1" undef_symbol.err
+ then
+ echo "Did not find expected error:"
+ echo " $1"
+ echo ""
+ echo "Actual error output below:"
+ cat undef_symbol.err
+ exit 1
+ fi
+}
+
+check "undef_symbol.so: error: undefined reference to 'a'"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/undef_symbol_main.cc b/binutils-2.25/gold/testsuite/undef_symbol_main.cc
new file mode 100644
index 00000000..2c210443
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/undef_symbol_main.cc
@@ -0,0 +1,29 @@
+// undef_symbol_1.cc -- a test case for undefined references
+
+// Copyright 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+// Main function for undefined symbol test.
+
+int
+main()
+{
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/ver_matching_def.cc b/binutils-2.25/gold/testsuite/ver_matching_def.cc
new file mode 100644
index 00000000..b654dff5
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_matching_def.cc
@@ -0,0 +1,73 @@
+// ver_matching_def.cc - test matching rules in version_script.map
+
+// Copyright 2007, 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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.
+
+extern "C" {
+void foo() {} // V1
+void foo1() {} // local
+};
+
+void bar() {} // V1
+void bar1() {} // global
+
+void baz(int*) {} // V1
+void baz(int*, char) {} // global
+void baz(char*, int) {} // global
+
+extern "C" {
+void bar2() {} // V1
+};
+
+namespace myns {
+void blah() {} // V1
+void bip() {} // V1
+
+class Stuff {
+ public:
+ Stuff() {} // V1
+};
+}
+
+class Biz {
+ public:
+ Biz() {} // global
+};
+
+namespace otherns {
+Biz biz; // global
+myns::Stuff stuff; // V2
+};
+
+extern "C" {
+void blaza() {} // V1
+void blaza1() {} // V1
+
+void original_blaza2() {} // V2
+__asm__(".symver original_blaza2,blaza2@@V2"); // overrides script
+
+void bla() {} // global
+void blaz() {} // V2
+void blazb() {} // V2
+
+int globaoeufxstuff = 0; // V1
+int globaoeufostuff = 0; // global
+float sizeof_headers = 50.0; // V1
+};
diff --git a/binutils-2.25/gold/testsuite/ver_matching_test.sh b/binutils-2.25/gold/testsuite/ver_matching_test.sh
new file mode 100755
index 00000000..4880efab
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_matching_test.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+
+# ver_matching_test.sh -- a test case for version script matching
+
+# Copyright 2008, 2010 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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 goes with ver_matching_def.cc, a C++ source file
+# constructed with several symbols mapped via version_script.map. We
+# run readelf on the resulting shared object and check that each
+# symbol has the correct version.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected symbol in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check_missing()
+{
+ if grep -q "$2" "$1"
+ then
+ echo "Found unexpected symbol in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check ver_matching_test.stdout "V1 *sizeof_headers$"
+check ver_matching_test.stdout "Base *globaoeufostuff$"
+check ver_matching_test.stdout "V1 *globaoeufxstuff$"
+check ver_matching_test.stdout "V2 *otherns::stuff$"
+check ver_matching_test.stdout "Base *otherns::biz$"
+check ver_matching_test.stdout "V1 *foo$"
+check ver_matching_test.stdout "V1 *bar()$"
+check ver_matching_test.stdout "Base *bar1()$"
+check ver_matching_test.stdout "V1 *bar2$"
+check ver_matching_test.stdout "V1 *myns::blah()$"
+check ver_matching_test.stdout "V1 *myns::bip()$"
+check ver_matching_test.stdout "V1 *myns::Stuff::Stuff()$"
+check ver_matching_test.stdout "Base *Biz::Biz()$"
+check ver_matching_test.stdout "V2 *blaza1$"
+check ver_matching_test.stdout "V2 *blaza2$"
+check ver_matching_test.stdout "V2 *blaza$"
+check ver_matching_test.stdout "Base *bla$"
+check ver_matching_test.stdout "V2 *blaz$"
+check ver_matching_test.stdout "V2 *blazb$"
+
+# Stuff inside quotes is matched literally, so "baz(int*, char)" should
+# not match the "baz(int *)" entry in the version table.
+check ver_matching_test.stdout "V1 *baz(int\\*)$"
+check_missing ver_matching_test.stdout "V1 *baz(int\\*, char)$"
+check_missing ver_matching_test.stdout "V1 *baz(char\\*, int)$"
+
+check_missing ver_matching_test.stdout "foo1"
+
+# This symbols is injected by the linker itself, but should still
+# follow local:
+check_missing ver_matching_test.stdout "__bss_start"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/ver_test.h b/binutils-2.25/gold/testsuite/ver_test.h
new file mode 100644
index 00000000..0b1aea8d
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test.h
@@ -0,0 +1,43 @@
+// ver_test.h -- a test case for gold
+
+// Copyright 2007, 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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.
+
+#ifdef USE_TRACE
+#include <cstdio>
+#define TRACE printf("In %s, %s()\n", __FILE__, __FUNCTION__);
+#else
+#define TRACE
+#endif
+
+extern bool t1();
+extern bool t2();
+extern bool t3();
+extern bool t4();
+
+extern "C" {
+
+extern int t1_2();
+extern int t2_2();
+extern int t3_2();
+extern int t4_2();
+extern int t4_2a();
+
+}
diff --git a/binutils-2.25/gold/testsuite/ver_test_1.cc b/binutils-2.25/gold/testsuite/ver_test_1.cc
new file mode 100644
index 00000000..42a18ec9
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_1.cc
@@ -0,0 +1,33 @@
+// ver_test_1.cc -- a test case for gold
+
+// Copyright 2007, 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 "ver_test.h"
+
+// Calls an unversioned function in file1 that overrides
+// a versioned function in file2.
+
+bool
+t1()
+{
+ TRACE
+ return t1_2() == 11;
+}
diff --git a/binutils-2.25/gold/testsuite/ver_test_1.sh b/binutils-2.25/gold/testsuite/ver_test_1.sh
new file mode 100755
index 00000000..edf73518
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_1.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+# ver_test_1.sh -- check that protected symbols are local
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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.
+
+syms=`grep ' HIDDEN ' ver_test_1.syms | grep ' GLOBAL '`
+if test -n "$syms"; then
+ echo "Found GLOBAL HIDDEN symbols"
+ echo $syms
+ exit 1
+fi
diff --git a/binutils-2.25/gold/testsuite/ver_test_10.script b/binutils-2.25/gold/testsuite/ver_test_10.script
new file mode 100644
index 00000000..fa9f1759
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_10.script
@@ -0,0 +1,30 @@
+## ver_test_10.script -- a test case for gold
+
+## Copyright 2008 Free Software Foundation, Inc.
+## Written by Ian Lance Taylor <iant@google.com>.
+
+## 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.
+
+# Test having a version script with no version.
+
+{
+ global:
+ t3_2;
+ local:
+ *;
+};
diff --git a/binutils-2.25/gold/testsuite/ver_test_10.sh b/binutils-2.25/gold/testsuite/ver_test_10.sh
new file mode 100755
index 00000000..68138a6d
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_10.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# ver_test_10.sh -- test global/local symbols
+
+# Copyright 2008 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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 goes with ver_test_4.script and ver_test_5.script. The
+# symbol t2_2 is not defined when ver_test_5.script is used.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected symbol in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check ver_test_10.syms "GLOBAL.*t3_2"
+check ver_test_10.syms "LOCAL.*t4_2"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/ver_test_2.cc b/binutils-2.25/gold/testsuite/ver_test_2.cc
new file mode 100644
index 00000000..b81e62e0
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_2.cc
@@ -0,0 +1,40 @@
+// ver_test_2.cc -- a test case for gold
+
+// Copyright 2007, 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 "ver_test.h"
+
+int
+t3_2()
+{
+ TRACE
+ return t1_2();
+}
+
+// Calls a versioned function in ver_test_4.cc which should be
+// overridden by an unversioned function in the main program.
+
+int
+t4_2()
+{
+ TRACE
+ return t4_2a();
+}
diff --git a/binutils-2.25/gold/testsuite/ver_test_2.script b/binutils-2.25/gold/testsuite/ver_test_2.script
new file mode 100644
index 00000000..15329d70
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_2.script
@@ -0,0 +1,31 @@
+## ver_test_2.script -- a test case for gold
+
+## Copyright 2007, 2008 Free Software Foundation, Inc.
+## Written by Cary Coutant <ccoutant@google.com>.
+
+## 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.
+
+VER1 {
+};
+
+VER2 {
+ global:
+ t1_2;
+ t3_2;
+ t4_2a;
+} VER1;
diff --git a/binutils-2.25/gold/testsuite/ver_test_2.sh b/binutils-2.25/gold/testsuite/ver_test_2.sh
new file mode 100755
index 00000000..0bd0f903
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_2.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# ver_test_2.sh -- test that symbol has correct version
+
+# Copyright 2008 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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 goes with ver_matching_def.cc, a C++ source file
+# constructed with several symbols mapped via version_script.map. We
+# run readelf on the resulting shared object and check that each
+# symbol has the correct version.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected symbol in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check ver_test_2.syms "t1_2@VER2"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/ver_test_3.cc b/binutils-2.25/gold/testsuite/ver_test_3.cc
new file mode 100644
index 00000000..022a888f
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_3.cc
@@ -0,0 +1,33 @@
+// ver_test_3.cc -- a test case for gold
+
+// Copyright 2007, 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 "ver_test.h"
+
+int
+t1_2() __attribute((visibility("hidden")));
+
+int
+t1_2()
+{
+ TRACE
+ return 11;
+}
diff --git a/binutils-2.25/gold/testsuite/ver_test_4.cc b/binutils-2.25/gold/testsuite/ver_test_4.cc
new file mode 100644
index 00000000..404dfbc3
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_4.cc
@@ -0,0 +1,64 @@
+// ver_test_4.cc -- a test case for gold
+
+// Copyright 2007, 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 "ver_test.h"
+
+__asm__(".symver t1_2_a,t1_2@@VER2");
+
+extern "C"
+int
+t1_2_a()
+{
+ TRACE
+ return 12;
+}
+
+__asm__(".symver t2_2_a,t2_2@VER1");
+
+extern "C"
+int
+t2_2_a()
+{
+ TRACE
+ return 21;
+}
+
+__asm__(".symver t2_2_b,t2_2@@VER2");
+
+extern "C"
+int
+t2_2_b()
+{
+ TRACE
+ return 22;
+}
+
+
+// This function is given a version by the version script, and should
+// be overridden by the main program.
+
+int
+t4_2a()
+{
+ TRACE
+ return -42;
+}
diff --git a/binutils-2.25/gold/testsuite/ver_test_4.script b/binutils-2.25/gold/testsuite/ver_test_4.script
new file mode 100644
index 00000000..e97c74eb
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_4.script
@@ -0,0 +1,35 @@
+## ver_test_4.script -- a test case for gold
+
+## Copyright 2007, 2008 Free Software Foundation, Inc.
+## Written by Cary Coutant <ccoutant@google.com>.
+
+## 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.
+
+VER1 {
+ global:
+ t2_2;
+ local:
+ *;
+};
+
+VER2 {
+ global:
+ t1_2;
+ t4_2a;
+} VER1;
+
diff --git a/binutils-2.25/gold/testsuite/ver_test_4.sh b/binutils-2.25/gold/testsuite/ver_test_4.sh
new file mode 100755
index 00000000..3466a5d4
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_4.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# ver_test_4.sh -- test that version symbol is visible.
+
+# Copyright 2008 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected symbol in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check ver_test_4.syms "t1_2@@VER2"
+check ver_test_4.syms "t2_2@VER1"
+check ver_test_4.syms "t2_2@@VER2"
+check ver_test_4.syms "GLOBAL.*ABS.*VER1"
+check ver_test_4.syms "GLOBAL.*ABS.*VER2"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/ver_test_5.cc b/binutils-2.25/gold/testsuite/ver_test_5.cc
new file mode 100644
index 00000000..cffeae64
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_5.cc
@@ -0,0 +1,29 @@
+// ver_test_5.cc -- a test case for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>
+
+// 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 "ver_test.h"
+
+int
+t3_2()
+{
+ return t2_2();
+}
diff --git a/binutils-2.25/gold/testsuite/ver_test_5.script b/binutils-2.25/gold/testsuite/ver_test_5.script
new file mode 100644
index 00000000..028cdd62
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_5.script
@@ -0,0 +1,31 @@
+## ver_test_5.script -- a test case for gold
+
+## Copyright 2008 Free Software Foundation, Inc.
+## Written by Ian Lance Taylor <iant@google.com>
+
+## 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 tests that we don't break when assigning a version to an
+# undefined symbol. This is used with ver_test_2.cc, which defines
+# t3_2 but only refers to t2_2.
+
+VER5 {
+ global:
+ t2_2;
+ t3_2;
+};
diff --git a/binutils-2.25/gold/testsuite/ver_test_5.sh b/binutils-2.25/gold/testsuite/ver_test_5.sh
new file mode 100755
index 00000000..2eacb455
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_5.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# ver_test_5.sh -- test that symbol has correct version
+
+# Copyright 2008 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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 goes with ver_test_4.script and ver_test_5.script. The
+# symbol t2_2 is not defined when ver_test_5.script is used.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected symbol in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check ver_test_5.syms "t3_2@@VER5"
+check ver_test_5.syms "t2_2@VER2"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/ver_test_6.c b/binutils-2.25/gold/testsuite/ver_test_6.c
new file mode 100644
index 00000000..44b483fd
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_6.c
@@ -0,0 +1,35 @@
+/* ver_test_6.c -- test common symbol with shared library version
+
+ Copyright 2008 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>
+
+ 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 is a test of a common symbol in the main program and a
+ versioned symbol in a shared library. The common symbol in the
+ main program should override the shared library symbol. */
+
+int t3_2;
+
+/* Since we don't use any of the arguments to main, we give it a void
+ prototype, so as to quiet gcc -Wstrict-prototypes. */
+int
+main(void)
+{
+ return t3_2;
+}
diff --git a/binutils-2.25/gold/testsuite/ver_test_7.cc b/binutils-2.25/gold/testsuite/ver_test_7.cc
new file mode 100644
index 00000000..d602a48f
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_7.cc
@@ -0,0 +1,37 @@
+// ver_test_7.cc -- test weak duplicate symbol with version
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>
+
+// 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 "ver_test.h"
+
+// This tests having a weak symbol which matches an entry in the
+// version script following a hidden definition from .symver. There
+// was a bug in which the weak symbol would cause the earlier symbol
+// to become globally visible when it should have been hidden.
+
+extern "C" int t2_2() __attribute__ ((weak));
+
+extern "C"
+int
+t2_2()
+{
+ return 23;
+}
diff --git a/binutils-2.25/gold/testsuite/ver_test_7.sh b/binutils-2.25/gold/testsuite/ver_test_7.sh
new file mode 100755
index 00000000..04d35fc9
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_7.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# ver_test_7.sh -- test that symbol has correct version
+
+# Copyright 2008 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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 goes with ver_test_4.script and ver_test_5.script. The
+# symbol t2_2 is not defined when ver_test_5.script is used.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected symbol in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check ver_test_7.syms "t2_2@@VER2"
+check ver_test_7.syms "t2_2@VER1"
+
+exit 0
diff --git a/binutils-2.25/gold/testsuite/ver_test_8.script b/binutils-2.25/gold/testsuite/ver_test_8.script
new file mode 100644
index 00000000..b5bfc3f0
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_8.script
@@ -0,0 +1,26 @@
+## ver_test_8.script -- a test case for gold
+
+## Copyright 2008 Free Software Foundation, Inc.
+## Written by Ian Lance Taylor <iant@google.com>
+
+## 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.
+
+VER_TEST_8 {
+ global:
+ *;
+};
diff --git a/binutils-2.25/gold/testsuite/ver_test_9.cc b/binutils-2.25/gold/testsuite/ver_test_9.cc
new file mode 100644
index 00000000..5d06d4ec
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_9.cc
@@ -0,0 +1,50 @@
+// ver_test_9.cc -- a test case for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 "ver_test.h"
+
+bool
+t1()
+{
+ return true;
+}
+
+int
+t2_2()
+{
+ TRACE
+ return 22;
+}
+
+int
+t3_2()
+{
+ TRACE
+ return 12;
+}
+
+int
+t4_2()
+{
+ TRACE
+ return 42;
+}
diff --git a/binutils-2.25/gold/testsuite/ver_test_main.cc b/binutils-2.25/gold/testsuite/ver_test_main.cc
new file mode 100644
index 00000000..f8a7b755
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_main.cc
@@ -0,0 +1,74 @@
+// ver_test_main.cc -- a test case for gold
+
+// Copyright 2007, 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 <cassert>
+
+#include "ver_test.h"
+
+int
+main()
+{
+ assert(t1());
+ assert(t2());
+ assert(t3());
+ assert(t4());
+ return 0;
+}
+
+// Calls a function in file2 that has two versions and verifies
+// that the default version is called.
+
+bool
+t2()
+{
+ TRACE
+ return t2_2() == 22;
+}
+
+// Call a function in a shared library that calls explicitly
+// the version of t1_2() defined in another shared library.
+
+bool
+t3()
+{
+ TRACE
+ return t3_2() == 12;
+}
+
+// Call a function in a shared library that calls a function which is
+// defined in the main program and defined with a default version in
+// the shared library. The symbol in the main program should override
+// even though it doesn't have a version.
+
+bool
+t4()
+{
+ TRACE
+ return t4_2() == 42;
+}
+
+int
+t4_2a()
+{
+ TRACE
+ return 42;
+}
diff --git a/binutils-2.25/gold/testsuite/ver_test_main_2.cc b/binutils-2.25/gold/testsuite/ver_test_main_2.cc
new file mode 100644
index 00000000..1599e0f3
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/ver_test_main_2.cc
@@ -0,0 +1,32 @@
+// ver_test_main_2.cc -- a test case for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cassert>
+
+#include "ver_test.h"
+
+int
+main()
+{
+ assert(t1_2() == 12);
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/version_script.map b/binutils-2.25/gold/testsuite/version_script.map
new file mode 100644
index 00000000..d3ba02ef
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/version_script.map
@@ -0,0 +1,34 @@
+V1 {
+ global:
+ extern "C++"
+ {
+ "bar()";
+ "baz(int*)";
+ };
+ foo;
+ blaza*;
+ bar*;
+ # Make sure we parse "extern" when it's not first thing in the section.
+ extern "C++"
+ {
+ myns::*;
+ };
+ # Would be a keyword in a linker script.
+ SECTIONS;
+ sizeof_headers;
+ # Crazy globbiness
+ glob*f[^A-Zo]st?ff;
+
+ local:
+ *foo*;
+};
+
+V2 {
+ global:
+ extern "C++" {
+ otherns::stuff;
+ };
+ blaz*;
+ local:
+ _[^A-Z]*;
+} V1;
diff --git a/binutils-2.25/gold/testsuite/weak_alias_test.script b/binutils-2.25/gold/testsuite/weak_alias_test.script
new file mode 100644
index 00000000..1911631d
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_alias_test.script
@@ -0,0 +1,8 @@
+VER1 {
+ global:
+ versioned_symbol;
+};
+VER2 {
+ global:
+ versioned_alias;
+};
diff --git a/binutils-2.25/gold/testsuite/weak_alias_test_1.cc b/binutils-2.25/gold/testsuite/weak_alias_test_1.cc
new file mode 100644
index 00000000..0ad92657
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_alias_test_1.cc
@@ -0,0 +1,52 @@
+// weak_alias_test_1.cc -- test weak aliases for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+// Define a weak symbol.
+
+extern int weak_symbol __attribute__ ((weak));
+int weak_symbol = 1;
+
+// Define a strong symbol with a weak alias.
+
+int strong_aliased = 2;
+extern int weak_aliased __attribute__ ((weak, alias ("strong_aliased")));
+
+// And another one.
+
+int strong_aliased_2 = 5;
+extern int weak_aliased_2 __attribute__ ((weak, alias ("strong_aliased_2")));
+
+// And a third.
+
+int strong_aliased_3 = 7;
+extern int weak_aliased_3 __attribute__ ((weak, alias ("strong_aliased_3")));
+
+// And a fourth.
+
+int strong_aliased_4 = 8;
+extern int weak_aliased_4 __attribute__ ((weak, alias ("strong_aliased_4")));
+
+// We want a symbol whose name is the same length as "strong_symbol",
+// so that weak_symbol here lines up with weak_symbol in
+// weak_alias_test_2.so.
+
+int Strong_Symbol = 101;
diff --git a/binutils-2.25/gold/testsuite/weak_alias_test_2.cc b/binutils-2.25/gold/testsuite/weak_alias_test_2.cc
new file mode 100644
index 00000000..8294525f
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_alias_test_2.cc
@@ -0,0 +1,41 @@
+// weak_alias_test_2.cc -- test weak aliases for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+// Define a strong symbol.
+
+int strong_symbol = 2;
+
+// Define a weak symbol. This will be overridden by the weak symbol
+// in weak_alias_test_1.cc.
+
+extern int weak_symbol __attribute__ ((weak));
+int weak_symbol = 3;
+
+// These are overridden by weak_alias_test_1.cc
+int strong_aliased = 100;
+extern int weak_aliased __attribute__ ((weak, alias ("strong_aliased")));
+int strong_aliased_2 = 102;
+extern int weak_aliased_2 __attribute__ ((weak, alias ("strong_aliased_2")));
+int strong_aliased_3 = 104;
+extern int weak_aliased_3 __attribute__ ((weak, alias ("strong_aliased_3")));
+int strong_aliased_4 = 106;
+extern int weak_aliased_4 __attribute__ ((weak, alias ("strong_aliased_4")));
diff --git a/binutils-2.25/gold/testsuite/weak_alias_test_3.cc b/binutils-2.25/gold/testsuite/weak_alias_test_3.cc
new file mode 100644
index 00000000..99152e2d
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_alias_test_3.cc
@@ -0,0 +1,26 @@
+// weak_alias_test_3.cc -- test weak aliases for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 is linked into the main program.
+
+extern int weak_symbol __attribute__ ((weak));
+int weak_symbol = 4;
diff --git a/binutils-2.25/gold/testsuite/weak_alias_test_4.cc b/binutils-2.25/gold/testsuite/weak_alias_test_4.cc
new file mode 100644
index 00000000..714c6d63
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_alias_test_4.cc
@@ -0,0 +1,68 @@
+// weak_alias_test_4.cc -- test weak aliases for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+// Verify that all the symbols look right from a shared library.
+
+extern int weak_symbol;
+extern int strong_aliased;
+extern int weak_aliased;
+extern int strong_aliased_2;
+extern int weak_aliased_2;
+extern int strong_aliased_3;
+extern int weak_aliased_3;
+extern int strong_aliased_4;
+extern int weak_aliased_4;
+extern int strong_symbol;
+
+bool
+t1()
+{
+ // Should come from weak_alias_test_3.cc.
+ if (weak_symbol != 4)
+ return false;
+
+ // Should come from weak_alias_test_main.cc.
+ if (strong_aliased != 3)
+ return false;
+
+ // weak_aliased need not match strong_aliased, which is overridden
+ // by weak_test_main.cc.
+
+ // Should come from weak_alias_test_main.cc.
+ if (weak_aliased_2 != 6)
+ return false;
+
+ // strong_aliased_2 need not match weak_aliased_2, which is
+ // overidden by weak_test_main.cc.
+
+ // The others should match.
+ if (weak_aliased_3 != 7 || strong_aliased_3 != 7)
+ return false;
+ if (weak_aliased_4 != 8 || strong_aliased_4 != 8)
+ return false;
+
+ // Should come from weak_alias_test_2.cc.
+ if (strong_symbol != 2)
+ return false;
+
+ return true;
+}
diff --git a/binutils-2.25/gold/testsuite/weak_alias_test_5.cc b/binutils-2.25/gold/testsuite/weak_alias_test_5.cc
new file mode 100644
index 00000000..df48092c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_alias_test_5.cc
@@ -0,0 +1,39 @@
+// weak_alias_test_5.cc -- test versioned weak aliases for gold
+
+// Copyright 2011 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+// Define a versioned symbol.
+int versioned_symbol = 1;
+__asm__(".symver versioned_symbol,versioned_symbol@@VER1");
+
+// Define a weak alias for the versioned symbol, with a different version.
+extern int versioned_alias __attribute__ ((weak, alias("versioned_symbol")));
+__asm__(".symver versioned_alias,versioned_alias@@VER2");
+
+bool
+t2()
+{
+ if (versioned_symbol != 1)
+ return false;
+ if (versioned_alias != 1)
+ return false;
+ return true;
+}
diff --git a/binutils-2.25/gold/testsuite/weak_alias_test_main.cc b/binutils-2.25/gold/testsuite/weak_alias_test_main.cc
new file mode 100644
index 00000000..e3f86207
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_alias_test_main.cc
@@ -0,0 +1,80 @@
+// weak_alias_test_main.cc -- test weak aliases for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <assert.h>
+
+// Defined in both weak_alias_test_1.cc and weak_alias_test_2.cc, but
+// we should get the one in weak_alias_test_1.cc.
+extern int weak_symbol;
+
+// Defined in weak_alias_test_2.cc.
+extern int strong_symbol;
+
+// weak_aliased is an alias for this.
+int strong_aliased = 3;
+
+// Defined as a weak alias in weak_alias_test_1.cc.
+int weak_aliased_2 = 6;
+
+// Defined in weak_alias_test_1.cc
+extern int strong_aliased_3;
+extern int weak_aliased_4;
+
+// Defined in weak_alias_test_5.cc
+extern int versioned_symbol;
+extern int versioned_alias;
+
+extern bool t1();
+extern bool t2();
+
+int
+main()
+{
+ // weak_symbol should come from weak_alias_test_3.cc.
+ assert(weak_symbol == 4);
+
+ // strong_symbol should come from weak_alias_test_2.cc.
+ assert(strong_symbol == 2);
+
+ // strong_aliased should come from this file, above.
+ assert(strong_aliased == 3);
+
+ // weak_aliased_2 should come from this file, above.
+ assert(weak_aliased_2 == 6);
+
+ // strong_aliased_3 should come from weak_alias_test_1.cc.
+ assert(strong_aliased_3 == 7);
+
+ // weak_aliased_4 should come from weak_alias_test_1.cc.
+ assert(weak_aliased_4 == 8);
+
+ // Make sure the symbols look right from a shared library.
+ assert(t1());
+
+ // versioned_symbol comes from weak_alias_test_5.cc.
+ assert(versioned_symbol == 1);
+ // So does versioned_alias.
+ assert(versioned_alias == 1);
+
+ // Make sure the versioned symbols look right from a shared library.
+ assert(t2());
+}
diff --git a/binutils-2.25/gold/testsuite/weak_plt.sh b/binutils-2.25/gold/testsuite/weak_plt.sh
new file mode 100755
index 00000000..6c419b80
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_plt.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# weak_plt.sh -- test calling a weak undefined function.
+
+# Copyright 2008 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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 tests a call to a weak undefined function. We use LD_PRELOAD
+# to force the function to be defined.
+
+LD_PRELOAD=./weak_plt_shared.so ./weak_plt
diff --git a/binutils-2.25/gold/testsuite/weak_plt_main.cc b/binutils-2.25/gold/testsuite/weak_plt_main.cc
new file mode 100644
index 00000000..33cb35eb
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_plt_main.cc
@@ -0,0 +1,33 @@
+// weak_plt_main.cc -- test call to weak undefined function for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cstdio>
+
+extern int weak_function() __attribute__((weak));
+
+int
+main()
+{
+ if (weak_function)
+ return weak_function();
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/weak_plt_shared.cc b/binutils-2.25/gold/testsuite/weak_plt_shared.cc
new file mode 100644
index 00000000..8d82005d
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_plt_shared.cc
@@ -0,0 +1,29 @@
+// weak_plt_shared.cc -- test call to weak undefined function for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cstdio>
+
+int
+weak_function()
+{
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/weak_test.cc b/binutils-2.25/gold/testsuite/weak_test.cc
new file mode 100644
index 00000000..c14a688d
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_test.cc
@@ -0,0 +1,47 @@
+// weak_test.cc -- test handling of weak symbols for gold
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 provides a set of test functions for TLS variables. The
+// functions are called by a main function in tls_test_main.cc. This
+// lets us test TLS access from a shared library. We currently don't
+// bother to test TLS access between two different files, on the
+// theory that that is no more complicated than ordinary variable
+// access between files.
+
+// We test that we correctly deal with weak symbols defined in
+// other libraries (in this case, libc). We need to make sure we
+// copy the associated GLOBAL reloc when we copy a WEAK reloc.
+
+
+#include <cstdio>
+
+int
+main()
+{
+ extern char** environ; // defined in libc
+ if (environ == NULL)
+ {
+ fprintf(stderr, "FAILED the environ test: environ is NULL\n");
+ return 1;
+ }
+ return 0;
+}
diff --git a/binutils-2.25/gold/testsuite/weak_undef.h b/binutils-2.25/gold/testsuite/weak_undef.h
new file mode 100644
index 00000000..17d5f02e
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_undef.h
@@ -0,0 +1,25 @@
+// weak_undef.h -- test handling of weak undefined symbols for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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.
+
+extern int t1();
+extern int t2();
+extern int t3();
diff --git a/binutils-2.25/gold/testsuite/weak_undef_file1.cc b/binutils-2.25/gold/testsuite/weak_undef_file1.cc
new file mode 100644
index 00000000..fd288704
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_undef_file1.cc
@@ -0,0 +1,75 @@
+// weak_undef_file1.cc -- test handling of weak undefined symbols for gold
+
+// Copyright 2008, 2010 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 test that we correctly deal with weak undefined symbols.
+// We need to make sure that the symbol is resolved to zero
+// by the linker and that no dynamic relocation is generated.
+
+// This source is used to build a shared library that defines
+// an arbitrary symbol other than the weak undefined symbol
+// referenced by the main program. The main program will be
+// linked with this library so that the symbol remains undefined.
+// Through the use of the embedded RPATH, the program will load
+// an alternate shared library that does define the symbol,
+// so that we can detect whether the symbol was left for runtime
+// resolution.
+
+#include <cstdio>
+
+#include "weak_undef.h"
+
+int is_such_symbol_ = 1;
+
+// We also define a symbol that is not defined by the alternate
+// library. The main program contains a weak reference to this
+// symbol, and tests that the reference remains weak even after
+// the definition was found at link time.
+
+int link_time_only = 1;
+
+extern int v2 __attribute__ ((weak));
+
+int *v3 = &v2;
+
+int
+t1()
+{
+ return is_such_symbol_;
+}
+
+// Test that a weak reference from a shared library to a symbol
+// defined in the main program does get resolved.
+
+int
+t2()
+{
+ return (&v2 == NULL) ? -1 : v2;
+}
+
+// Test that a weak reference from a shared library to a symbol
+// defined in the main program does get resolved.
+
+int
+t3()
+{
+ return (v3 == NULL) ? -1 : *v3;
+}
diff --git a/binutils-2.25/gold/testsuite/weak_undef_file2.cc b/binutils-2.25/gold/testsuite/weak_undef_file2.cc
new file mode 100644
index 00000000..33701b2c
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_undef_file2.cc
@@ -0,0 +1,70 @@
+// weak_undef_file2.cc -- test handling of weak undefined symbols for gold
+
+// Copyright 2008, 2010 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 test that we correctly deal with weak undefined symbols.
+// We need to make sure that the symbol is resolved to zero
+// by the linker and that no dynamic relocation is generated.
+
+// This source is used to build a shared library that defines
+// the weak undefined symbol referenced by the main program.
+// The main program will be linked with a library that does not
+// provide this definition, so that the symbol remains undefined.
+// Through the use of the embedded RPATH, the program will load
+// this alternate shared library that does define the symbol,
+// so that we can detect whether the symbol was left for runtime
+// resolution.
+
+
+#include <cstdio>
+
+#include "weak_undef.h"
+
+int is_such_symbol_ = 1;
+int no_such_symbol_ = 2;
+
+extern int v2 __attribute__ ((weak));
+
+int *v3 = &v2;
+
+int
+t1()
+{
+ return no_such_symbol_;
+}
+
+// Test that a weak reference from a shared library to a symbol
+// defined in the main program does get resolved.
+
+int
+t2()
+{
+ return (&v2 == NULL) ? -1 : v2;
+}
+
+// Test that a weak reference from a shared library to a symbol
+// defined in the main program does get resolved.
+
+int
+t3()
+{
+ return (v3 == NULL) ? -1 : *v3;
+}
diff --git a/binutils-2.25/gold/testsuite/weak_undef_test.cc b/binutils-2.25/gold/testsuite/weak_undef_test.cc
new file mode 100644
index 00000000..880d5cdc
--- /dev/null
+++ b/binutils-2.25/gold/testsuite/weak_undef_test.cc
@@ -0,0 +1,106 @@
+// weak_undef_test.cc -- test handling of weak undefined symbols for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// 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 test that we correctly deal with weak undefined symbols.
+// We need to make sure that a weak undefined symbol in the main
+// program is resolved to zero by the linker and that no dynamic
+// relocation is generated. We also make sure that a weak undefined
+// symbol in a shared library can resolve to a symbol in the main
+// program.
+
+// This file will be linked with a shared library that does not
+// define the symbol, so that the symbol remains undefined.
+// Through the use of LD_LIBRARY_PATH, the program will load
+// an alternate shared library that does define the symbol,
+// so that we can detect whether the symbol was left for runtime
+// resolution.
+
+// Similarly, this file will be linked with a shared library that
+// does define a different symbol, and loaded with an alternate
+// shared library that does not define that symbol. We check that
+// the weak reference remains weak, and that it is resolved to
+// zero at runtime.
+
+
+#include <cstdio>
+#include "weak_undef.h"
+
+extern int no_such_symbol_ __attribute__ ((weak));
+
+extern int link_time_only __attribute__ ((weak));
+
+int *p1 = &no_such_symbol_;
+
+int *p2 = &link_time_only;
+
+int v2 = 42;
+
+int
+main()
+{
+ int status = 0;
+ int v;
+
+ if ((v = t1()) != 2)
+ {
+ fprintf(stderr, "FAILED weak undef test 1: %s\n",
+ "bound to wrong library");
+ status = 1;
+ }
+
+ if ((v = t2()) != 42)
+ {
+ fprintf(stderr, "FAILED weak undef test 2: expected %d, got %d\n",
+ 42, v);
+ status = 1;
+ }
+
+ if ((v = t3()) != 42)
+ {
+ fprintf(stderr, "FAILED weak undef test 3: expected %d, got %d\n",
+ 42, v);
+ status = 1;
+ }
+
+ if (&no_such_symbol_ != NULL)
+ {
+ fprintf(stderr, "FAILED weak undef test 4: %s\n",
+ "&no_such_symbol_ is not NULL");
+ status = 1;
+ }
+
+ if (p1 != NULL)
+ {
+ fprintf(stderr, "FAILED weak undef test 5: %s\n",
+ "p1 is not NULL");
+ status = 1;
+ }
+
+ if (p2 != NULL)
+ {
+ fprintf(stderr, "FAILED weak undef test 6: %s\n",
+ "p2 is not NULL");
+ status = 1;
+ }
+
+ return status;
+}
diff --git a/binutils-2.25/gold/tilegx.cc b/binutils-2.25/gold/tilegx.cc
new file mode 100644
index 00000000..576a28c6
--- /dev/null
+++ b/binutils-2.25/gold/tilegx.cc
@@ -0,0 +1,4924 @@
+// tilegx.cc -- tilegx target support for gold.
+
+// Copyright 2012, 2013 Free Software Foundation, Inc.
+// Written by Jiong Wang (jiwang@tilera.com)
+
+// 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 <cstring>
+
+#include "elfcpp.h"
+#include "dwarf.h"
+#include "parameters.h"
+#include "reloc.h"
+#include "tilegx.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 "gc.h"
+#include "icf.h"
+
+// the first got entry reserved
+const int32_t TILEGX_GOT_RESERVE_COUNT = 1;
+
+// the first two .got.plt entry reserved
+const int32_t TILEGX_GOTPLT_RESERVE_COUNT = 2;
+
+// 1. for both 64/32 bit mode, the instruction bundle is always 64bit.
+// 2. thus .plt section should always be aligned to 64 bit.
+const int32_t TILEGX_INST_BUNDLE_SIZE = 64;
+
+namespace
+{
+
+using namespace gold;
+
+// A class to handle the PLT data.
+// This is an abstract base class that handles most of the linker details
+// but does not know the actual contents of PLT entries. The derived
+// classes below fill in those details.
+
+template<int size, bool big_endian>
+class Output_data_plt_tilegx : public Output_section_data
+{
+ public:
+ typedef Output_data_reloc<elfcpp::SHT_RELA, true,size, big_endian>
+ Reloc_section;
+
+ Output_data_plt_tilegx(Layout* layout, uint64_t addralign,
+ Output_data_got<size, big_endian>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_section_data(addralign), layout_(layout),
+ irelative_rel_(NULL), got_(got), got_plt_(got_plt),
+ got_irelative_(got_irelative), count_(0),
+ irelative_count_(0), free_list_()
+ { this->init(layout); }
+
+ Output_data_plt_tilegx(Layout* layout, uint64_t plt_entry_size,
+ Output_data_got<size, big_endian>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ : Output_section_data((plt_count + 1) * plt_entry_size,
+ TILEGX_INST_BUNDLE_SIZE, false),
+ layout_(layout), irelative_rel_(NULL), got_(got),
+ got_plt_(got_plt), got_irelative_(got_irelative), count_(plt_count),
+ irelative_count_(0), free_list_()
+ {
+ this->init(layout);
+
+ // Initialize the free list and reserve the first entry.
+ this->free_list_.init((plt_count + 1) * plt_entry_size, false);
+ this->free_list_.remove(0, plt_entry_size);
+ }
+
+ // Initialize the PLT section.
+ void
+ init(Layout* layout);
+
+ // 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<size, big_endian>*, unsigned int);
+
+ // Add the relocation for a PLT entry.
+ void
+ add_relocation(Symbol_table*, Layout*, Symbol*, unsigned int);
+
+ // Return the .rela.plt section data.
+ Reloc_section*
+ rela_plt()
+ { return this->rel_; }
+
+ // Return where the IRELATIVE relocations should go in the PLT
+ // relocations.
+ Reloc_section*
+ rela_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 plt_entry_size; }
+
+ // Reserve a slot in the PLT for an existing symbol in an incremental update.
+ void
+ reserve_slot(unsigned int plt_index)
+ {
+ this->free_list_.remove((plt_index + 1) * this->get_plt_entry_size(),
+ (plt_index + 2) * this->get_plt_entry_size());
+ }
+
+ // Return the PLT address to use for a global symbol.
+ uint64_t
+ address_for_global(const Symbol*);
+
+ // Return the PLT address to use for a local symbol.
+ uint64_t
+ address_for_local(const Relobj*, unsigned int symndx);
+
+ protected:
+ // Fill in the first PLT entry.
+ void
+ fill_first_plt_entry(unsigned char*);
+
+ // Fill in a normal PLT entry. Returns the offset into the entry that
+ // should be the initial GOT slot value.
+ void
+ fill_plt_entry(unsigned char*,
+ typename elfcpp::Elf_types<size>::Elf_Addr,
+ unsigned int,
+ typename elfcpp::Elf_types<size>::Elf_Addr,
+ unsigned int, unsigned int);
+
+ 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();
+
+ // Write out the PLT data.
+ void
+ do_write(Output_file*);
+
+ // 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 IRELATIVE relocs, if necessary. These must follow the
+ // regular PLT relocations.
+ Reloc_section* irelative_rel_;
+ // The .got section.
+ Output_data_got<size, big_endian>* got_;
+ // 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_TILEGX_IRELATIVE relocs. These
+ // follow the regular PLT entries.
+ unsigned int irelative_count_;
+ // List of available regions within the section, for incremental
+ // update links.
+ Free_list free_list_;
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 40;
+ // The first entry in the PLT.
+ static const unsigned char first_plt_entry[plt_entry_size];
+ // Other entries in the PLT for an executable.
+ static const unsigned char plt_entry[plt_entry_size];
+};
+
+// The tilegx target class.
+// See the ABI at
+// http://www.tilera.com/scm
+// TLS info comes from
+// http://people.redhat.com/drepper/tls.pdf
+
+template<int size, bool big_endian>
+class Target_tilegx : public Sized_target<size, big_endian>
+{
+ public:
+ // TileGX use RELA
+ typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
+ Reloc_section;
+
+ Target_tilegx(const Target::Target_info* info = &tilegx_info)
+ : Sized_target<size, big_endian>(info),
+ got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
+ global_offset_table_(NULL), tilegx_dynamic_(NULL), rela_dyn_(NULL),
+ rela_irelative_(NULL), copy_relocs_(elfcpp::R_TILEGX_COPY),
+ got_mod_index_offset_(-1U),
+ tls_get_addr_sym_defined_(false)
+ { }
+
+ // Scan the relocations to look for symbol adjustments.
+ void
+ gc_process_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols);
+
+ // Scan the relocations to look for symbol adjustments.
+ void
+ scan_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols);
+
+ // 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<size, 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,
+ typename elfcpp::Elf_types<size>::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<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols,
+ Relocatable_relocs*);
+
+ // Relocate a section during a relocatable link.
+ void
+ relocate_relocs(
+ const Relocate_info<size, big_endian>*,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
+ const Relocatable_relocs*,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+ section_size_type view_size,
+ unsigned char* reloc_view,
+ section_size_type reloc_view_size);
+
+ // 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; }
+
+ // define tilegx specific symbols
+ virtual void
+ do_define_standard_symbols(Symbol_table*, Layout*);
+
+ // Return the PLT section.
+ 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); }
+
+ // This function should be defined in targets that can use relocation
+ // types to determine (implemented in local_reloc_may_be_function_pointer
+ // and global_reloc_may_be_function_pointer)
+ // if a function's pointer is taken. ICF uses this in safe mode to only
+ // fold those functions whose pointer is defintely not taken. For tilegx
+ // pie binaries, safe ICF cannot be done by looking at relocation types.
+ 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 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->got_ == NULL)
+ return 0;
+ return this->got_size() / (size / 8);
+ }
+
+ // 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;
+
+ // Create the GOT section for an incremental update.
+ Output_data_got_base*
+ init_got_plt_for_update(Symbol_table* symtab,
+ Layout* layout,
+ unsigned int got_count,
+ unsigned int plt_count);
+
+ // Reserve a GOT entry for a local symbol, and regenerate any
+ // necessary dynamic relocations.
+ void
+ reserve_local_got_entry(unsigned int got_index,
+ Sized_relobj<size, big_endian>* obj,
+ unsigned int r_sym,
+ unsigned int got_type);
+
+ // Reserve a GOT entry for a global symbol, and regenerate any
+ // necessary dynamic relocations.
+ void
+ reserve_global_got_entry(unsigned int got_index, Symbol* gsym,
+ unsigned int got_type);
+
+ // Register an existing PLT entry for a global symbol.
+ void
+ register_global_plt_entry(Symbol_table*, Layout*, unsigned int plt_index,
+ Symbol* gsym);
+
+ // Force a COPY relocation for a given symbol.
+ void
+ emit_copy_reloc(Symbol_table*, Symbol*, Output_section*, off_t);
+
+ // Apply an incremental relocation.
+ void
+ apply_relocation(const Relocate_info<size, big_endian>* relinfo,
+ typename elfcpp::Elf_types<size>::Elf_Addr r_offset,
+ unsigned int r_type,
+ typename elfcpp::Elf_types<size>::Elf_Swxword r_addend,
+ const Symbol* gsym,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size);
+
+ 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_tilegx* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+ const elfcpp::Sym<size, big_endian>& lsym,
+ bool is_discarded);
+
+ inline void
+ global(Symbol_table* symtab, Layout* layout, Target_tilegx* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+ Symbol* gsym);
+
+ inline bool
+ local_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
+ Target_tilegx* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, big_endian>& reloc,
+ unsigned int r_type,
+ const elfcpp::Sym<size, big_endian>& lsym);
+
+ inline bool
+ global_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
+ Target_tilegx* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, big_endian>& reloc,
+ unsigned int r_type,
+ Symbol* gsym);
+
+ private:
+ static void
+ unsupported_reloc_local(Sized_relobj_file<size, big_endian>*,
+ unsigned int r_type);
+
+ static void
+ unsupported_reloc_global(Sized_relobj_file<size, big_endian>*,
+ unsigned int r_type, Symbol*);
+
+ void
+ check_non_pic(Relobj*, unsigned int r_type);
+
+ inline bool
+ possible_function_pointer_reloc(unsigned int r_type);
+
+ bool
+ reloc_needs_plt_for_ifunc(Sized_relobj_file<size, big_endian>*,
+ 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()
+ {
+ }
+
+ // Do a relocation. Return false if the caller should not issue
+ // any warnings about this relocation.
+ inline bool
+ relocate(const Relocate_info<size, big_endian>*, Target_tilegx*,
+ Output_section*,
+ size_t relnum, const elfcpp::Rela<size, big_endian>&,
+ unsigned int r_type, const Sized_symbol<size>*,
+ const Symbol_value<size>*,
+ unsigned char*, typename elfcpp::Elf_types<size>::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.
+ Output_data_got<size, big_endian>*
+ 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 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<size, big_endian>* relobj,
+ unsigned int local_sym_index);
+
+ // Create a GOT entry for the TLS module index.
+ unsigned int
+ got_mod_index_entry(Symbol_table* symtab, Layout* layout,
+ Sized_relobj_file<size, big_endian>* object);
+
+ // Get the PLT section.
+ Output_data_plt_tilegx<size, big_endian>*
+ plt_section() const
+ {
+ gold_assert(this->plt_ != NULL);
+ return this->plt_;
+ }
+
+ // Get the dynamic reloc section, creating it if necessary.
+ Reloc_section*
+ rela_dyn_section(Layout*);
+
+ // Get the section to use for IRELATIVE relocations.
+ Reloc_section*
+ rela_irelative_section(Layout*);
+
+ // Add a potential copy relocation.
+ void
+ copy_reloc(Symbol_table* symtab, Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int shndx, Output_section* output_section,
+ Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
+ {
+ this->copy_relocs_.copy_reloc(symtab, layout,
+ symtab->get_sized_symbol<size>(sym),
+ object, shndx, output_section,
+ reloc, this->rela_dyn_section(layout));
+ }
+
+ // Information about this specific target which we pass to the
+ // general Target structure.
+ static const Target::Target_info tilegx_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_OFFSET = 1, // GOT entry for TLS offset
+ GOT_TYPE_TLS_PAIR = 2, // GOT entry for TLS module/offset pair
+ GOT_TYPE_TLS_DESC = 3 // GOT entry for TLS_DESC pair
+ };
+
+ // This type is used as the argument to the target specific
+ // relocation routines. The only target specific reloc is
+ // R_X86_64_TLSDESC against a local symbol.
+ struct Tlsdesc_info
+ {
+ Tlsdesc_info(Sized_relobj_file<size, big_endian>* a_object,
+ unsigned int a_r_sym)
+ : object(a_object), r_sym(a_r_sym)
+ { }
+
+ // The object in which the local symbol is defined.
+ Sized_relobj_file<size, big_endian>* object;
+ // The local symbol index in the object.
+ unsigned int r_sym;
+ };
+
+ // The GOT section.
+ Output_data_got<size, big_endian>* got_;
+ // The PLT section.
+ Output_data_plt_tilegx<size, big_endian>* plt_;
+ // The GOT PLT section.
+ Output_data_space* got_plt_;
+ // The GOT section for IRELATIVE relocations.
+ Output_data_space* got_irelative_;
+ // The _GLOBAL_OFFSET_TABLE_ symbol.
+ Symbol* global_offset_table_;
+ // The _TILEGX_DYNAMIC_ symbol.
+ Symbol* tilegx_dynamic_;
+ // The dynamic reloc section.
+ Reloc_section* rela_dyn_;
+ // The section to use for IRELATIVE relocs.
+ Reloc_section* rela_irelative_;
+ // Relocs saved to avoid a COPY reloc.
+ Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
+ // Offset of the GOT entry for the TLS module index.
+ unsigned int got_mod_index_offset_;
+ // True if the _tls_get_addr symbol has been defined.
+ bool tls_get_addr_sym_defined_;
+};
+
+template<>
+const Target::Target_info Target_tilegx<64, false>::tilegx_info =
+{
+ 64, // size
+ false, // is_big_endian
+ elfcpp::EM_TILEGX, // 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.so.1", // program interpreter
+ 0x10000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // 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
+};
+
+template<>
+const Target::Target_info Target_tilegx<32, false>::tilegx_info =
+{
+ 32, // size
+ false, // is_big_endian
+ elfcpp::EM_TILEGX, // 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
+ "/lib32/ld.so.1", // program interpreter
+ 0x10000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // 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
+};
+
+template<>
+const Target::Target_info Target_tilegx<64, true>::tilegx_info =
+{
+ 64, // size
+ true, // is_big_endian
+ elfcpp::EM_TILEGX, // 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.so.1", // program interpreter
+ 0x10000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // 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
+};
+
+template<>
+const Target::Target_info Target_tilegx<32, true>::tilegx_info =
+{
+ 32, // size
+ true, // is_big_endian
+ elfcpp::EM_TILEGX, // 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
+ "/lib32/ld.so.1", // program interpreter
+ 0x10000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // 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
+};
+
+// tilegx relocation handlers
+template<int size, bool big_endian>
+class Tilegx_relocate_functions
+{
+public:
+ // overflow check will be supported later
+ typedef enum
+ {
+ STATUS_OKAY, // No error during relocation.
+ STATUS_OVERFLOW, // Relocation overflow.
+ STATUS_BAD_RELOC // Relocation cannot be applied.
+ } Status;
+
+ struct Tilegx_howto
+ {
+ // right shift operand by this number of bits.
+ unsigned char srshift;
+
+ // the offset to apply relocation.
+ unsigned char doffset;
+
+ // set to 1 for pc-relative relocation.
+ unsigned char is_pcrel;
+
+ // size in bits, or 0 if this table entry should be ignored.
+ unsigned char bsize;
+
+ // whether we need to check overflow.
+ unsigned char overflow;
+ };
+
+ static const Tilegx_howto howto[elfcpp::R_TILEGX_NUM];
+
+private:
+
+ // Do a simple rela relocation
+ template<int valsize>
+ static inline void
+ rela(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ elfcpp::Elf_Xword srshift, elfcpp::Elf_Xword doffset,
+ elfcpp::Elf_Xword bitmask)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ Valtype reloc = 0;
+ if (size == 32)
+ reloc = Bits<32>::sign_extend(psymval->value(object, addend)) >> srshift;
+ else
+ reloc = psymval->value(object, addend) >> srshift;
+
+ elfcpp::Elf_Xword dst_mask = bitmask << doffset;
+
+ val &= ~dst_mask;
+ reloc &= bitmask;
+
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, val | (reloc<<doffset));
+ }
+
+ // Do a simple rela relocation
+ template<int valsize>
+ static inline void
+ rela_ua(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ elfcpp::Elf_Xword srshift, elfcpp::Elf_Xword doffset,
+ elfcpp::Elf_Xword bitmask)
+ {
+ typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
+ Valtype;
+ unsigned char* wv = view;
+ Valtype val = elfcpp::Swap_unaligned<valsize, big_endian>::readval(wv);
+ Valtype reloc = 0;
+ if (size == 32)
+ reloc = Bits<32>::sign_extend(psymval->value(object, addend)) >> srshift;
+ else
+ reloc = psymval->value(object, addend) >> srshift;
+
+ elfcpp::Elf_Xword dst_mask = bitmask << doffset;
+
+ val &= ~dst_mask;
+ reloc &= bitmask;
+
+ elfcpp::Swap_unaligned<valsize, big_endian>::writeval(wv,
+ val | (reloc<<doffset));
+ }
+
+ template<int valsize>
+ static inline void
+ rela(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ elfcpp::Elf_Xword srshift, elfcpp::Elf_Xword doffset1,
+ elfcpp::Elf_Xword bitmask1, elfcpp::Elf_Xword doffset2,
+ elfcpp::Elf_Xword bitmask2)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ Valtype reloc = 0;
+ if (size == 32)
+ reloc = Bits<32>::sign_extend(psymval->value(object, addend)) >> srshift;
+ else
+ reloc = psymval->value(object, addend) >> srshift;
+
+ elfcpp::Elf_Xword dst_mask = (bitmask1 << doffset1)
+ | (bitmask2 << doffset2);
+ val &= ~dst_mask;
+ reloc = ((reloc & bitmask1) << doffset1)
+ | ((reloc & bitmask2) << doffset2);
+
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
+
+ }
+
+ // Do a simple PC relative relocation with a Symbol_value with the
+ // addend in the relocation.
+ template<int valsize>
+ static inline void
+ pcrela(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ elfcpp::Elf_Xword srshift, elfcpp::Elf_Xword doffset,
+ elfcpp::Elf_Xword bitmask)
+
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ Valtype reloc = 0;
+ if (size == 32)
+ reloc = Bits<32>::sign_extend(psymval->value(object, addend) - address)
+ >> srshift;
+ else
+ reloc = (psymval->value(object, addend) - address) >> srshift;
+
+ elfcpp::Elf_Xword dst_mask = bitmask << doffset;
+ val &= ~dst_mask;
+ reloc &= bitmask;
+
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, val | (reloc<<doffset));
+ }
+
+ template<int valsize>
+ static inline void
+ pcrela_ua(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ elfcpp::Elf_Xword srshift, elfcpp::Elf_Xword doffset,
+ elfcpp::Elf_Xword bitmask)
+
+ {
+ typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
+ Valtype;
+ unsigned char* wv = view;
+ Valtype reloc = 0;
+ if (size == 32)
+ reloc = Bits<32>::sign_extend(psymval->value(object, addend) - address)
+ >> srshift;
+ else
+ reloc = (psymval->value(object, addend) - address) >> srshift;
+
+ reloc &= bitmask;
+
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, reloc << doffset);
+ }
+
+ template<int valsize>
+ static inline void
+ pcrela(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ elfcpp::Elf_Xword srshift, elfcpp::Elf_Xword doffset1,
+ elfcpp::Elf_Xword bitmask1, elfcpp::Elf_Xword doffset2,
+ elfcpp::Elf_Xword bitmask2)
+
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ Valtype reloc = 0;
+ if (size == 32)
+ reloc = Bits<32>::sign_extend(psymval->value(object, addend) - address)
+ >> srshift;
+ else
+ reloc = (psymval->value(object, addend) - address) >> srshift;
+
+ elfcpp::Elf_Xword dst_mask = (bitmask1 << doffset1)
+ | (bitmask2 << doffset2);
+ val &= ~dst_mask;
+ reloc = ((reloc & bitmask1) << doffset1)
+ | ((reloc & bitmask2) << doffset2);
+
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
+ }
+
+ typedef Tilegx_relocate_functions<size, big_endian> This;
+ typedef Relocate_functions<size, big_endian> Base;
+
+public:
+
+ static inline void
+ abs64(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This::template rela_ua<64>(view, object, psymval, addend, 0, 0,
+ 0xffffffffffffffffllu);
+ }
+
+ static inline void
+ abs32(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This::template rela_ua<32>(view, object, psymval, addend, 0, 0,
+ 0xffffffff);
+ }
+
+ static inline void
+ abs16(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend)
+ {
+ This::template rela_ua<16>(view, object, psymval, addend, 0, 0,
+ 0xffff);
+ }
+
+ static inline void
+ pc_abs64(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This::template pcrela_ua<64>(view, object, psymval, addend, address, 0, 0,
+ 0xffffffffffffffffllu);
+ }
+
+ static inline void
+ pc_abs32(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This::template pcrela_ua<32>(view, object, psymval, addend, address, 0, 0,
+ 0xffffffff);
+ }
+
+ static inline void
+ pc_abs16(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ This::template pcrela_ua<16>(view, object, psymval, addend, address, 0, 0,
+ 0xffff);
+ }
+
+ static inline void
+ imm_x_general(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ Tilegx_howto &r_howto)
+ {
+ This::template rela<64>(view, object, psymval, addend,
+ (elfcpp::Elf_Xword)(r_howto.srshift),
+ (elfcpp::Elf_Xword)(r_howto.doffset),
+ (elfcpp::Elf_Xword)((1 << r_howto.bsize) - 1));
+ }
+
+ static inline void
+ imm_x_pcrel_general(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ Tilegx_howto &r_howto)
+ {
+ This::template pcrela<64>(view, object, psymval, addend, address,
+ (elfcpp::Elf_Xword)(r_howto.srshift),
+ (elfcpp::Elf_Xword)(r_howto.doffset),
+ (elfcpp::Elf_Xword)((1 << r_howto.bsize) - 1));
+ }
+
+ static inline void
+ imm_x_two_part_general(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr addend,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ unsigned int r_type)
+ {
+
+ elfcpp::Elf_Xword doffset1 = 0llu;
+ elfcpp::Elf_Xword doffset2 = 0llu;
+ elfcpp::Elf_Xword dmask1 = 0llu;
+ elfcpp::Elf_Xword dmask2 = 0llu;
+ elfcpp::Elf_Xword rshift = 0llu;
+ unsigned int pc_rel = 0;
+
+ switch (r_type)
+ {
+ case elfcpp::R_TILEGX_BROFF_X1:
+ doffset1 = 31llu;
+ doffset2 = 37llu;
+ dmask1 = 0x3fllu;
+ dmask2 = 0x1ffc0llu;
+ rshift = 3llu;
+ pc_rel = 1;
+ break;
+ case elfcpp::R_TILEGX_DEST_IMM8_X1:
+ doffset1 = 31llu;
+ doffset2 = 43llu;
+ dmask1 = 0x3fllu;
+ dmask2 = 0xc0llu;
+ rshift = 0llu;
+ break;
+ }
+
+ if (pc_rel)
+ This::template pcrela<64>(view, object, psymval, addend, address,
+ rshift, doffset1, dmask1, doffset2, dmask2);
+ else
+ This::template rela<64>(view, object, psymval, addend, rshift,
+ doffset1, dmask1, doffset2, dmask2);
+
+ }
+
+ static inline void
+ tls_relax(unsigned char* view, unsigned int r_type,
+ tls::Tls_optimization opt_t)
+ {
+
+ const uint64_t TILEGX_X_MOVE_R0_R0 = 0x283bf8005107f000llu;
+ const uint64_t TILEGX_Y_MOVE_R0_R0 = 0xae05f800540bf000llu;
+ const uint64_t TILEGX_X_LD = 0x286ae80000000000llu;
+ const uint64_t TILEGX_X_LD4S = 0x286a980000000000llu;
+ const uint64_t TILEGX_X1_FULL_MASK = 0x3fffffff80000000llu;
+ const uint64_t TILEGX_X0_RRR_MASK = 0x000000007ffc0000llu;
+ const uint64_t TILEGX_X1_RRR_MASK = 0x3ffe000000000000llu;
+ const uint64_t TILEGX_Y0_RRR_MASK = 0x00000000780c0000llu;
+ const uint64_t TILEGX_Y1_RRR_MASK = 0x3c06000000000000llu;
+ const uint64_t TILEGX_X0_RRR_SRCB_MASK = 0x000000007ffff000llu;
+ const uint64_t TILEGX_X1_RRR_SRCB_MASK = 0x3ffff80000000000llu;
+ const uint64_t TILEGX_Y0_RRR_SRCB_MASK = 0x00000000780ff000llu;
+ const uint64_t TILEGX_Y1_RRR_SRCB_MASK = 0x3c07f80000000000llu;
+ const uint64_t TILEGX_X_ADD_R0_R0_TP = 0x2807a800500f5000llu;
+ const uint64_t TILEGX_Y_ADD_R0_R0_TP = 0x9a13a8002c275000llu;
+ const uint64_t TILEGX_X_ADDX_R0_R0_TP = 0x2805a800500b5000llu;
+ const uint64_t TILEGX_Y_ADDX_R0_R0_TP = 0x9a01a8002c035000llu;
+
+ const uint64_t R_TILEGX_IMM8_X0_TLS_ADD_MASK =
+ (TILEGX_X0_RRR_MASK | (0x3Fllu << 12));
+
+ const uint64_t R_TILEGX_IMM8_X1_TLS_ADD_MASK =
+ (TILEGX_X1_RRR_MASK | (0x3Fllu << 43));
+
+ const uint64_t R_TILEGX_IMM8_Y0_TLS_ADD_MASK =
+ (TILEGX_Y0_RRR_MASK | (0x3Fllu << 12));
+
+ const uint64_t R_TILEGX_IMM8_Y1_TLS_ADD_MASK =
+ (TILEGX_Y1_RRR_MASK | (0x3Fllu << 43));
+
+ const uint64_t R_TILEGX_IMM8_X0_TLS_ADD_LE_MASK =
+ (TILEGX_X0_RRR_SRCB_MASK | (0x3Fllu << 6));
+
+ const uint64_t R_TILEGX_IMM8_X1_TLS_ADD_LE_MASK =
+ (TILEGX_X1_RRR_SRCB_MASK | (0x3Fllu << 37));
+
+ const uint64_t R_TILEGX_IMM8_Y0_TLS_ADD_LE_MASK =
+ (TILEGX_Y0_RRR_SRCB_MASK | (0x3Fllu << 6));
+
+ const uint64_t R_TILEGX_IMM8_Y1_TLS_ADD_LE_MASK =
+ (TILEGX_Y1_RRR_SRCB_MASK | (0x3Fllu << 37));
+
+ typedef typename elfcpp::Swap<64, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<64, big_endian>::readval(wv);
+ Valtype reloc = 0;
+
+ switch (r_type)
+ {
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
+ if (opt_t == tls::TLSOPT_NONE) {
+ // GD/IE: 1. copy dest operand into the second source operand
+ // 2. change the opcode to "add"
+ reloc = (val & 0x3Fllu) << 12; // featch the dest reg
+ reloc |= ((size == 32
+ ? TILEGX_X_ADDX_R0_R0_TP
+ : TILEGX_X_ADD_R0_R0_TP)
+ & TILEGX_X0_RRR_MASK); // change opcode
+ val &= ~R_TILEGX_IMM8_X0_TLS_ADD_MASK;
+ } else if (opt_t == tls::TLSOPT_TO_LE) {
+ // LE: 1. copy dest operand into the first source operand
+ // 2. change the opcode to "move"
+ reloc = (val & 0x3Fllu) << 6;
+ reloc |= (TILEGX_X_MOVE_R0_R0 & TILEGX_X0_RRR_SRCB_MASK);
+ val &= ~R_TILEGX_IMM8_X0_TLS_ADD_LE_MASK;
+ } else
+ gold_unreachable();
+ break;
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
+ if (opt_t == tls::TLSOPT_NONE) {
+ reloc = (val & (0x3Fllu << 31)) << 12;
+ reloc |= ((size == 32
+ ? TILEGX_X_ADDX_R0_R0_TP
+ : TILEGX_X_ADD_R0_R0_TP)
+ & TILEGX_X1_RRR_MASK);
+ val &= ~R_TILEGX_IMM8_X1_TLS_ADD_MASK;
+ } else if (opt_t == tls::TLSOPT_TO_LE) {
+ reloc = (val & (0x3Fllu << 31)) << 6;
+ reloc |= (TILEGX_X_MOVE_R0_R0 & TILEGX_X1_RRR_SRCB_MASK);
+ val &= ~R_TILEGX_IMM8_X1_TLS_ADD_LE_MASK;
+ } else
+ gold_unreachable();
+ break;
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
+ if (opt_t == tls::TLSOPT_NONE) {
+ reloc = (val & 0x3Fllu) << 12;
+ reloc |= ((size == 32
+ ? TILEGX_Y_ADDX_R0_R0_TP
+ : TILEGX_Y_ADD_R0_R0_TP)
+ & TILEGX_Y0_RRR_MASK);
+ val &= ~R_TILEGX_IMM8_Y0_TLS_ADD_MASK;
+ } else if (opt_t == tls::TLSOPT_TO_LE) {
+ reloc = (val & 0x3Fllu) << 6;
+ reloc |= (TILEGX_Y_MOVE_R0_R0 & TILEGX_Y0_RRR_SRCB_MASK);
+ val &= ~R_TILEGX_IMM8_Y0_TLS_ADD_LE_MASK;
+ } else
+ gold_unreachable();
+ break;
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
+ if (opt_t == tls::TLSOPT_NONE) {
+ reloc = (val & (0x3Fllu << 31)) << 12;
+ reloc |= ((size == 32
+ ? TILEGX_Y_ADDX_R0_R0_TP
+ : TILEGX_Y_ADD_R0_R0_TP)
+ & TILEGX_Y1_RRR_MASK);
+ val &= ~R_TILEGX_IMM8_Y1_TLS_ADD_MASK;
+ } else if (opt_t == tls::TLSOPT_TO_LE) {
+ reloc = (val & (0x3Fllu << 31)) << 6;
+ reloc |= (TILEGX_Y_MOVE_R0_R0 & TILEGX_Y1_RRR_SRCB_MASK);
+ val &= ~R_TILEGX_IMM8_Y1_TLS_ADD_LE_MASK;
+ } else
+ gold_unreachable();
+ break;
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
+ if (opt_t == tls::TLSOPT_NONE) {
+ // GD see comments for optimize_tls_reloc
+ reloc = TILEGX_X_MOVE_R0_R0 & TILEGX_X0_RRR_SRCB_MASK;
+ val &= ~TILEGX_X0_RRR_SRCB_MASK;
+ } else if (opt_t == tls::TLSOPT_TO_IE
+ || opt_t == tls::TLSOPT_TO_LE) {
+ // IE/LE
+ reloc = (size == 32
+ ? TILEGX_X_ADDX_R0_R0_TP
+ : TILEGX_X_ADD_R0_R0_TP)
+ & TILEGX_X0_RRR_SRCB_MASK;
+ val &= ~TILEGX_X0_RRR_SRCB_MASK;
+ }
+ break;
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
+ if (opt_t == tls::TLSOPT_NONE) {
+ reloc = TILEGX_X_MOVE_R0_R0 & TILEGX_X1_RRR_SRCB_MASK;
+ val &= ~TILEGX_X1_RRR_SRCB_MASK;
+ } else if (opt_t == tls::TLSOPT_TO_IE
+ || opt_t == tls::TLSOPT_TO_LE) {
+ reloc = (size == 32
+ ? TILEGX_X_ADDX_R0_R0_TP
+ : TILEGX_X_ADD_R0_R0_TP)
+ & TILEGX_X1_RRR_SRCB_MASK;
+ val &= ~TILEGX_X1_RRR_SRCB_MASK;
+ }
+ break;
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
+ if (opt_t == tls::TLSOPT_NONE) {
+ reloc = TILEGX_Y_MOVE_R0_R0 & TILEGX_Y0_RRR_SRCB_MASK;
+ val &= ~TILEGX_Y0_RRR_SRCB_MASK;
+ } else if (opt_t == tls::TLSOPT_TO_IE
+ || opt_t == tls::TLSOPT_TO_LE) {
+ reloc = (size == 32
+ ? TILEGX_Y_ADDX_R0_R0_TP
+ : TILEGX_Y_ADD_R0_R0_TP)
+ & TILEGX_Y0_RRR_SRCB_MASK;
+ val &= ~TILEGX_Y0_RRR_SRCB_MASK;
+ }
+ break;
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
+ if (opt_t == tls::TLSOPT_NONE) {
+ reloc = TILEGX_Y_MOVE_R0_R0 & TILEGX_Y1_RRR_SRCB_MASK;
+ val &= ~TILEGX_Y1_RRR_SRCB_MASK;
+ } else if (opt_t == tls::TLSOPT_TO_IE
+ || opt_t == tls::TLSOPT_TO_LE) {
+ reloc = (size == 32
+ ? TILEGX_Y_ADDX_R0_R0_TP
+ : TILEGX_Y_ADD_R0_R0_TP)
+ & TILEGX_Y1_RRR_SRCB_MASK;
+ val &= ~TILEGX_Y1_RRR_SRCB_MASK;
+ }
+ break;
+ case elfcpp::R_TILEGX_TLS_IE_LOAD:
+ if (opt_t == tls::TLSOPT_NONE) {
+ // IE
+ reloc = (size == 32
+ ? TILEGX_X_LD4S
+ : TILEGX_X_LD)
+ & TILEGX_X1_RRR_SRCB_MASK;
+ val &= ~TILEGX_X1_RRR_SRCB_MASK;
+ } else if (opt_t == tls::TLSOPT_TO_LE) {
+ // LE
+ reloc = TILEGX_X_MOVE_R0_R0 & TILEGX_X1_RRR_SRCB_MASK;
+ val &= ~TILEGX_X1_RRR_SRCB_MASK;
+ } else
+ gold_unreachable();
+ break;
+ case elfcpp::R_TILEGX_TLS_GD_CALL:
+ if (opt_t == tls::TLSOPT_TO_IE) {
+ // ld/ld4s r0, r0
+ reloc = (size == 32
+ ? TILEGX_X_LD4S
+ : TILEGX_X_LD) & TILEGX_X1_FULL_MASK;
+ val &= ~TILEGX_X1_FULL_MASK;
+ } else if (opt_t == tls::TLSOPT_TO_LE) {
+ // move r0, r0
+ reloc = TILEGX_X_MOVE_R0_R0 & TILEGX_X1_FULL_MASK;
+ val &= ~TILEGX_X1_FULL_MASK;
+ } else
+ // should be handled in ::relocate
+ gold_unreachable();
+ break;
+ default:
+ gold_unreachable();
+ break;
+ }
+ elfcpp::Swap<64, big_endian>::writeval(wv, val | reloc);
+ }
+};
+
+template<>
+const Tilegx_relocate_functions<64, false>::Tilegx_howto
+Tilegx_relocate_functions<64, false>::howto[elfcpp::R_TILEGX_NUM] =
+{
+ { 0, 0, 0, 0, 0}, // R_TILEGX_NONE
+ { 0, 0, 0, 64, 0}, // R_TILEGX_64
+ { 0, 0, 0, 32, 0}, // R_TILEGX_32
+ { 0, 0, 0, 16, 0}, // R_TILEGX_16
+ { 0, 0, 0, 8, 0}, // R_TILEGX_8
+ { 0, 0, 1, 64, 0}, // R_TILEGX_64_PCREL
+ { 0, 0, 1, 32, 0}, // R_TILEGX_32_PCREL
+ { 0, 0, 1, 16, 0}, // R_TILEGX_16_PCREL
+ { 0, 0, 1, 8, 0}, // R_TILEGX_8_PCREL
+ { 0, 0, 0, 0, 0}, // R_TILEGX_HW0
+ { 16, 0, 0, 0, 0}, // R_TILEGX_HW1
+ { 32, 0, 0, 0, 0}, // R_TILEGX_HW2
+ { 48, 0, 0, 0, 0}, // R_TILEGX_HW3
+ { 0, 0, 0, 0, 0}, // R_TILEGX_HW0_LAST
+ { 16, 0, 0, 0, 0}, // R_TILEGX_HW1_LAST
+ { 32, 0, 0, 0, 0}, // R_TILEGX_HW2_LAST
+ { 0, 0, 0, 0, 0}, // R_TILEGX_COPY
+ { 0, 0, 0, 8, 0}, // R_TILEGX_GLOB_DAT
+ { 0, 0, 0, 0, 0}, // R_TILEGX_JMP_SLOT
+ { 0, 0, 0, 0, 0}, // R_TILEGX_RELATIVE
+ { 3, 1, 1, 0, 0}, // R_TILEGX_BROFF_X1
+ { 3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1
+ { 3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1_PLT
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_Y0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_Y1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_DEST_IMM8_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MT_IMM14_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MF_IMM14_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MMSTART_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MMEND_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_Y0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_Y1
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0
+ { 16, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW1
+ { 16, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW1
+ { 32, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW2
+ { 32, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW2
+ { 48, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW3
+ { 48, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW3
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST
+ { 32, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST
+ { 32, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST
+ { 0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PCREL
+ { 0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PCREL
+ { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PCREL
+ { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PCREL
+ { 32, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PCREL
+ { 32, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PCREL
+ { 48, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW3_PCREL
+ { 48, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW3_PCREL
+ { 0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PCREL
+ { 0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PCREL
+ { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PCREL
+ { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PCREL
+ { 32, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PCREL
+ { 32, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PCREL
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_GOT
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_GOT
+ { 0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PLT_PCREL
+ { 0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PLT_PCREL
+ { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PLT_PCREL
+ { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PLT_PCREL
+ { 32, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PLT_PCREL
+ { 32, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PLT_PCREL
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_GOT
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_GOT
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_GOT
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_GOT
+ { 32, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_GOT
+ { 32, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_GOT
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_GD
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_GD
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_LE
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_LE
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IRELATIVE
+ { 0, 0, 0, 0, 0}, // R_TILEGX_INVALID
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_IE
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_IE
+ { 0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL
+ { 0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL
+ { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL
+ { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL
+ { 32, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL
+ { 32, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE
+ { 0, 0, 0, 0, 0}, // R_TILEGX_INVALID
+ { 0, 0, 0, 0, 0}, // R_TILEGX_INVALID
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPMOD64
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPOFF64
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_TPOFF64
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPMOD32
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPOFF32
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_TPOFF32
+ { 3, 31, 1, 27, 0}, // R_TILEGX_TLS_GD_CALL
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X0_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X1_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y0_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y1_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_IE_LOAD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X0_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X1_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y0_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y1_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_GNU_VTINHERIT
+ { 0, 0, 0, 0, 0}, // R_TILEGX_GNU_VTENTRY
+};
+
+template<>
+const Tilegx_relocate_functions<32, false>::Tilegx_howto
+Tilegx_relocate_functions<32, false>::howto[elfcpp::R_TILEGX_NUM] =
+{
+ { 0, 0, 0, 0, 0}, // R_TILEGX_NONE
+ { 0, 0, 0, 64, 0}, // R_TILEGX_64
+ { 0, 0, 0, 32, 0}, // R_TILEGX_32
+ { 0, 0, 0, 16, 0}, // R_TILEGX_16
+ { 0, 0, 0, 8, 0}, // R_TILEGX_8
+ { 0, 0, 1, 64, 0}, // R_TILEGX_64_PCREL
+ { 0, 0, 1, 32, 0}, // R_TILEGX_32_PCREL
+ { 0, 0, 1, 16, 0}, // R_TILEGX_16_PCREL
+ { 0, 0, 1, 8, 0}, // R_TILEGX_8_PCREL
+ { 0, 0, 0, 0, 0}, // R_TILEGX_HW0
+ { 16, 0, 0, 0, 0}, // R_TILEGX_HW1
+ { 31, 0, 0, 0, 0}, // R_TILEGX_HW2
+ { 31, 0, 0, 0, 0}, // R_TILEGX_HW3
+ { 0, 0, 0, 0, 0}, // R_TILEGX_HW0_LAST
+ { 16, 0, 0, 0, 0}, // R_TILEGX_HW1_LAST
+ { 31, 0, 0, 0, 0}, // R_TILEGX_HW2_LAST
+ { 0, 0, 0, 0, 0}, // R_TILEGX_COPY
+ { 0, 0, 0, 8, 0}, // R_TILEGX_GLOB_DAT
+ { 0, 0, 0, 0, 0}, // R_TILEGX_JMP_SLOT
+ { 0, 0, 0, 0, 0}, // R_TILEGX_RELATIVE
+ { 3, 1, 1, 0, 0}, // R_TILEGX_BROFF_X1
+ { 3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1
+ { 3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1_PLT
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_Y0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_Y1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_DEST_IMM8_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MT_IMM14_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MF_IMM14_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MMSTART_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MMEND_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_Y0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_Y1
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0
+ { 16, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW1
+ { 16, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW1
+ { 31, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW2
+ { 31, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW2
+ { 31, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW3
+ { 31, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW3
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST
+ { 31, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST
+ { 31, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST
+ { 0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PCREL
+ { 0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PCREL
+ { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PCREL
+ { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PCREL
+ { 31, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PCREL
+ { 31, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PCREL
+ { 31, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW3_PCREL
+ { 31, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW3_PCREL
+ { 0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PCREL
+ { 0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PCREL
+ { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PCREL
+ { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PCREL
+ { 31, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PCREL
+ { 31, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PCREL
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_GOT
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_GOT
+ { 0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PLT_PCREL
+ { 0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PLT_PCREL
+ { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PLT_PCREL
+ { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PLT_PCREL
+ { 31, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PLT_PCREL
+ { 31, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PLT_PCREL
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_GOT
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_GOT
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_GOT
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_GOT
+ { 31, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_GOT
+ { 31, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_GOT
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_GD
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_GD
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_LE
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_LE
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IRELATIVE
+ { 0, 0, 0, 0, 0}, // R_TILEGX_INVALID
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_IE
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_IE
+ { 0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL
+ { 0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL
+ { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL
+ { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL
+ { 31, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL
+ { 31, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE
+ { 0, 0, 0, 0, 0}, // R_TILEGX_INVALID
+ { 0, 0, 0, 0, 0}, // R_TILEGX_INVALID
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPMOD64
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPOFF64
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_TPOFF64
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPMOD32
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPOFF32
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_TPOFF32
+ { 3, 31, 1, 27, 0}, // R_TILEGX_TLS_GD_CALL
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X0_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X1_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y0_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y1_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_IE_LOAD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X0_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X1_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y0_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y1_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_GNU_VTINHERIT
+ { 0, 0, 0, 0, 0}, // R_TILEGX_GNU_VTENTRY
+};
+
+template<>
+const Tilegx_relocate_functions<64, true>::Tilegx_howto
+Tilegx_relocate_functions<64, true>::howto[elfcpp::R_TILEGX_NUM] =
+{
+ { 0, 0, 0, 0, 0}, // R_TILEGX_NONE
+ { 0, 0, 0, 64, 0}, // R_TILEGX_64
+ { 0, 0, 0, 32, 0}, // R_TILEGX_32
+ { 0, 0, 0, 16, 0}, // R_TILEGX_16
+ { 0, 0, 0, 8, 0}, // R_TILEGX_8
+ { 0, 0, 1, 64, 0}, // R_TILEGX_64_PCREL
+ { 0, 0, 1, 32, 0}, // R_TILEGX_32_PCREL
+ { 0, 0, 1, 16, 0}, // R_TILEGX_16_PCREL
+ { 0, 0, 1, 8, 0}, // R_TILEGX_8_PCREL
+ { 0, 0, 0, 0, 0}, // R_TILEGX_HW0
+ { 16, 0, 0, 0, 0}, // R_TILEGX_HW1
+ { 32, 0, 0, 0, 0}, // R_TILEGX_HW2
+ { 48, 0, 0, 0, 0}, // R_TILEGX_HW3
+ { 0, 0, 0, 0, 0}, // R_TILEGX_HW0_LAST
+ { 16, 0, 0, 0, 0}, // R_TILEGX_HW1_LAST
+ { 32, 0, 0, 0, 0}, // R_TILEGX_HW2_LAST
+ { 0, 0, 0, 0, 0}, // R_TILEGX_COPY
+ { 0, 0, 0, 8, 0}, // R_TILEGX_GLOB_DAT
+ { 0, 0, 0, 0, 0}, // R_TILEGX_JMP_SLOT
+ { 0, 0, 0, 0, 0}, // R_TILEGX_RELATIVE
+ { 3, 1, 1, 0, 0}, // R_TILEGX_BROFF_X1
+ { 3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1
+ { 3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1_PLT
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_Y0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_Y1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_DEST_IMM8_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MT_IMM14_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MF_IMM14_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MMSTART_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MMEND_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_Y0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_Y1
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0
+ { 16, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW1
+ { 16, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW1
+ { 32, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW2
+ { 32, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW2
+ { 48, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW3
+ { 48, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW3
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST
+ { 32, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST
+ { 32, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST
+ { 0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PCREL
+ { 0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PCREL
+ { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PCREL
+ { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PCREL
+ { 32, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PCREL
+ { 32, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PCREL
+ { 48, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW3_PCREL
+ { 48, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW3_PCREL
+ { 0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PCREL
+ { 0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PCREL
+ { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PCREL
+ { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PCREL
+ { 32, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PCREL
+ { 32, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PCREL
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_GOT
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_GOT
+ { 0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PLT_PCREL
+ { 0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PLT_PCREL
+ { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PLT_PCREL
+ { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PLT_PCREL
+ { 32, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PLT_PCREL
+ { 32, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PLT_PCREL
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_GOT
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_GOT
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_GOT
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_GOT
+ { 32, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_GOT
+ { 32, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_GOT
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_GD
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_GD
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_LE
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_LE
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IRELATIVE
+ { 0, 0, 0, 0, 0}, // R_TILEGX_INVALID
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_IE
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_IE
+ { 0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL
+ { 0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL
+ { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL
+ { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL
+ { 32, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL
+ { 32, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE
+ { 0, 0, 0, 0, 0}, // R_TILEGX_INVALID
+ { 0, 0, 0, 0, 0}, // R_TILEGX_INVALID
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPMOD64
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPOFF64
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_TPOFF64
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPMOD32
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPOFF32
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_TPOFF32
+ { 3, 31, 1, 27, 0}, // R_TILEGX_TLS_GD_CALL
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X0_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X1_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y0_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y1_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_IE_LOAD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X0_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X1_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y0_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y1_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_GNU_VTINHERIT
+ { 0, 0, 0, 0, 0}, // R_TILEGX_GNU_VTENTRY
+};
+
+template<>
+const Tilegx_relocate_functions<32, true>::Tilegx_howto
+Tilegx_relocate_functions<32, true>::howto[elfcpp::R_TILEGX_NUM] =
+{
+ { 0, 0, 0, 0, 0}, // R_TILEGX_NONE
+ { 0, 0, 0, 64, 0}, // R_TILEGX_64
+ { 0, 0, 0, 32, 0}, // R_TILEGX_32
+ { 0, 0, 0, 16, 0}, // R_TILEGX_16
+ { 0, 0, 0, 8, 0}, // R_TILEGX_8
+ { 0, 0, 1, 64, 0}, // R_TILEGX_64_PCREL
+ { 0, 0, 1, 32, 0}, // R_TILEGX_32_PCREL
+ { 0, 0, 1, 16, 0}, // R_TILEGX_16_PCREL
+ { 0, 0, 1, 8, 0}, // R_TILEGX_8_PCREL
+ { 0, 0, 0, 0, 0}, // R_TILEGX_HW0
+ { 16, 0, 0, 0, 0}, // R_TILEGX_HW1
+ { 31, 0, 0, 0, 0}, // R_TILEGX_HW2
+ { 31, 0, 0, 0, 0}, // R_TILEGX_HW3
+ { 0, 0, 0, 0, 0}, // R_TILEGX_HW0_LAST
+ { 16, 0, 0, 0, 0}, // R_TILEGX_HW1_LAST
+ { 31, 0, 0, 0, 0}, // R_TILEGX_HW2_LAST
+ { 0, 0, 0, 0, 0}, // R_TILEGX_COPY
+ { 0, 0, 0, 8, 0}, // R_TILEGX_GLOB_DAT
+ { 0, 0, 0, 0, 0}, // R_TILEGX_JMP_SLOT
+ { 0, 0, 0, 0, 0}, // R_TILEGX_RELATIVE
+ { 3, 1, 1, 0, 0}, // R_TILEGX_BROFF_X1
+ { 3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1
+ { 3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1_PLT
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_Y0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_IMM8_Y1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_DEST_IMM8_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MT_IMM14_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MF_IMM14_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MMSTART_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_MMEND_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_X0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_X1
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_Y0
+ { 0, 1, 0, 8, 0}, // R_TILEGX_SHAMT_Y1
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0
+ { 16, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW1
+ { 16, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW1
+ { 31, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW2
+ { 31, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW2
+ { 31, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW3
+ { 31, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW3
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST
+ { 31, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST
+ { 31, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST
+ { 0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PCREL
+ { 0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PCREL
+ { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PCREL
+ { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PCREL
+ { 31, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PCREL
+ { 31, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PCREL
+ { 31, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW3_PCREL
+ { 31, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW3_PCREL
+ { 0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PCREL
+ { 0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PCREL
+ { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PCREL
+ { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PCREL
+ { 31, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PCREL
+ { 31, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PCREL
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_GOT
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_GOT
+ { 0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PLT_PCREL
+ { 0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PLT_PCREL
+ { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PLT_PCREL
+ { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PLT_PCREL
+ { 31, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PLT_PCREL
+ { 31, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PLT_PCREL
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_GOT
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_GOT
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_GOT
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_GOT
+ { 31, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_GOT
+ { 31, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_GOT
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_GD
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_GD
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_LE
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_LE
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IRELATIVE
+ { 0, 0, 0, 0, 0}, // R_TILEGX_INVALID
+ { 0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_IE
+ { 0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_IE
+ { 0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL
+ { 0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL
+ { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL
+ { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL
+ { 31, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL
+ { 31, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL
+ { 0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE
+ { 0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE
+ { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE
+ { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE
+ { 0, 0, 0, 0, 0}, // R_TILEGX_INVALID
+ { 0, 0, 0, 0, 0}, // R_TILEGX_INVALID
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPMOD64
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPOFF64
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_TPOFF64
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPMOD32
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_DTPOFF32
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_TPOFF32
+ { 3, 31, 1, 27, 0}, // R_TILEGX_TLS_GD_CALL
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X0_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X1_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y0_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y1_TLS_GD_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_TLS_IE_LOAD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X0_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_X1_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y0_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_IMM8_Y1_TLS_ADD
+ { 0, 0, 0, 0, 0}, // R_TILEGX_GNU_VTINHERIT
+ { 0, 0, 0, 0, 0}, // R_TILEGX_GNU_VTENTRY
+};
+
+// Get the GOT section, creating it if necessary.
+
+template<int size, bool big_endian>
+Output_data_got<size, big_endian>*
+Target_tilegx<size, big_endian>::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.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);
+
+ this->got_ = new Output_data_got<size, big_endian>();
+
+ layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_, got_order, true);
+
+ // 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_,
+ 0, 0, elfcpp::STT_OBJECT,
+ elfcpp::STB_LOCAL,
+ elfcpp::STV_HIDDEN, 0,
+ false, false);
+
+ if (parameters->options().shared()) {
+ // we need to keep the address of .dynamic section in the
+ // first got entry for .so
+ this->tilegx_dynamic_ =
+ symtab->define_in_output_data("_TILEGX_DYNAMIC_", NULL,
+ Symbol_table::PREDEFINED,
+ layout->dynamic_section(),
+ 0, 0, elfcpp::STT_OBJECT,
+ elfcpp::STB_LOCAL,
+ elfcpp::STV_HIDDEN, 0,
+ false, false);
+
+ this->got_->add_global(this->tilegx_dynamic_, GOT_TYPE_STANDARD);
+ } else
+ // for executable, just set the first entry to zero.
+ this->got_->set_current_data_size(size / 8);
+
+ this->got_plt_ = new Output_data_space(size / 8, "** 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 two entries are reserved.
+ this->got_plt_->set_current_data_size
+ (TILEGX_GOTPLT_RESERVE_COUNT * (size / 8));
+
+ if (!is_got_plt_relro)
+ {
+ // Those bytes can go into the relro segment.
+ layout->increase_relro(size / 8);
+ }
+
+
+ // If there are any IRELATIVE relocations, they get GOT entries
+ // in .got.plt after the jump slot entries.
+ this->got_irelative_
+ = new Output_data_space(size / 8, "** 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);
+ }
+
+ return this->got_;
+}
+
+// Get the dynamic reloc section, creating it if necessary.
+
+template<int size, bool big_endian>
+typename Target_tilegx<size, big_endian>::Reloc_section*
+Target_tilegx<size, big_endian>::rela_dyn_section(Layout* layout)
+{
+ if (this->rela_dyn_ == NULL)
+ {
+ gold_assert(layout != NULL);
+ this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
+ layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
+ elfcpp::SHF_ALLOC, this->rela_dyn_,
+ ORDER_DYNAMIC_RELOCS, false);
+ }
+ return this->rela_dyn_;
+}
+
+// Get the section to use for IRELATIVE relocs, creating it if
+// necessary. These go in .rela.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.
+
+template<int size, bool big_endian>
+typename Target_tilegx<size, big_endian>::Reloc_section*
+Target_tilegx<size, big_endian>::rela_irelative_section(Layout* layout)
+{
+ if (this->rela_irelative_ == NULL)
+ {
+ // Make sure we have already created the dynamic reloc section.
+ this->rela_dyn_section(layout);
+ this->rela_irelative_ = new Reloc_section(false);
+ layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
+ elfcpp::SHF_ALLOC, this->rela_irelative_,
+ ORDER_DYNAMIC_RELOCS, false);
+ gold_assert(this->rela_dyn_->output_section()
+ == this->rela_irelative_->output_section());
+ }
+ return this->rela_irelative_;
+}
+
+// Initialize the PLT section.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_tilegx<size, big_endian>::init(Layout* layout)
+{
+ this->rel_ = new Reloc_section(false);
+ layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
+ elfcpp::SHF_ALLOC, this->rel_,
+ ORDER_DYNAMIC_PLT_RELOCS, false);
+}
+
+template<int size, bool big_endian>
+void
+Output_data_plt_tilegx<size, big_endian>::do_adjust_output_section(
+ Output_section* os)
+{
+ os->set_entsize(this->get_plt_entry_size());
+}
+
+// Add an entry to the PLT.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_tilegx<size, big_endian>::add_entry(Symbol_table* symtab,
+ Layout* layout, Symbol* gsym)
+{
+ gold_assert(!gsym->has_plt_offset());
+
+ unsigned int plt_index;
+ off_t plt_offset;
+ section_offset_type got_offset;
+
+ unsigned int* pcount;
+ unsigned int reserved;
+ Output_data_space* got;
+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
+ && gsym->can_use_relative_reloc(false))
+ {
+ pcount = &this->irelative_count_;
+ reserved = 0;
+ got = this->got_irelative_;
+ }
+ else
+ {
+ pcount = &this->count_;
+ reserved = TILEGX_GOTPLT_RESERVE_COUNT;
+ got = this->got_plt_;
+ }
+
+ if (!this->is_data_size_valid())
+ {
+ plt_index = *pcount;
+
+ // TILEGX .plt section layout
+ //
+ // ----
+ // plt_header
+ // ----
+ // plt stub
+ // ----
+ // ...
+ // ----
+ //
+ // TILEGX .got.plt section layout
+ //
+ // ----
+ // reserv1
+ // ----
+ // reserv2
+ // ----
+ // entries for normal function
+ // ----
+ // ...
+ // ----
+ // entries for ifunc
+ // ----
+ // ...
+ // ----
+ if (got == this->got_irelative_)
+ plt_offset = plt_index * this->get_plt_entry_size();
+ else
+ plt_offset = (plt_index + 1) * this->get_plt_entry_size();
+
+ ++*pcount;
+
+ got_offset = (plt_index + reserved) * (size / 8);
+ gold_assert(got_offset == got->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).
+ got->set_current_data_size(got_offset + size / 8);
+ }
+ else
+ {
+ // FIXME: This is probably not correct for IRELATIVE relocs.
+
+ // For incremental updates, find an available slot.
+ plt_offset = this->free_list_.allocate(this->get_plt_entry_size(),
+ this->get_plt_entry_size(), 0);
+ if (plt_offset == -1)
+ gold_fallback(_("out of patch space (PLT);"
+ " relink with --incremental-full"));
+
+ // The GOT and PLT entries have a 1-1 correspondance, so the GOT offset
+ // can be calculated from the PLT index, adjusting for the three
+ // reserved entries at the beginning of the GOT.
+ plt_index = plt_offset / this->get_plt_entry_size() - 1;
+ got_offset = (plt_index + reserved) * (size / 8);
+ }
+
+ gsym->set_plt_offset(plt_offset);
+
+ // Every PLT entry needs a reloc.
+ this->add_relocation(symtab, layout, gsym, 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.
+
+template<int size, bool big_endian>
+unsigned int
+Output_data_plt_tilegx<size, big_endian>::add_local_ifunc_entry(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* 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 + size / 8);
+
+ // Every PLT entry needs a reloc.
+ Reloc_section* rela = this->rela_irelative(symtab, layout);
+ rela->add_symbolless_local_addend(relobj, local_sym_index,
+ elfcpp::R_TILEGX_IRELATIVE,
+ this->got_irelative_, got_offset, 0);
+
+ return plt_offset;
+}
+
+// Add the relocation for a PLT entry.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_tilegx<size, big_endian>::add_relocation(Symbol_table* symtab,
+ Layout* layout,
+ Symbol* gsym,
+ unsigned int got_offset)
+{
+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
+ && gsym->can_use_relative_reloc(false))
+ {
+ Reloc_section* rela = this->rela_irelative(symtab, layout);
+ rela->add_symbolless_global_addend(gsym, elfcpp::R_TILEGX_IRELATIVE,
+ this->got_irelative_, got_offset, 0);
+ }
+ else
+ {
+ gsym->set_needs_dynsym_entry();
+ this->rel_->add_global(gsym, elfcpp::R_TILEGX_JMP_SLOT, this->got_plt_,
+ got_offset, 0);
+ }
+}
+
+// Return where the IRELATIVE relocations should go in the PLT. These
+// follow the JUMP_SLOT and the TLSDESC relocations.
+
+template<int size, bool big_endian>
+typename Output_data_plt_tilegx<size, big_endian>::Reloc_section*
+Output_data_plt_tilegx<size, big_endian>::rela_irelative(Symbol_table* symtab,
+ Layout* layout)
+{
+ if (this->irelative_rel_ == NULL)
+ {
+ // case we see any later on.
+ this->irelative_rel_ = new Reloc_section(false);
+ layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
+ 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 .rela.plt
+ // section to hold R_TILEGX_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("__rela_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("__rela_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.
+
+template<int size, bool big_endian>
+uint64_t
+Output_data_plt_tilegx<size, big_endian>::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.
+
+template<int size, bool big_endian>
+uint64_t
+Output_data_plt_tilegx<size, big_endian>::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));
+}
+
+// Set the final size.
+template<int size, bool big_endian>
+void
+Output_data_plt_tilegx<size, big_endian>::set_final_data_size()
+{
+ unsigned int count = this->count_ + this->irelative_count_;
+ this->set_data_size((count + 1) * this->get_plt_entry_size());
+}
+
+// The first entry in the PLT for an executable.
+template<>
+const unsigned char
+Output_data_plt_tilegx<64, false>::first_plt_entry[plt_entry_size] =
+{
+ 0x00, 0x30, 0x48, 0x51,
+ 0x6e, 0x43, 0xa0, 0x18, // { ld_add r28, r27, 8 }
+ 0x00, 0x30, 0xbc, 0x35,
+ 0x00, 0x40, 0xde, 0x9e, // { ld r27, r27 }
+ 0xff, 0xaf, 0x30, 0x40,
+ 0x60, 0x73, 0x6a, 0x28, // { info 10 ; jr r27 }
+ // padding
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+template<>
+const unsigned char
+Output_data_plt_tilegx<32, false>::first_plt_entry[plt_entry_size] =
+{
+ 0x00, 0x30, 0x48, 0x51,
+ 0x6e, 0x23, 0x58, 0x18, // { ld4s_add r28, r27, 4 }
+ 0x00, 0x30, 0xbc, 0x35,
+ 0x00, 0x40, 0xde, 0x9c, // { ld4s r27, r27 }
+ 0xff, 0xaf, 0x30, 0x40,
+ 0x60, 0x73, 0x6a, 0x28, // { info 10 ; jr r27 }
+ // padding
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+template<>
+const unsigned char
+Output_data_plt_tilegx<64, true>::first_plt_entry[plt_entry_size] =
+{
+ 0x00, 0x30, 0x48, 0x51,
+ 0x6e, 0x43, 0xa0, 0x18, // { ld_add r28, r27, 8 }
+ 0x00, 0x30, 0xbc, 0x35,
+ 0x00, 0x40, 0xde, 0x9e, // { ld r27, r27 }
+ 0xff, 0xaf, 0x30, 0x40,
+ 0x60, 0x73, 0x6a, 0x28, // { info 10 ; jr r27 }
+ // padding
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+template<>
+const unsigned char
+Output_data_plt_tilegx<32, true>::first_plt_entry[plt_entry_size] =
+{
+ 0x00, 0x30, 0x48, 0x51,
+ 0x6e, 0x23, 0x58, 0x18, // { ld4s_add r28, r27, 4 }
+ 0x00, 0x30, 0xbc, 0x35,
+ 0x00, 0x40, 0xde, 0x9c, // { ld4s r27, r27 }
+ 0xff, 0xaf, 0x30, 0x40,
+ 0x60, 0x73, 0x6a, 0x28, // { info 10 ; jr r27 }
+ // padding
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+template<int size, bool big_endian>
+void
+Output_data_plt_tilegx<size, big_endian>::fill_first_plt_entry(
+ unsigned char* pov)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+}
+
+// Subsequent entries in the PLT for an executable.
+
+template<>
+const unsigned char
+Output_data_plt_tilegx<64, false>::plt_entry[plt_entry_size] =
+{
+ 0xdc, 0x0f, 0x00, 0x10,
+ 0x0d, 0xf0, 0x6a, 0x28, // { moveli r28, 0 ; lnk r26 }
+ 0xdb, 0x0f, 0x00, 0x10,
+ 0x8e, 0x03, 0x00, 0x38, // { moveli r27, 0 ; shl16insli r28, r28, 0 }
+ 0x9c, 0xc6, 0x0d, 0xd0,
+ 0x6d, 0x03, 0x00, 0x38, // { add r28, r26, r28 ; shl16insli r27, r27, 0 }
+ 0x9b, 0xb6, 0xc5, 0xad,
+ 0xff, 0x57, 0xe0, 0x8e, // { add r27, r26, r27 ; info 10 ; ld r28, r28 }
+ 0xdd, 0x0f, 0x00, 0x70,
+ 0x80, 0x73, 0x6a, 0x28, // { shl16insli r29, zero, 0 ; jr r28 }
+
+};
+
+template<>
+const unsigned char
+Output_data_plt_tilegx<32, false>::plt_entry[plt_entry_size] =
+{
+ 0xdc, 0x0f, 0x00, 0x10,
+ 0x0d, 0xf0, 0x6a, 0x28, // { moveli r28, 0 ; lnk r26 }
+ 0xdb, 0x0f, 0x00, 0x10,
+ 0x8e, 0x03, 0x00, 0x38, // { moveli r27, 0 ; shl16insli r28, r28, 0 }
+ 0x9c, 0xc6, 0x0d, 0xd0,
+ 0x6d, 0x03, 0x00, 0x38, // { add r28, r26, r28 ; shl16insli r27, r27, 0 }
+ 0x9b, 0xb6, 0xc5, 0xad,
+ 0xff, 0x57, 0xe0, 0x8c, // { add r27, r26, r27 ; info 10 ; ld4s r28, r28 }
+ 0xdd, 0x0f, 0x00, 0x70,
+ 0x80, 0x73, 0x6a, 0x28, // { shl16insli r29, zero, 0 ; jr r28 }
+};
+
+template<>
+const unsigned char
+Output_data_plt_tilegx<64, true>::plt_entry[plt_entry_size] =
+{
+ 0xdc, 0x0f, 0x00, 0x10,
+ 0x0d, 0xf0, 0x6a, 0x28, // { moveli r28, 0 ; lnk r26 }
+ 0xdb, 0x0f, 0x00, 0x10,
+ 0x8e, 0x03, 0x00, 0x38, // { moveli r27, 0 ; shl16insli r28, r28, 0 }
+ 0x9c, 0xc6, 0x0d, 0xd0,
+ 0x6d, 0x03, 0x00, 0x38, // { add r28, r26, r28 ; shl16insli r27, r27, 0 }
+ 0x9b, 0xb6, 0xc5, 0xad,
+ 0xff, 0x57, 0xe0, 0x8e, // { add r27, r26, r27 ; info 10 ; ld r28, r28 }
+ 0xdd, 0x0f, 0x00, 0x70,
+ 0x80, 0x73, 0x6a, 0x28, // { shl16insli r29, zero, 0 ; jr r28 }
+
+};
+
+template<>
+const unsigned char
+Output_data_plt_tilegx<32, true>::plt_entry[plt_entry_size] =
+{
+ 0xdc, 0x0f, 0x00, 0x10,
+ 0x0d, 0xf0, 0x6a, 0x28, // { moveli r28, 0 ; lnk r26 }
+ 0xdb, 0x0f, 0x00, 0x10,
+ 0x8e, 0x03, 0x00, 0x38, // { moveli r27, 0 ; shl16insli r28, r28, 0 }
+ 0x9c, 0xc6, 0x0d, 0xd0,
+ 0x6d, 0x03, 0x00, 0x38, // { add r28, r26, r28 ; shl16insli r27, r27, 0 }
+ 0x9b, 0xb6, 0xc5, 0xad,
+ 0xff, 0x57, 0xe0, 0x8c, // { add r27, r26, r27 ; info 10 ; ld4s r28, r28 }
+ 0xdd, 0x0f, 0x00, 0x70,
+ 0x80, 0x73, 0x6a, 0x28, // { shl16insli r29, zero, 0 ; jr r28 }
+};
+
+template<int size, bool big_endian>
+void
+Output_data_plt_tilegx<size, big_endian>::fill_plt_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr gotplt_base,
+ unsigned int got_offset,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_base,
+ unsigned int plt_offset, unsigned int plt_index)
+{
+
+ const uint32_t TILEGX_IMM16_MASK = 0xFFFF;
+ const uint32_t TILEGX_X0_IMM16_BITOFF = 12;
+ const uint32_t TILEGX_X1_IMM16_BITOFF = 43;
+
+ typedef typename elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::Valtype
+ Valtype;
+ memcpy(pov, plt_entry, plt_entry_size);
+
+ // first bundle in plt stub - x0
+ Valtype* wv = reinterpret_cast<Valtype*>(pov);
+ Valtype val = elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::readval(wv);
+ Valtype reloc =
+ ((gotplt_base + got_offset) - (plt_base + plt_offset + 8)) >> 16;
+ elfcpp::Elf_Xword dst_mask =
+ (elfcpp::Elf_Xword)(TILEGX_IMM16_MASK) << TILEGX_X0_IMM16_BITOFF;
+ val &= ~dst_mask;
+ reloc &= TILEGX_IMM16_MASK;
+ elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::writeval(wv,
+ val | (reloc<<TILEGX_X0_IMM16_BITOFF));
+
+ // second bundle in plt stub - x1
+ wv = reinterpret_cast<Valtype*>(pov + 8);
+ val = elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::readval(wv);
+ reloc = (gotplt_base + got_offset) - (plt_base + plt_offset + 8);
+ dst_mask = (elfcpp::Elf_Xword)(TILEGX_IMM16_MASK) << TILEGX_X1_IMM16_BITOFF;
+ val &= ~dst_mask;
+ reloc &= TILEGX_IMM16_MASK;
+ elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::writeval(wv,
+ val | (reloc<<TILEGX_X1_IMM16_BITOFF));
+
+ // second bundle in plt stub - x0
+ wv = reinterpret_cast<Valtype*>(pov + 8);
+ val = elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::readval(wv);
+ reloc = (gotplt_base - (plt_base + plt_offset + 8)) >> 16;
+ dst_mask = (elfcpp::Elf_Xword)(TILEGX_IMM16_MASK) << TILEGX_X0_IMM16_BITOFF;
+ val &= ~dst_mask;
+ reloc &= TILEGX_IMM16_MASK;
+ elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::writeval(wv,
+ val | (reloc<<TILEGX_X0_IMM16_BITOFF));
+
+ // third bundle in plt stub - x1
+ wv = reinterpret_cast<Valtype*>(pov + 16);
+ val = elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::readval(wv);
+ reloc = gotplt_base - (plt_base + plt_offset + 8);
+ dst_mask = (elfcpp::Elf_Xword)(TILEGX_IMM16_MASK) << TILEGX_X1_IMM16_BITOFF;
+ val &= ~dst_mask;
+ reloc &= TILEGX_IMM16_MASK;
+ elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::writeval(wv,
+ val | (reloc<<TILEGX_X1_IMM16_BITOFF));
+
+ // fifth bundle in plt stub - carry plt_index x0
+ wv = reinterpret_cast<Valtype*>(pov + 32);
+ val = elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::readval(wv);
+ dst_mask = (elfcpp::Elf_Xword)(TILEGX_IMM16_MASK) << TILEGX_X0_IMM16_BITOFF;
+ val &= ~dst_mask;
+ plt_index &= TILEGX_IMM16_MASK;
+ elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::writeval(wv,
+ val | (plt_index<<TILEGX_X0_IMM16_BITOFF));
+
+}
+
+// Write out the PLT. This uses the hand-coded instructions above.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_tilegx<size, big_endian>::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;
+
+ // The base address of the .plt section.
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address = this->address();
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address =
+ this->got_plt_->address();
+
+ this->fill_first_plt_entry(pov);
+ pov += this->get_plt_entry_size();
+
+ unsigned char* got_pov = got_view;
+
+ // first entry of .got.plt are set to -1
+ // second entry of .got.plt are set to 0
+ memset(got_pov, 0xff, size / 8);
+ got_pov += size / 8;
+ memset(got_pov, 0x0, size / 8);
+ got_pov += size / 8;
+
+ unsigned int plt_offset = this->get_plt_entry_size();
+ const unsigned int count = this->count_ + this->irelative_count_;
+ unsigned int got_offset = (size / 8) * TILEGX_GOTPLT_RESERVE_COUNT;
+ for (unsigned int plt_index = 0;
+ plt_index < count;
+ ++plt_index,
+ pov += this->get_plt_entry_size(),
+ got_pov += size / 8,
+ plt_offset += this->get_plt_entry_size(),
+ got_offset += size / 8)
+ {
+ // Set and adjust the PLT entry itself.
+ this->fill_plt_entry(pov, got_address, got_offset,
+ plt_address, plt_offset, plt_index);
+
+ // Initialize entry in .got.plt to plt start address
+ elfcpp::Swap<size, big_endian>::writeval(got_pov, plt_address);
+ }
+
+ gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
+ gold_assert(static_cast<section_size_type>(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.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::make_plt_section(Symbol_table* symtab,
+ Layout* layout)
+{
+ if (this->plt_ == NULL)
+ {
+ // Create the GOT sections first.
+ this->got_section(symtab, layout);
+
+ // Ensure that .rela.dyn always appears before .rela.plt,
+ // becuase on TILE-Gx, .rela.dyn needs to include .rela.plt
+ // in it's range.
+ this->rela_dyn_section(layout);
+
+ this->plt_ = new Output_data_plt_tilegx<size, big_endian>(layout,
+ TILEGX_INST_BUNDLE_SIZE, this->got_, this->got_plt_,
+ this->got_irelative_);
+
+ layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_EXECINSTR),
+ this->plt_, ORDER_NON_RELRO_FIRST,
+ false);
+
+ // Make the sh_info field of .rela.plt point to .plt.
+ Output_section* rela_plt_os = this->plt_->rela_plt()->output_section();
+ rela_plt_os->set_info_section(this->plt_->output_section());
+ }
+}
+
+// Create a PLT entry for a global symbol.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::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.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::make_local_ifunc_plt_entry(
+ Symbol_table* symtab, Layout* layout,
+ Sized_relobj_file<size, big_endian>* 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.
+
+template<int size, bool big_endian>
+unsigned int
+Target_tilegx<size, big_endian>::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<int size, bool big_endian>
+unsigned int
+Target_tilegx<size, big_endian>::first_plt_entry_offset() const
+{
+ return this->plt_->first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_tilegx<size, big_endian>::plt_entry_size() const
+{
+ return this->plt_->get_plt_entry_size();
+}
+
+// Create the GOT and PLT sections for an incremental update.
+
+template<int size, bool big_endian>
+Output_data_got_base*
+Target_tilegx<size, big_endian>::init_got_plt_for_update(Symbol_table* symtab,
+ Layout* layout,
+ unsigned int got_count,
+ unsigned int plt_count)
+{
+ gold_assert(this->got_ == NULL);
+
+ this->got_ =
+ new Output_data_got<size, big_endian>((got_count
+ + TILEGX_GOT_RESERVE_COUNT)
+ * (size / 8));
+ layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_, ORDER_RELRO_LAST,
+ true);
+
+ // Define _GLOBAL_OFFSET_TABLE_ at the start of the GOT.
+ this->global_offset_table_ =
+ symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
+ Symbol_table::PREDEFINED,
+ this->got_,
+ 0, 0, elfcpp::STT_OBJECT,
+ elfcpp::STB_LOCAL,
+ elfcpp::STV_HIDDEN, 0,
+ false, false);
+
+ if (parameters->options().shared()) {
+ this->tilegx_dynamic_ =
+ symtab->define_in_output_data("_TILEGX_DYNAMIC_", NULL,
+ Symbol_table::PREDEFINED,
+ layout->dynamic_section(),
+ 0, 0, elfcpp::STT_OBJECT,
+ elfcpp::STB_LOCAL,
+ elfcpp::STV_HIDDEN, 0,
+ false, false);
+
+ this->got_->add_global(this->tilegx_dynamic_, GOT_TYPE_STANDARD);
+ } else
+ this->got_->set_current_data_size(size / 8);
+
+ // Add the two reserved entries.
+ this->got_plt_
+ = new Output_data_space((plt_count + TILEGX_GOTPLT_RESERVE_COUNT)
+ * (size / 8), size / 8, "** GOT PLT");
+ layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_plt_, ORDER_NON_RELRO_FIRST,
+ false);
+
+ // If there are any IRELATIVE relocations, they get GOT entries in
+ // .got.plt after the jump slot.
+ this->got_irelative_
+ = new Output_data_space(0, size / 8, "** GOT IRELATIVE PLT");
+ layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+ this->got_irelative_,
+ ORDER_NON_RELRO_FIRST, false);
+
+ // Create the PLT section.
+ this->plt_ = new Output_data_plt_tilegx<size, big_endian>(layout,
+ this->plt_entry_size(), this->got_, this->got_plt_, this->got_irelative_,
+ plt_count);
+
+ 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 .rela.plt point to .plt.
+ Output_section* rela_plt_os = this->plt_->rela_plt()->output_section();
+ rela_plt_os->set_info_section(this->plt_->output_section());
+
+ // Create the rela_dyn section.
+ this->rela_dyn_section(layout);
+
+ return this->got_;
+}
+
+// Reserve a GOT entry for a local symbol, and regenerate any
+// necessary dynamic relocations.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::reserve_local_got_entry(
+ unsigned int got_index,
+ Sized_relobj<size, big_endian>* obj,
+ unsigned int r_sym,
+ unsigned int got_type)
+{
+ unsigned int got_offset = (got_index + TILEGX_GOT_RESERVE_COUNT)
+ * (size / 8);
+ Reloc_section* rela_dyn = this->rela_dyn_section(NULL);
+
+ this->got_->reserve_local(got_index, obj, r_sym, got_type);
+ switch (got_type)
+ {
+ case GOT_TYPE_STANDARD:
+ if (parameters->options().output_is_position_independent())
+ rela_dyn->add_local_relative(obj, r_sym, elfcpp::R_TILEGX_RELATIVE,
+ this->got_, got_offset, 0, false);
+ break;
+ case GOT_TYPE_TLS_OFFSET:
+ rela_dyn->add_local(obj, r_sym,
+ size == 32 ? elfcpp::R_TILEGX_TLS_DTPOFF32
+ : elfcpp::R_TILEGX_TLS_DTPOFF64,
+ this->got_, got_offset, 0);
+ break;
+ case GOT_TYPE_TLS_PAIR:
+ this->got_->reserve_slot(got_index + 1);
+ rela_dyn->add_local(obj, r_sym,
+ size == 32 ? elfcpp::R_TILEGX_TLS_DTPMOD32
+ : elfcpp::R_TILEGX_TLS_DTPMOD64,
+ this->got_, got_offset, 0);
+ break;
+ case GOT_TYPE_TLS_DESC:
+ gold_fatal(_("TLS_DESC not yet supported for incremental linking"));
+ break;
+ default:
+ gold_unreachable();
+ }
+}
+
+// Reserve a GOT entry for a global symbol, and regenerate any
+// necessary dynamic relocations.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::reserve_global_got_entry(
+ unsigned int got_index, Symbol* gsym, unsigned int got_type)
+{
+ unsigned int got_offset = (got_index + TILEGX_GOT_RESERVE_COUNT)
+ * (size / 8);
+ Reloc_section* rela_dyn = this->rela_dyn_section(NULL);
+
+ this->got_->reserve_global(got_index, gsym, got_type);
+ switch (got_type)
+ {
+ case GOT_TYPE_STANDARD:
+ if (!gsym->final_value_is_known())
+ {
+ if (gsym->is_from_dynobj()
+ || gsym->is_undefined()
+ || gsym->is_preemptible()
+ || gsym->type() == elfcpp::STT_GNU_IFUNC)
+ rela_dyn->add_global(gsym, elfcpp::R_TILEGX_GLOB_DAT,
+ this->got_, got_offset, 0);
+ else
+ rela_dyn->add_global_relative(gsym, elfcpp::R_TILEGX_RELATIVE,
+ this->got_, got_offset, 0, false);
+ }
+ break;
+ case GOT_TYPE_TLS_OFFSET:
+ rela_dyn->add_global_relative(gsym,
+ size == 32 ? elfcpp::R_TILEGX_TLS_TPOFF32
+ : elfcpp::R_TILEGX_TLS_TPOFF64,
+ this->got_, got_offset, 0, false);
+ break;
+ case GOT_TYPE_TLS_PAIR:
+ this->got_->reserve_slot(got_index + 1);
+ rela_dyn->add_global_relative(gsym,
+ size == 32 ? elfcpp::R_TILEGX_TLS_DTPMOD32
+ : elfcpp::R_TILEGX_TLS_DTPMOD64,
+ this->got_, got_offset, 0, false);
+ rela_dyn->add_global_relative(gsym,
+ size == 32 ? elfcpp::R_TILEGX_TLS_DTPOFF32
+ : elfcpp::R_TILEGX_TLS_DTPOFF64,
+ this->got_, got_offset + size / 8,
+ 0, false);
+ break;
+ case GOT_TYPE_TLS_DESC:
+ gold_fatal(_("TLS_DESC not yet supported for TILEGX"));
+ break;
+ default:
+ gold_unreachable();
+ }
+}
+
+// Register an existing PLT entry for a global symbol.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::register_global_plt_entry(
+ Symbol_table* symtab, Layout* layout, unsigned int plt_index, Symbol* gsym)
+{
+ gold_assert(this->plt_ != NULL);
+ gold_assert(!gsym->has_plt_offset());
+
+ this->plt_->reserve_slot(plt_index);
+
+ gsym->set_plt_offset((plt_index + 1) * this->plt_entry_size());
+
+ unsigned int got_offset = (plt_index + 2) * (size / 8);
+ this->plt_->add_relocation(symtab, layout, gsym, got_offset);
+}
+
+// Force a COPY relocation for a given symbol.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::emit_copy_reloc(
+ Symbol_table* symtab, Symbol* sym, Output_section* os, off_t offset)
+{
+ this->copy_relocs_.emit_copy_reloc(symtab,
+ symtab->get_sized_symbol<size>(sym),
+ os,
+ offset,
+ this->rela_dyn_section(NULL));
+}
+
+// Create a GOT entry for the TLS module index.
+
+template<int size, bool big_endian>
+unsigned int
+Target_tilegx<size, big_endian>::got_mod_index_entry(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object)
+{
+ if (this->got_mod_index_offset_ == -1U)
+ {
+ gold_assert(symtab != NULL && layout != NULL && object != NULL);
+ Reloc_section* rela_dyn = this->rela_dyn_section(layout);
+ Output_data_got<size, big_endian>* got
+ = this->got_section(symtab, layout);
+ unsigned int got_offset = got->add_constant(0);
+ rela_dyn->add_local(object, 0,
+ size == 32 ? elfcpp::R_TILEGX_TLS_DTPMOD32
+ : elfcpp::R_TILEGX_TLS_DTPMOD64, got,
+ got_offset, 0);
+ 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.
+//
+// the transformation rules is described below:
+//
+// compiler GD reference
+// |
+// V
+// moveli tmp, hw1_last_tls_gd(x) X0/X1
+// shl16insli r0, tmp, hw0_tls_gd(x) X0/X1
+// addi r0, got, tls_add(x) Y0/Y1/X0/X1
+// jal tls_gd_call(x) X1
+// addi adr, r0, tls_gd_add(x) Y0/Y1/X0/X1
+//
+// linker tranformation of GD insn sequence
+// |
+// V
+// ==> GD:
+// moveli tmp, hw1_last_tls_gd(x) X0/X1
+// shl16insli r0, tmp, hw0_tls_gd(x) X0/X1
+// add r0, got, r0 Y0/Y1/X0/X1
+// jal plt(__tls_get_addr) X1
+// move adr, r0 Y0/Y1/X0/X1
+// ==> IE:
+// moveli tmp, hw1_last_tls_ie(x) X0/X1
+// shl16insli r0, tmp, hw0_tls_ie(x) X0/X1
+// add r0, got, r0 Y0/Y1/X0/X1
+// ld r0, r0 X1
+// add adr, r0, tp Y0/Y1/X0/X1
+// ==> LE:
+// moveli tmp, hw1_last_tls_le(x) X0/X1
+// shl16insli r0, tmp, hw0_tls_le(x) X0/X1
+// move r0, r0 Y0/Y1/X0/X1
+// move r0, r0 Y0/Y1/X0/X1
+// add adr, r0, tp Y0/Y1/X0/X1
+//
+//
+// compiler IE reference
+// |
+// V
+// moveli tmp, hw1_last_tls_ie(x) X0/X1
+// shl16insli tmp, tmp, hw0_tls_ie(x) X0/X1
+// addi tmp, got, tls_add(x) Y0/Y1/X0/X1
+// ld_tls tmp, tmp, tls_ie_load(x) X1
+// add adr, tmp, tp Y0/Y1/X0/X1
+//
+// linker transformation for IE insn sequence
+// |
+// V
+// ==> IE:
+// moveli tmp, hw1_last_tls_ie(x) X0/X1
+// shl16insli tmp, tmp, hw0_tls_ie(x) X0/X1
+// add tmp, got, tmp Y0/Y1/X0/X1
+// ld tmp, tmp X1
+// add adr, tmp, tp Y0/Y1/X0/X1
+// ==> LE:
+// moveli tmp, hw1_last_tls_le(x) X0/X1
+// shl16insli tmp, tmp, hw0_tls_le(x) X0/X1
+// move tmp, tmp Y0/Y1/X0/X1
+// move tmp, tmp Y0/Y1/X0/X1
+//
+//
+// compiler LE reference
+// |
+// V
+// moveli tmp, hw1_last_tls_le(x) X0/X1
+// shl16insli tmp, tmp, hw0_tls_le(x) X0/X1
+// add adr, tmp, tp Y0/Y1/X0/X1
+
+template<int size, bool big_endian>
+tls::Tls_optimization
+Target_tilegx<size, big_endian>::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)
+ {
+ // unique GD relocations
+ case elfcpp::R_TILEGX_TLS_GD_CALL:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
+ // 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;
+
+ // unique IE relocations
+ case elfcpp::R_TILEGX_TLS_IE_LOAD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
+ // 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;
+
+ // could be created for both GD and IE
+ // but they are expanded into the same
+ // instruction in GD and IE.
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
+ if (is_final)
+ return tls::TLSOPT_TO_LE;
+ return tls::TLSOPT_NONE;
+
+ // unique LE relocations
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
+ // 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.
+
+template<int size, bool big_endian>
+int
+Target_tilegx<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
+{
+ switch (r_type)
+ {
+ case elfcpp::R_TILEGX_NONE:
+ case elfcpp::R_TILEGX_GNU_VTINHERIT:
+ case elfcpp::R_TILEGX_GNU_VTENTRY:
+ // No symbol reference.
+ return 0;
+
+ case elfcpp::R_TILEGX_64:
+ case elfcpp::R_TILEGX_32:
+ case elfcpp::R_TILEGX_16:
+ case elfcpp::R_TILEGX_8:
+ return Symbol::ABSOLUTE_REF;
+
+ case elfcpp::R_TILEGX_BROFF_X1:
+ case elfcpp::R_TILEGX_64_PCREL:
+ case elfcpp::R_TILEGX_32_PCREL:
+ case elfcpp::R_TILEGX_16_PCREL:
+ case elfcpp::R_TILEGX_8_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW3_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW3_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PCREL:
+ return Symbol::RELATIVE_REF;
+
+ case elfcpp::R_TILEGX_JUMPOFF_X1:
+ case elfcpp::R_TILEGX_JUMPOFF_X1_PLT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL:
+ return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+
+ case elfcpp::R_TILEGX_IMM16_X0_HW0:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2:
+ case elfcpp::R_TILEGX_IMM16_X0_HW3:
+ case elfcpp::R_TILEGX_IMM16_X1_HW3:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST:
+ return Symbol::ABSOLUTE_REF;
+
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_GOT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_GOT:
+ // Absolute in GOT.
+ return Symbol::ABSOLUTE_REF;
+
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_TLS_DTPOFF64:
+ case elfcpp::R_TILEGX_TLS_DTPMOD32:
+ case elfcpp::R_TILEGX_TLS_DTPOFF32:
+ case elfcpp::R_TILEGX_TLS_TPOFF32:
+ case elfcpp::R_TILEGX_TLS_GD_CALL:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_TLS_IE_LOAD:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
+ return Symbol::TLS_REF;
+
+ case elfcpp::R_TILEGX_COPY:
+ case elfcpp::R_TILEGX_GLOB_DAT:
+ case elfcpp::R_TILEGX_JMP_SLOT:
+ case elfcpp::R_TILEGX_RELATIVE:
+ case elfcpp::R_TILEGX_TLS_TPOFF64:
+ case elfcpp::R_TILEGX_TLS_DTPMOD64:
+ default:
+ // Not expected. We will give an error later.
+ return 0;
+ }
+}
+
+// Report an unsupported relocation against a local symbol.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::Scan::unsupported_reloc_local(
+ Sized_relobj_file<size, 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.
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::Scan::check_non_pic(Relobj* object,
+ unsigned int r_type)
+{
+ switch (r_type)
+ {
+ // These are the relocation types supported by glibc for tilegx
+ // which should always work.
+ case elfcpp::R_TILEGX_RELATIVE:
+ case elfcpp::R_TILEGX_GLOB_DAT:
+ case elfcpp::R_TILEGX_JMP_SLOT:
+ case elfcpp::R_TILEGX_TLS_DTPMOD64:
+ case elfcpp::R_TILEGX_TLS_DTPOFF64:
+ case elfcpp::R_TILEGX_TLS_TPOFF64:
+ case elfcpp::R_TILEGX_8:
+ case elfcpp::R_TILEGX_16:
+ case elfcpp::R_TILEGX_32:
+ case elfcpp::R_TILEGX_64:
+ case elfcpp::R_TILEGX_COPY:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2:
+ case elfcpp::R_TILEGX_IMM16_X0_HW3:
+ case elfcpp::R_TILEGX_IMM16_X1_HW3:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST:
+ case elfcpp::R_TILEGX_BROFF_X1:
+ case elfcpp::R_TILEGX_JUMPOFF_X1:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW3_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW3_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PCREL:
+ 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;
+ gold_assert(parameters->options().output_is_position_independent());
+ object->error(_("requires unsupported dynamic reloc %u; "
+ "recompile with -fPIC"),
+ r_type);
+ this->issued_non_pic_error_ = true;
+ return;
+
+ case elfcpp::R_TILEGX_NONE:
+ gold_unreachable();
+ }
+}
+
+// Return whether we need to make a PLT entry for a relocation of the
+// given type against a STT_GNU_IFUNC symbol.
+
+template<int size, bool big_endian>
+bool
+Target_tilegx<size, big_endian>::Scan::reloc_needs_plt_for_ifunc(
+ Sized_relobj_file<size, big_endian>* 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.
+
+template<int size, bool big_endian>
+inline void
+Target_tilegx<size, big_endian>::Scan::local(Symbol_table* symtab,
+ Layout* layout,
+ Target_tilegx<size, big_endian>* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, big_endian>& reloc,
+ unsigned int r_type,
+ const elfcpp::Sym<size, big_endian>& lsym,
+ bool is_discarded)
+{
+ if (is_discarded)
+ return;
+
+ // A local STT_GNU_IFUNC symbol may require a PLT entry.
+ bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
+ if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type))
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ target->make_local_ifunc_plt_entry(symtab, layout, object, r_sym);
+ }
+
+ switch (r_type)
+ {
+ case elfcpp::R_TILEGX_NONE:
+ case elfcpp::R_TILEGX_GNU_VTINHERIT:
+ case elfcpp::R_TILEGX_GNU_VTENTRY:
+ break;
+
+ // If building a shared library (or a position-independent
+ // executable), because the runtime address needs plus
+ // the module base address, so generate a R_TILEGX_RELATIVE.
+ case elfcpp::R_TILEGX_32:
+ case elfcpp::R_TILEGX_64:
+ if (parameters->options().output_is_position_independent())
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_local_relative(object, r_sym,
+ elfcpp::R_TILEGX_RELATIVE,
+ output_section, data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend(), is_ifunc);
+ }
+ break;
+
+ // If building a shared library (or a position-independent
+ // executable), we need to create a dynamic relocation for this
+ // location.
+ case elfcpp::R_TILEGX_8:
+ case elfcpp::R_TILEGX_16:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2:
+ case elfcpp::R_TILEGX_IMM16_X0_HW3:
+ case elfcpp::R_TILEGX_IMM16_X1_HW3:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST:
+ if (parameters->options().output_is_position_independent())
+ {
+ this->check_non_pic(object, r_type);
+
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ if (lsym.get_st_type() != elfcpp::STT_SECTION)
+ rela_dyn->add_local(object, r_sym, r_type, output_section,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
+ else
+ {
+ gold_assert(lsym.get_st_value() == 0);
+ rela_dyn->add_symbolless_local_addend(object, r_sym, r_type,
+ output_section,
+ data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend());
+
+ }
+ }
+ break;
+
+ // R_TILEGX_JUMPOFF_X1_PLT against local symbol
+ // may happen for ifunc case.
+ case elfcpp::R_TILEGX_JUMPOFF_X1_PLT:
+ case elfcpp::R_TILEGX_JUMPOFF_X1:
+ case elfcpp::R_TILEGX_64_PCREL:
+ case elfcpp::R_TILEGX_32_PCREL:
+ case elfcpp::R_TILEGX_16_PCREL:
+ case elfcpp::R_TILEGX_8_PCREL:
+ case elfcpp::R_TILEGX_BROFF_X1:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW3_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW3_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL:
+ break;
+
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_GOT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_GOT:
+ {
+ // The symbol requires a GOT entry.
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+
+ // 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 (is_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)
+ {
+ // tilegx dynamic linker will not update local got entry,
+ // so, if we are generating a shared object, we need to add a
+ // dynamic relocation for this symbol's GOT entry to inform
+ // dynamic linker plus the load base explictly.
+ if (parameters->options().output_is_position_independent())
+ {
+ unsigned int got_offset
+ = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
+
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_local_relative(object, r_sym,
+ r_type,
+ got, got_offset, 0, is_ifunc);
+ }
+ }
+ }
+ break;
+
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_TLS_GD_CALL:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_TLS_IE_LOAD:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
+ {
+ bool output_is_shared = parameters->options().shared();
+ const tls::Tls_optimization opt_t =
+ Target_tilegx<size, big_endian>::optimize_tls_reloc(
+ !output_is_shared, r_type);
+
+ switch (r_type)
+ {
+ case elfcpp::R_TILEGX_TLS_GD_CALL:
+ // FIXME: predefine __tls_get_addr
+ //
+ // R_TILEGX_TLS_GD_CALL implicitly reference __tls_get_addr,
+ // while all other target, x86/arm/mips/powerpc/sparc
+ // generate tls relocation against __tls_get_addr explictly,
+ // so for TILEGX, we need the following hack.
+ if (opt_t == tls::TLSOPT_NONE) {
+ if (!target->tls_get_addr_sym_defined_) {
+ Symbol* sym = NULL;
+ options::parse_set(NULL, "__tls_get_addr",
+ (gold::options::String_set*)
+ &parameters->options().undefined());
+ symtab->add_undefined_symbols_from_command_line(layout);
+ target->tls_get_addr_sym_defined_ = true;
+ sym = symtab->lookup("__tls_get_addr");
+ sym->set_in_reg();
+ }
+ target->make_plt_entry(symtab, layout,
+ symtab->lookup("__tls_get_addr"));
+ }
+ break;
+
+ // only make effect when applying relocation
+ case elfcpp::R_TILEGX_TLS_IE_LOAD:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
+ break;
+
+ // GD: requires two GOT entry for module index and offset
+ // IE: requires one GOT entry for tp-relative offset
+ // LE: shouldn't happen for global symbol
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
+ {
+ if (opt_t == tls::TLSOPT_NONE) {
+ Output_data_got<size, big_endian> *got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym
+ = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ unsigned int shndx = lsym.get_st_shndx();
+ bool is_ordinary;
+ shndx = object->adjust_sym_shndx(r_sym, shndx,
+ &is_ordinary);
+ 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->rela_dyn_section(layout),
+ size == 32
+ ? elfcpp::R_TILEGX_TLS_DTPMOD32
+ : elfcpp::R_TILEGX_TLS_DTPMOD64);
+ } else if (opt_t == tls::TLSOPT_TO_IE) {
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ Reloc_section* rela_dyn
+ = target->rela_dyn_section(layout);
+ unsigned int r_sym
+ = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ unsigned int off = got->add_constant(0);
+ object->set_local_got_offset(r_sym,
+ GOT_TYPE_TLS_OFFSET,off);
+ rela_dyn->add_symbolless_local_addend(object, r_sym,
+ size == 32
+ ? elfcpp::R_TILEGX_TLS_TPOFF32
+ : elfcpp::R_TILEGX_TLS_TPOFF64,
+ got, off, 0);
+ } else if (opt_t != tls::TLSOPT_TO_LE)
+ // only TO_LE is allowed for local symbol
+ unsupported_reloc_local(object, r_type);
+ }
+ break;
+
+ // IE
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
+ {
+ layout->set_has_static_tls();
+ if (opt_t == tls::TLSOPT_NONE) {
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ Reloc_section* rela_dyn
+ = target->rela_dyn_section(layout);
+ unsigned int r_sym
+ = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ unsigned int off = got->add_constant(0);
+ object->set_local_got_offset(r_sym,
+ GOT_TYPE_TLS_OFFSET, off);
+ rela_dyn->add_symbolless_local_addend(object, r_sym,
+ size == 32
+ ? elfcpp::R_TILEGX_TLS_TPOFF32
+ : elfcpp::R_TILEGX_TLS_TPOFF64,
+ got, off, 0);
+ } else if (opt_t != tls::TLSOPT_TO_LE)
+ unsupported_reloc_local(object, r_type);
+ }
+ break;
+
+ // LE
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
+ layout->set_has_static_tls();
+ if (parameters->options().shared()) {
+ // defer to dynamic linker
+ gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
+ unsigned int r_sym
+ = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_symbolless_local_addend(object, r_sym, r_type,
+ output_section, data_shndx,
+ reloc.get_r_offset(), 0);
+ }
+ break;
+
+ default:
+ gold_unreachable();
+ }
+ }
+ break;
+
+ case elfcpp::R_TILEGX_COPY:
+ case elfcpp::R_TILEGX_GLOB_DAT:
+ case elfcpp::R_TILEGX_JMP_SLOT:
+ case elfcpp::R_TILEGX_RELATIVE:
+ // These are outstanding tls relocs, which are unexpected when linking
+ case elfcpp::R_TILEGX_TLS_TPOFF32:
+ case elfcpp::R_TILEGX_TLS_TPOFF64:
+ case elfcpp::R_TILEGX_TLS_DTPMOD32:
+ case elfcpp::R_TILEGX_TLS_DTPMOD64:
+ case elfcpp::R_TILEGX_TLS_DTPOFF32:
+ case elfcpp::R_TILEGX_TLS_DTPOFF64:
+ gold_error(_("%s: unexpected reloc %u in object file"),
+ object->name().c_str(), r_type);
+ break;
+
+ default:
+ gold_error(_("%s: unsupported reloc %u against local symbol"),
+ object->name().c_str(), r_type);
+ break;
+ }
+}
+
+
+// Report an unsupported relocation against a global symbol.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::Scan::unsupported_reloc_global(
+ Sized_relobj_file<size, 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());
+}
+
+// Returns true if this relocation type could be that of a function pointer.
+template<int size, bool big_endian>
+inline bool
+Target_tilegx<size, big_endian>::Scan::possible_function_pointer_reloc(
+ unsigned int r_type)
+{
+ switch (r_type)
+ {
+ case elfcpp::R_TILEGX_IMM16_X0_HW0:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2:
+ case elfcpp::R_TILEGX_IMM16_X0_HW3:
+ case elfcpp::R_TILEGX_IMM16_X1_HW3:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW3_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW3_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_GOT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_GOT:
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+// For safe ICF, scan a relocation for a local symbol to check if it
+// corresponds to a function pointer being taken. In that case mark
+// the function whose pointer was taken as not foldable.
+
+template<int size, bool big_endian>
+inline bool
+Target_tilegx<size, big_endian>::Scan::local_reloc_may_be_function_pointer(
+ Symbol_table* ,
+ Layout* ,
+ Target_tilegx<size, big_endian>* ,
+ Sized_relobj_file<size, big_endian>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<size, big_endian>& ,
+ unsigned int r_type,
+ const elfcpp::Sym<size, big_endian>&)
+{
+ return possible_function_pointer_reloc(r_type);
+}
+
+// For safe ICF, scan a relocation for a global symbol to check if it
+// corresponds to a function pointer being taken. In that case mark
+// the function whose pointer was taken as not foldable.
+
+template<int size, bool big_endian>
+inline bool
+Target_tilegx<size, big_endian>::Scan::global_reloc_may_be_function_pointer(
+ Symbol_table*,
+ Layout* ,
+ Target_tilegx<size, big_endian>* ,
+ Sized_relobj_file<size, big_endian>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<size, big_endian>& ,
+ unsigned int r_type,
+ Symbol* gsym)
+{
+ // GOT is not a function.
+ if (strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0)
+ return false;
+
+ // When building a shared library, do not fold symbols whose visibility
+ // is hidden, internal or protected.
+ return ((parameters->options().shared()
+ && (gsym->visibility() == elfcpp::STV_INTERNAL
+ || gsym->visibility() == elfcpp::STV_PROTECTED
+ || gsym->visibility() == elfcpp::STV_HIDDEN))
+ || possible_function_pointer_reloc(r_type));
+}
+
+// Scan a relocation for a global symbol.
+
+template<int size, bool big_endian>
+inline void
+Target_tilegx<size, big_endian>::Scan::global(Symbol_table* symtab,
+ Layout* layout,
+ Target_tilegx<size, big_endian>* target,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, 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);
+
+ // 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_TILEGX_NONE:
+ case elfcpp::R_TILEGX_GNU_VTINHERIT:
+ case elfcpp::R_TILEGX_GNU_VTENTRY:
+ break;
+
+ case elfcpp::R_TILEGX_DEST_IMM8_X1:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2:
+ case elfcpp::R_TILEGX_IMM16_X0_HW3:
+ case elfcpp::R_TILEGX_IMM16_X1_HW3:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST:
+ case elfcpp::R_TILEGX_64:
+ case elfcpp::R_TILEGX_32:
+ case elfcpp::R_TILEGX_16:
+ case elfcpp::R_TILEGX_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 (((size == 64 && r_type == elfcpp::R_TILEGX_64)
+ || (size == 32 && r_type == elfcpp::R_TILEGX_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* rela_dyn =
+ target->rela_irelative_section(layout);
+ unsigned int r_type = elfcpp::R_TILEGX_IRELATIVE;
+ rela_dyn->add_symbolless_global_addend(gsym, r_type,
+ output_section, object,
+ data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend());
+ } else if ((r_type == elfcpp::R_TILEGX_64
+ || r_type == elfcpp::R_TILEGX_32)
+ && gsym->can_use_relative_reloc(false))
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_global_relative(gsym, elfcpp::R_TILEGX_RELATIVE,
+ output_section, object,
+ data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend(), false);
+ }
+ else
+ {
+ this->check_non_pic(object, r_type);
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_global(gsym, r_type, output_section, object,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ }
+ }
+ break;
+
+ case elfcpp::R_TILEGX_BROFF_X1:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW3_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW3_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PCREL:
+ case elfcpp::R_TILEGX_64_PCREL:
+ case elfcpp::R_TILEGX_32_PCREL:
+ case elfcpp::R_TILEGX_16_PCREL:
+ case elfcpp::R_TILEGX_8_PCREL:
+ {
+ // Make a PLT entry if necessary.
+ if (gsym->needs_plt_entry())
+ target->make_plt_entry(symtab, layout, gsym);
+ // Make a dynamic relocation if necessary.
+ if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+ {
+ if (gsym->may_need_copy_reloc())
+ {
+ target->copy_reloc(symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
+ }
+ else
+ {
+ this->check_non_pic(object, r_type);
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_global(gsym, r_type, output_section, object,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ }
+ }
+ break;
+
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_GOT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_GOT:
+ {
+ // The symbol requires a GOT entry.
+ Output_data_got<size, big_endian>* 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
+ // dynamic relocation for it.
+ Reloc_section* rela_dyn = target->rela_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, rela_dyn,
+ elfcpp::R_TILEGX_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);
+ rela_dyn->add_global_relative(gsym,
+ r_type,
+ got, got_off, 0, false);
+ }
+ }
+ }
+ }
+ break;
+
+ // a minor difference here for R_TILEGX_JUMPOFF_X1
+ // between bfd linker and gold linker for gold, when
+ // R_TILEGX_JUMPOFF_X1 against global symbol, we
+ // turn it into JUMPOFF_X1_PLT, otherwise the distance
+ // to the symbol function may overflow at runtime.
+ case elfcpp::R_TILEGX_JUMPOFF_X1:
+
+ case elfcpp::R_TILEGX_JUMPOFF_X1_PLT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL:
+ // 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_TILEGX_IMM16_X0_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_TLS_GD_CALL:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_TLS_IE_LOAD:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
+ {
+ const bool is_final = gsym->final_value_is_known();
+ const tls::Tls_optimization opt_t =
+ Target_tilegx<size, big_endian>::optimize_tls_reloc(is_final,
+ r_type);
+
+ switch (r_type)
+ {
+ // only expand to plt against __tls_get_addr in GD model
+ case elfcpp::R_TILEGX_TLS_GD_CALL:
+ if (opt_t == tls::TLSOPT_NONE) {
+ // FIXME: it's better '__tls_get_addr' referenced explictly
+ if (!target->tls_get_addr_sym_defined_) {
+ Symbol* sym = NULL;
+ options::parse_set(NULL, "__tls_get_addr",
+ (gold::options::String_set*)
+ &parameters->options().undefined());
+ symtab->add_undefined_symbols_from_command_line(layout);
+ target->tls_get_addr_sym_defined_ = true;
+ sym = symtab->lookup("__tls_get_addr");
+ sym->set_in_reg();
+ }
+ target->make_plt_entry(symtab, layout,
+ symtab->lookup("__tls_get_addr"));
+ }
+ break;
+
+ // only make effect when applying relocation
+ case elfcpp::R_TILEGX_TLS_IE_LOAD:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
+ break;
+
+ // GD: requires two GOT entry for module index and offset
+ // IE: requires one GOT entry for tp-relative offset
+ // LE: shouldn't happen for global symbol
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
+ {
+ if (opt_t == tls::TLSOPT_NONE) {
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
+ target->rela_dyn_section(layout),
+ size == 32
+ ? elfcpp::R_TILEGX_TLS_DTPMOD32
+ : elfcpp::R_TILEGX_TLS_DTPMOD64,
+ size == 32
+ ? elfcpp::R_TILEGX_TLS_DTPOFF32
+ : elfcpp::R_TILEGX_TLS_DTPOFF64);
+ } else if (opt_t == tls::TLSOPT_TO_IE) {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ target->rela_dyn_section(layout),
+ size == 32
+ ? elfcpp::R_TILEGX_TLS_TPOFF32
+ : elfcpp::R_TILEGX_TLS_TPOFF64);
+ } else if (opt_t != tls::TLSOPT_TO_LE)
+ // exteranl symbol should not be optimized to TO_LE
+ unsupported_reloc_global(object, r_type, gsym);
+ }
+ break;
+
+ // IE
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
+ {
+ layout->set_has_static_tls();
+ if (opt_t == tls::TLSOPT_NONE) {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ target->rela_dyn_section(layout),
+ size == 32
+ ? elfcpp::R_TILEGX_TLS_TPOFF32
+ : elfcpp::R_TILEGX_TLS_TPOFF64);
+ } else if (opt_t != tls::TLSOPT_TO_LE)
+ unsupported_reloc_global(object, r_type, gsym);
+ }
+ break;
+
+ // LE
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
+ layout->set_has_static_tls();
+ if (parameters->options().shared()) {
+ // defer to dynamic linker
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_symbolless_global_addend(gsym, r_type,
+ output_section, object,
+ data_shndx,
+ reloc.get_r_offset(), 0);
+ }
+ break;
+
+ default:
+ gold_unreachable();
+ }
+ }
+ break;
+
+ // below are outstanding relocs
+ // should not existed in static linking stage
+ case elfcpp::R_TILEGX_COPY:
+ case elfcpp::R_TILEGX_GLOB_DAT:
+ case elfcpp::R_TILEGX_JMP_SLOT:
+ case elfcpp::R_TILEGX_RELATIVE:
+ case elfcpp::R_TILEGX_TLS_TPOFF32:
+ case elfcpp::R_TILEGX_TLS_TPOFF64:
+ case elfcpp::R_TILEGX_TLS_DTPMOD32:
+ case elfcpp::R_TILEGX_TLS_DTPMOD64:
+ case elfcpp::R_TILEGX_TLS_DTPOFF32:
+ case elfcpp::R_TILEGX_TLS_DTPOFF64:
+ gold_error(_("%s: unexpected reloc %u in object file"),
+ object->name().c_str(), r_type);
+ break;
+
+ default:
+ gold_error(_("%s: unsupported reloc %u against global symbol %s"),
+ object->name().c_str(), r_type,
+ gsym->demangled_name().c_str());
+ break;
+ }
+}
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::gc_process_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols)
+{
+ typedef Target_tilegx<size, big_endian> Tilegx;
+ typedef typename Target_tilegx<size, big_endian>::Scan Scan;
+
+ if (sh_type == elfcpp::SHT_REL)
+ {
+ return;
+ }
+
+ gold::gc_process_relocs<size, big_endian,
+ Tilegx, elfcpp::SHT_RELA, Scan,
+ typename Target_tilegx<size, big_endian>::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<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::scan_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols)
+{
+ typedef Target_tilegx<size, big_endian> Tilegx;
+ typedef typename Target_tilegx<size, big_endian>::Scan Scan;
+
+ if (sh_type == elfcpp::SHT_REL)
+ {
+ gold_error(_("%s: unsupported REL reloc section"),
+ object->name().c_str());
+ return;
+ }
+
+ gold::scan_relocs<size, big_endian, Tilegx, elfcpp::SHT_RELA, Scan>(
+ symtab,
+ layout,
+ this,
+ object,
+ data_shndx,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ local_symbol_count,
+ plocal_symbols);
+}
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::do_define_standard_symbols(
+ Symbol_table* symtab,
+ Layout* layout)
+{
+ Output_section* feedback_section = layout->find_output_section(".feedback");
+
+ if (feedback_section != NULL)
+ {
+ symtab->define_in_output_data("__feedback_section_end",
+ NULL,
+ Symbol_table::PREDEFINED,
+ feedback_section,
+ 0,
+ 0,
+ elfcpp::STT_NOTYPE,
+ elfcpp::STB_GLOBAL,
+ elfcpp::STV_HIDDEN,
+ 0,
+ true, // offset_is_from_end
+ false);
+ }
+}
+
+// Finalize the sections.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::do_finalize_sections(
+ Layout* layout,
+ const Input_objects*,
+ Symbol_table* symtab)
+{
+ const Reloc_section* rel_plt = (this->plt_ == NULL
+ ? NULL
+ : this->plt_->rela_plt());
+ layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt,
+ this->rela_dyn_, true, true);
+
+ // 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->rela_dyn_section(layout));
+
+ // Set the size of the _GLOBAL_OFFSET_TABLE_ symbol to the size of
+ // the .got section.
+ Symbol* sym = this->global_offset_table_;
+ if (sym != NULL)
+ {
+ uint64_t data_size = this->got_->current_data_size();
+ symtab->get_sized_symbol<size>(sym)->set_symsize(data_size);
+
+ // If the .got section is more than 0x8000 bytes, we add
+ // 0x8000 to the value of _GLOBAL_OFFSET_TABLE_, so that 16
+ // bit relocations have a greater chance of working.
+ if (data_size >= 0x8000)
+ symtab->get_sized_symbol<size>(sym)->set_value(
+ symtab->get_sized_symbol<size>(sym)->value() + 0x8000);
+ }
+
+ if (parameters->doing_static_link()
+ && (this->plt_ == NULL || !this->plt_->has_irelative_section()))
+ {
+ // If linking statically, make sure that the __rela_iplt symbols
+ // were defined if necessary, even if we didn't create a PLT.
+ static const Define_symbol_in_segment syms[] =
+ {
+ {
+ "__rela_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
+ },
+ {
+ "__rela_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());
+ }
+}
+
+// Perform a relocation.
+
+template<int size, bool big_endian>
+inline bool
+Target_tilegx<size, big_endian>::Relocate::relocate(
+ const Relocate_info<size, big_endian>* relinfo,
+ Target_tilegx<size, big_endian>* target,
+ Output_section*,
+ size_t relnum,
+ const elfcpp::Rela<size, big_endian>& rela,
+ unsigned int r_type,
+ const Sized_symbol<size>* gsym,
+ const Symbol_value<size>* psymval,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type)
+{
+ if (view == NULL)
+ return true;
+
+ typedef Tilegx_relocate_functions<size, big_endian> TilegxReloc;
+ typename TilegxReloc::Tilegx_howto r_howto;
+
+ const Sized_relobj_file<size, big_endian>* object = relinfo->object;
+
+ // Pick the value to use for symbols defined in the PLT.
+ Symbol_value<size> symval;
+ 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<size>(rela.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;
+ }
+ }
+
+ elfcpp::Elf_Xword addend = rela.get_r_addend();
+
+ // Get the GOT offset if needed.
+ // For tilegx, the GOT pointer points to the start of the GOT section.
+ bool have_got_offset = false;
+ int got_offset = 0;
+ int got_base = target->got_ != NULL
+ ? target->got_->current_data_size() >= 0x8000 ? 0x8000 : 0
+ : 0;
+ unsigned int got_type = GOT_TYPE_STANDARD;
+ bool always_apply_relocation = false;
+ switch (r_type)
+ {
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_GOT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_GOT:
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(got_type));
+ got_offset = gsym->got_offset(got_type) - got_base;
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset =
+ object->local_got_offset(r_sym, got_type) - got_base;
+ }
+ have_got_offset = true;
+ break;
+
+ default:
+ break;
+ }
+
+ r_howto = TilegxReloc::howto[r_type];
+ switch (r_type)
+ {
+ case elfcpp::R_TILEGX_NONE:
+ case elfcpp::R_TILEGX_GNU_VTINHERIT:
+ case elfcpp::R_TILEGX_GNU_VTENTRY:
+ break;
+
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_GOT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_GOT:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_GOT:
+ gold_assert(have_got_offset);
+ symval.set_output_value(got_offset);
+ psymval = &symval;
+ always_apply_relocation = true;
+ addend = 0;
+
+ // when under PIC mode, these relocations are deferred to rtld
+ case elfcpp::R_TILEGX_IMM16_X0_HW0:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2:
+ case elfcpp::R_TILEGX_IMM16_X0_HW3:
+ case elfcpp::R_TILEGX_IMM16_X1_HW3:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST:
+ if (always_apply_relocation
+ || !parameters->options().output_is_position_independent())
+ TilegxReloc::imm_x_general(view, object, psymval, addend, r_howto);
+ break;
+
+ case elfcpp::R_TILEGX_JUMPOFF_X1:
+ case elfcpp::R_TILEGX_JUMPOFF_X1_PLT:
+ gold_assert(gsym == NULL
+ || gsym->has_plt_offset()
+ || gsym->final_value_is_known()
+ || (gsym->is_defined()
+ && !gsym->is_from_dynobj()
+ && !gsym->is_preemptible()));
+ TilegxReloc::imm_x_pcrel_general(view, object, psymval, addend,
+ address, r_howto);
+ break;
+
+
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW3_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW3_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL:
+ case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PCREL:
+ TilegxReloc::imm_x_pcrel_general(view, object, psymval, addend,
+ address, r_howto);
+ break;
+
+ case elfcpp::R_TILEGX_BROFF_X1:
+ case elfcpp::R_TILEGX_DEST_IMM8_X1:
+ TilegxReloc::imm_x_two_part_general(view, object, psymval,
+ addend, address, r_type);
+ break;
+
+
+ // below are general relocation types, which can be
+ // handled by target-independent handlers
+ case elfcpp::R_TILEGX_64:
+ TilegxReloc::abs64(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_TILEGX_64_PCREL:
+ TilegxReloc::pc_abs64(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_TILEGX_32:
+ TilegxReloc::abs32(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_TILEGX_32_PCREL:
+ TilegxReloc::pc_abs32(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_TILEGX_16:
+ TilegxReloc::abs16(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_TILEGX_16_PCREL:
+ TilegxReloc::pc_abs16(view, object, psymval, addend, address);
+ break;
+
+ case elfcpp::R_TILEGX_8:
+ Relocate_functions<size, big_endian>::rela8(view, object,
+ psymval, addend);
+ break;
+
+ case elfcpp::R_TILEGX_8_PCREL:
+ Relocate_functions<size, big_endian>::pcrela8(view, object,
+ psymval, addend, address);
+ break;
+
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_TLS_GD_CALL:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_TLS_IE_LOAD:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
+ {
+ const bool is_final = (gsym == NULL
+ ? !parameters->options().shared()
+ : gsym->final_value_is_known());
+ tls::Tls_optimization opt_t =
+ Target_tilegx<size, big_endian>::optimize_tls_reloc(is_final,
+ r_type);
+
+ switch (r_type)
+ {
+
+ case elfcpp::R_TILEGX_TLS_GD_CALL:
+ {
+ if (opt_t == tls::TLSOPT_NONE) {
+ Symbol *tls_sym = relinfo->symtab->lookup("__tls_get_addr");
+ symval.set_output_value(
+ target->plt_address_for_global(tls_sym));
+ psymval = &symval;
+ TilegxReloc::imm_x_pcrel_general(view, object, psymval,
+ addend, address, r_howto);
+ }
+ else if (opt_t == tls::TLSOPT_TO_IE
+ || opt_t == tls::TLSOPT_TO_LE)
+ TilegxReloc::tls_relax(view, r_type, opt_t);
+ }
+ break;
+
+ // XX_TLS_GD is the same as normal X_GOT relocation
+ // except allocating a got entry pair,
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
+ if (opt_t == tls::TLSOPT_NONE) {
+ got_type = GOT_TYPE_TLS_PAIR;
+ have_got_offset = true;
+ } else if (opt_t == tls::TLSOPT_TO_IE) {
+ got_type = GOT_TYPE_TLS_OFFSET;
+ have_got_offset = true;
+ }
+ goto do_update_value;
+ // XX_TLS_IE is the same as normal X_GOT relocation
+ // except allocating one additional runtime relocation
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
+ if (opt_t == tls::TLSOPT_NONE) {
+ got_type = GOT_TYPE_TLS_OFFSET;
+ have_got_offset = true;
+ }
+ do_update_value:
+ if (have_got_offset) {
+ if (gsym != NULL) {
+ gold_assert(gsym->has_got_offset(got_type));
+ got_offset = gsym->got_offset(got_type) - got_base;
+ } else {
+ unsigned int r_sym
+ = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset =
+ object->local_got_offset(r_sym, got_type) - got_base;
+ }
+ }
+
+ if (opt_t == tls::TLSOPT_NONE
+ || opt_t == tls::TLSOPT_TO_IE) {
+ // for both GD/IE, these relocations
+ // actually calculate got offset, so
+ // there behavior are the same
+ gold_assert(have_got_offset);
+ symval.set_output_value(got_offset);
+ psymval = &symval;
+ addend = 0;
+ TilegxReloc::imm_x_general(view, object, psymval,
+ addend, r_howto);
+ break;
+ } // else if (opt_t == tls::TLSOPT_TO_LE)
+ // both GD/IE are turned into LE, which
+ // is absolute relocation.
+ //
+ // | go through
+ // |
+ // V
+ // LE
+ //
+ // tp
+ // |
+ // V
+ // t_var1 | t_var2 | t_var3 | ...
+ // --------------------------------------------------
+ //
+ // so offset to tp should be negative, we get offset
+ // from the following formular for LE
+ //
+ // t_var1_off = t_var1_sym_value - tls_section_start
+ //
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
+ case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
+ {
+ Output_segment *tls_segment = relinfo->layout->tls_segment();
+ if (tls_segment == NULL) {
+ gold_assert(parameters->errors()->error_count() > 0
+ || issue_undefined_symbol_error(gsym));
+ return false;
+ }
+
+ typename elfcpp::Elf_types<size>::Elf_Addr value
+ = psymval->value(relinfo->object, 0);
+ symval.set_output_value(value);
+ psymval = &symval;
+ TilegxReloc::imm_x_general(view, object, psymval,
+ addend, r_howto);
+ }
+ break;
+
+ // tls relaxation
+ case elfcpp::R_TILEGX_TLS_IE_LOAD:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
+ case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
+ case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
+ TilegxReloc::tls_relax(view, r_type, opt_t);
+ break;
+
+ default:
+ gold_unreachable();
+ }
+ }
+ break;
+
+ // below are outstanding relocs
+ // should not existed in static linking stage
+ case elfcpp::R_TILEGX_COPY:
+ case elfcpp::R_TILEGX_GLOB_DAT:
+ case elfcpp::R_TILEGX_JMP_SLOT:
+ case elfcpp::R_TILEGX_RELATIVE:
+ case elfcpp::R_TILEGX_TLS_TPOFF32:
+ case elfcpp::R_TILEGX_TLS_TPOFF64:
+ case elfcpp::R_TILEGX_TLS_DTPMOD32:
+ case elfcpp::R_TILEGX_TLS_DTPMOD64:
+ case elfcpp::R_TILEGX_TLS_DTPOFF32:
+ case elfcpp::R_TILEGX_TLS_DTPOFF64:
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unexpected reloc %u in object file"),
+ r_type);
+ break;
+
+ default:
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unsupported reloc %u"),
+ r_type);
+ break;
+ }
+
+ return true;
+}
+
+// Relocate section data.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::relocate_section(
+ const Relocate_info<size, 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,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size,
+ const Reloc_symbol_changes* reloc_symbol_changes)
+{
+ typedef Target_tilegx<size, big_endian> Tilegx;
+ typedef typename Target_tilegx<size, big_endian>::Relocate Tilegx_relocate;
+
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+
+ gold::relocate_section<size, big_endian, Tilegx, elfcpp::SHT_RELA,
+ Tilegx_relocate, gold::Default_comdat_behavior>(
+ relinfo,
+ this,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ view,
+ address,
+ view_size,
+ reloc_symbol_changes);
+}
+
+// Apply an incremental relocation. Incremental relocations always refer
+// to global symbols.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::apply_relocation(
+ const Relocate_info<size, big_endian>* relinfo,
+ typename elfcpp::Elf_types<size>::Elf_Addr r_offset,
+ unsigned int r_type,
+ typename elfcpp::Elf_types<size>::Elf_Swxword r_addend,
+ const Symbol* gsym,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size)
+{
+ gold::apply_relocation<size, big_endian, Target_tilegx<size, big_endian>,
+ typename Target_tilegx<size, big_endian>::Relocate>(
+ relinfo,
+ this,
+ r_offset,
+ r_type,
+ r_addend,
+ gsym,
+ view,
+ address,
+ view_size);
+}
+
+// Return the size of a relocation while scanning during a relocatable
+// link.
+
+template<int size, bool big_endian>
+unsigned int
+Target_tilegx<size,big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
+ unsigned int, Relobj*)
+{
+ // We are always SHT_RELA, so we should never get here.
+ gold_unreachable();
+ return 0;
+}
+
+// Scan the relocs during a relocatable link.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::scan_relocatable_relocs(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols,
+ Relocatable_relocs* rr)
+{
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+
+ typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
+ Relocatable_size_for_reloc> Scan_relocatable_relocs;
+
+ gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
+ Scan_relocatable_relocs>(
+ symtab,
+ layout,
+ object,
+ data_shndx,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ local_symbol_count,
+ plocal_symbols,
+ rr);
+}
+
+// Relocate a section during a relocatable link.
+
+template<int size, bool big_endian>
+void
+Target_tilegx<size, big_endian>::relocate_relocs(
+ const Relocate_info<size, big_endian>* relinfo,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
+ const Relocatable_relocs* rr,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::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_RELA);
+
+ gold::relocate_relocs<size, big_endian, elfcpp::SHT_RELA>(
+ 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.
+
+template<int size, bool big_endian>
+uint64_t
+Target_tilegx<size, big_endian>::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 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.
+
+template<int size, bool big_endian>
+uint64_t
+Target_tilegx<size, big_endian>::do_ehframe_datarel_base() const
+{
+ gold_assert(this->global_offset_table_ != NULL);
+ Symbol* sym = this->global_offset_table_;
+ Sized_symbol<size>* ssym = static_cast<Sized_symbol<size>*>(sym);
+ return ssym->value();
+}
+
+// The selector for tilegx object files.
+
+template<int size, bool big_endian>
+class Target_selector_tilegx : public Target_selector
+{
+public:
+ Target_selector_tilegx()
+ : Target_selector(elfcpp::EM_TILEGX, size, big_endian,
+ (size == 64
+ ? (big_endian ? "elf64-tilegx-be" : "elf64-tilegx-le")
+ : (big_endian ? "elf32-tilegx-be"
+ : "elf32-tilegx-le")),
+ (size == 64
+ ? (big_endian ? "elf64tilegx_be" : "elf64tilegx")
+ : (big_endian ? "elf32tilegx_be" : "elf32tilegx")))
+ { }
+
+ Target*
+ do_instantiate_target()
+ { return new Target_tilegx<size, big_endian>(); }
+
+};
+
+Target_selector_tilegx<64, false> target_selector_tilegx64_le;
+Target_selector_tilegx<32, false> target_selector_tilegx32_le;
+Target_selector_tilegx<64, true> target_selector_tilegx64_be;
+Target_selector_tilegx<32, true> target_selector_tilegx32_be;
+} // End anonymous namespace.
diff --git a/binutils-2.25/gold/timer.cc b/binutils-2.25/gold/timer.cc
new file mode 100644
index 00000000..f3a1c911
--- /dev/null
+++ b/binutils-2.25/gold/timer.cc
@@ -0,0 +1,133 @@
+// timer.cc -- helper class for time accounting
+
+// Copyright 2009, 2010 Free Software Foundation, Inc.
+// Written by Rafael Avila de Espindola <espindola@google.com>.
+
+// 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 <unistd.h>
+
+#ifdef HAVE_TIMES
+#include <sys/times.h>
+#endif
+
+#include "libiberty.h"
+
+#include "timer.h"
+
+namespace gold
+{
+
+// Class Timer
+
+Timer::Timer()
+{
+ this->start_time_.wall = 0;
+ this->start_time_.user = 0;
+ this->start_time_.sys = 0;
+}
+
+// Start counting the time.
+void
+Timer::start()
+{
+ this->get_time(&this->start_time_);
+}
+
+// Record the time used by pass N (0 <= N <= 2).
+void
+Timer::stamp(int n)
+{
+ gold_assert(n >= 0 && n <= 2);
+ TimeStats& thispass = this->pass_times_[n];
+ this->get_time(&thispass);
+}
+
+#if HAVE_SYSCONF && defined _SC_CLK_TCK
+# define TICKS_PER_SECOND sysconf (_SC_CLK_TCK) /* POSIX 1003.1-1996 */
+#else
+# ifdef CLK_TCK
+# define TICKS_PER_SECOND CLK_TCK /* POSIX 1003.1-1988; obsolescent */
+# else
+# ifdef HZ
+# define TICKS_PER_SECOND HZ /* traditional UNIX */
+# else
+# define TICKS_PER_SECOND 100 /* often the correct value */
+# endif
+# endif
+#endif
+
+// times returns statistics in clock_t units. This variable will hold the
+// conversion factor to seconds. We use a variable that is initialized once
+// because sysconf can be slow.
+static long ticks_per_sec;
+class Timer_init
+{
+ public:
+ Timer_init()
+ {
+ ticks_per_sec = TICKS_PER_SECOND;
+ }
+};
+Timer_init timer_init;
+
+// Write the current time information.
+void
+Timer::get_time(TimeStats *now)
+{
+#ifdef HAVE_TIMES
+ tms t;
+ now->wall = (times(&t) * 1000) / ticks_per_sec;
+ now->user = (t.tms_utime * 1000) / ticks_per_sec;
+ now->sys = (t.tms_stime * 1000) / ticks_per_sec;
+#else
+ now->wall = get_run_time() / 1000;
+ now->user = 0;
+ now->sys = 0;
+#endif
+}
+
+// Return the stats since start was called.
+Timer::TimeStats
+Timer::get_elapsed_time()
+{
+ TimeStats now;
+ this->get_time(&now);
+ TimeStats delta;
+ delta.wall = now.wall - this->start_time_.wall;
+ delta.user = now.user - this->start_time_.user;
+ delta.sys = now.sys - this->start_time_.sys;
+ return delta;
+}
+
+// Return the stats for pass N (0 <= N <= 2).
+Timer::TimeStats
+Timer::get_pass_time(int n)
+{
+ gold_assert(n >= 0 && n <= 2);
+ TimeStats thispass = this->pass_times_[n];
+ TimeStats& lastpass = n > 0 ? this->pass_times_[n-1] : this->start_time_;
+ thispass.wall -= lastpass.wall;
+ thispass.user -= lastpass.user;
+ thispass.sys -= lastpass.sys;
+ return thispass;
+}
+
+}
diff --git a/binutils-2.25/gold/timer.h b/binutils-2.25/gold/timer.h
new file mode 100644
index 00000000..4f986ca1
--- /dev/null
+++ b/binutils-2.25/gold/timer.h
@@ -0,0 +1,80 @@
+// timer.h -- helper class for time accounting -*- C++ -*-
+
+// Copyright 2009, 2010 Free Software Foundation, Inc.
+// Written by Rafael Avila de Espindola <espindola@google.com>.
+
+// 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_TIMER_H
+#define GOLD_TIMER_H
+
+namespace gold
+{
+
+class Timer
+{
+ public:
+ // Used to report time statistics. All fields are in milliseconds.
+ struct TimeStats
+ {
+ /* User time in this process. */
+ long user;
+
+ /* System time in this process. */
+ long sys;
+
+ /* Wall clock time. */
+ long wall;
+ };
+
+ Timer();
+
+ // Return the stats since start was called.
+ TimeStats
+ get_elapsed_time();
+
+ // Return the stats for pass N (0 <= N <= 2).
+ TimeStats
+ get_pass_time(int n);
+
+ // Start counting the time.
+ void
+ start();
+
+ // Record the time used by pass N (0 <= N <= 2).
+ void
+ stamp(int n);
+
+ private:
+ // This class cannot be copied.
+ Timer(const Timer&);
+ Timer& operator=(const Timer&);
+
+ // Write the current time information.
+ static void
+ get_time(TimeStats* now);
+
+ // The time of the last call to start.
+ TimeStats start_time_;
+
+ // Times for each pass.
+ TimeStats pass_times_[3];
+};
+
+}
+#endif
diff --git a/binutils-2.25/gold/tls.h b/binutils-2.25/gold/tls.h
new file mode 100644
index 00000000..5b5cb6ea
--- /dev/null
+++ b/binutils-2.25/gold/tls.h
@@ -0,0 +1,81 @@
+// tls.h -- Thread-Local Storage utility routines for gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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_TLS_H
+#define GOLD_TLS_H
+
+#include "elfcpp.h"
+#include "reloc.h"
+
+namespace gold
+{
+
+namespace tls
+{
+
+// This is used for relocations that can be converted to a different,
+// more efficient type of relocation.
+
+enum Tls_optimization
+{
+ TLSOPT_NONE, // Can not convert this relocation to a more efficient one.
+ TLSOPT_TO_LD, // Can convert General Dynamic to Local Dynamic.
+ TLSOPT_TO_LE, // Can convert GD or LD to Local-Exec.
+ TLSOPT_TO_IE, // Can convert GD or LD or LE to Initial-Exec.
+};
+
+// Check the range for a TLS relocation. This is inlined for efficiency.
+
+template<int size, bool big_endian>
+inline void
+check_range(const Relocate_info<size, big_endian>* relinfo,
+ size_t relnum,
+ typename elfcpp::Elf_types<size>::Elf_Addr rel_offset,
+ section_size_type view_size, int off)
+{
+ typename elfcpp::Elf_types<size>::Elf_Addr offset = rel_offset + off;
+ // Elf_Addr is unsigned, so this also tests for signed offset < 0.
+ if (offset > view_size)
+ gold_error_at_location(relinfo, relnum, rel_offset,
+ _("TLS relocation out of range"));
+}
+
+// Check the validity of a TLS relocation. This is like assert.
+
+template<int size, bool big_endian>
+inline void
+check_tls(const Relocate_info<size, big_endian>* relinfo,
+ size_t relnum,
+ typename elfcpp::Elf_types<size>::Elf_Addr rel_offset,
+ bool valid)
+{
+ if (!valid)
+ gold_error_at_location(relinfo, relnum, rel_offset,
+ _("TLS relocation against invalid instruction"));
+}
+
+
+} // End namespace tls.
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_TLS_H)
diff --git a/binutils-2.25/gold/token.h b/binutils-2.25/gold/token.h
new file mode 100644
index 00000000..5cf64a0d
--- /dev/null
+++ b/binutils-2.25/gold/token.h
@@ -0,0 +1,335 @@
+// token.h -- lock tokens for gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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_TOKEN_H
+#define GOLD_TOKEN_H
+
+namespace gold
+{
+
+class Condvar;
+class Task;
+
+// A list of Tasks, managed through the next_locked_ field in the
+// class Task. We define this class here because we need it in
+// Task_token.
+
+class Task_list
+{
+ public:
+ Task_list()
+ : head_(NULL), tail_(NULL)
+ { }
+
+ ~Task_list()
+ { gold_assert(this->head_ == NULL && this->tail_ == NULL); }
+
+ // Return whether the list is empty.
+ bool
+ empty() const
+ { return this->head_ == NULL; }
+
+ // Add T to the head of the list.
+ void
+ push_front(Task* t);
+
+ // Add T to the end of the list.
+ void
+ push_back(Task* t);
+
+ // Remove the first Task on the list and return it. Return NULL if
+ // the list is empty.
+ Task*
+ pop_front();
+
+ private:
+ // The start of the list. NULL if the list is empty.
+ Task* head_;
+ // The end of the list. NULL if the list is empty.
+ Task* tail_;
+};
+
+// We support two basic types of locks, which are both implemented
+// using the single class Task_token.
+
+// A write lock may be held by a single Task at a time. This is used
+// to control access to a single shared resource such as an Object.
+
+// A blocker is used to indicate that a Task A must be run after some
+// set of Tasks B. For each of the Tasks B, we increment the blocker
+// when the Task is created, and decrement it when the Task is
+// completed. When the count goes to 0, the task A is ready to run.
+
+// There are no shared read locks. We always read and write objects
+// in predictable patterns. The purpose of the locks is to permit
+// some flexibility for the threading system, for cases where the
+// execution order does not matter.
+
+// These tokens are only manipulated when the workqueue lock is held
+// or when they are first created. They do not require any locking
+// themselves.
+
+class Task_token
+{
+ public:
+ Task_token(bool is_blocker)
+ : is_blocker_(is_blocker), blockers_(0), writer_(NULL), waiting_()
+ { }
+
+ ~Task_token()
+ {
+ gold_assert(this->blockers_ == 0);
+ gold_assert(this->writer_ == NULL);
+ }
+
+ // Return whether this is a blocker.
+ bool
+ is_blocker() const
+ { return this->is_blocker_; }
+
+ // A write lock token uses these methods.
+
+ // Is the token writable?
+ bool
+ is_writable() const
+ {
+ gold_assert(!this->is_blocker_);
+ return this->writer_ == NULL;
+ }
+
+ // Add the task as the token's writer (there may only be one
+ // writer).
+ void
+ add_writer(const Task* t)
+ {
+ gold_assert(!this->is_blocker_ && this->writer_ == NULL);
+ this->writer_ = t;
+ }
+
+ // Remove the task as the token's writer.
+ void
+ remove_writer(const Task* t)
+ {
+ gold_assert(!this->is_blocker_ && this->writer_ == t);
+ this->writer_ = NULL;
+ }
+
+ // A blocker token uses these methods.
+
+ // Add a blocker to the token.
+ void
+ add_blocker()
+ {
+ gold_assert(this->is_blocker_);
+ ++this->blockers_;
+ this->writer_ = NULL;
+ }
+
+ // Add some number of blockers to the token.
+ void
+ add_blockers(int c)
+ {
+ gold_assert(this->is_blocker_);
+ this->blockers_ += c;
+ this->writer_ = NULL;
+ }
+
+ // Remove a blocker from the token. Returns true if block count
+ // drops to zero.
+ bool
+ remove_blocker()
+ {
+ gold_assert(this->is_blocker_ && this->blockers_ > 0);
+ --this->blockers_;
+ this->writer_ = NULL;
+ return this->blockers_ == 0;
+ }
+
+ // Is the token currently blocked?
+ bool
+ is_blocked() const
+ {
+ gold_assert(this->is_blocker_);
+ return this->blockers_ > 0;
+ }
+
+ // Both blocker and write lock tokens use these methods.
+
+ // Add T to the list of tasks waiting for this token to be released.
+ void
+ add_waiting(Task* t)
+ { this->waiting_.push_back(t); }
+
+ // Add T to the front of the list of tasks waiting for this token to
+ // be released.
+ void
+ add_waiting_front(Task* t)
+ { this->waiting_.push_front(t); }
+
+ // Remove the first Task waiting for this token to be released, and
+ // return it. Return NULL if no Tasks are waiting.
+ Task*
+ remove_first_waiting()
+ { return this->waiting_.pop_front(); }
+
+ private:
+ // It makes no sense to copy these.
+ Task_token(const Task_token&);
+ Task_token& operator=(const Task_token&);
+
+ // Whether this is a blocker token.
+ bool is_blocker_;
+ // The number of blockers.
+ int blockers_;
+ // The single writer.
+ const Task* writer_;
+ // The list of Tasks waiting for this token to be released.
+ Task_list waiting_;
+};
+
+// In order to support tokens more reliably, we provide objects which
+// handle them using RAII.
+
+// RAII class to get a write lock on a token. This requires
+// specifying the task which is doing the lock.
+
+class Task_write_token
+{
+ public:
+ Task_write_token(Task_token* token, const Task* task)
+ : token_(token), task_(task)
+ { this->token_->add_writer(this->task_); }
+
+ ~Task_write_token()
+ { this->token_->remove_writer(this->task_); }
+
+ private:
+ Task_write_token(const Task_write_token&);
+ Task_write_token& operator=(const Task_write_token&);
+
+ Task_token* token_;
+ const Task* task_;
+};
+
+// RAII class for a blocker.
+
+class Task_block_token
+{
+ public:
+ // The blocker count must be incremented when the task is created.
+ // This object is created when the task is run, so we don't do
+ // anything in the constructor.
+ Task_block_token(Task_token* token)
+ : token_(token)
+ { gold_assert(this->token_->is_blocked()); }
+
+ ~Task_block_token()
+ { this->token_->remove_blocker(); }
+
+ private:
+ Task_block_token(const Task_block_token&);
+ Task_block_token& operator=(const Task_block_token&);
+
+ Task_token* token_;
+};
+
+// An object which implements an RAII lock for any object which
+// supports lock and unlock methods.
+
+template<typename Obj>
+class Task_lock_obj
+{
+ public:
+ Task_lock_obj(const Task* task, Obj* obj)
+ : task_(task), obj_(obj)
+ { this->obj_->lock(task); }
+
+ ~Task_lock_obj()
+ { this->obj_->unlock(this->task_); }
+
+ private:
+ Task_lock_obj(const Task_lock_obj&);
+ Task_lock_obj& operator=(const Task_lock_obj&);
+
+ const Task* task_;
+ Obj* obj_;
+};
+
+// A class which holds the set of Task_tokens which must be locked for
+// a Task. No Task requires more than four Task_tokens, so we set
+// that as a limit.
+
+class Task_locker
+{
+ public:
+ static const int max_task_count = 4;
+
+ Task_locker()
+ : count_(0)
+ { }
+
+ ~Task_locker()
+ { }
+
+ // Clear the locker.
+ void
+ clear()
+ { this->count_ = 0; }
+
+ // Add a token to the locker.
+ void
+ add(Task* t, Task_token* token)
+ {
+ gold_assert(this->count_ < max_task_count);
+ this->tokens_[this->count_] = token;
+ ++this->count_;
+ // A blocker will have been incremented when the task is created.
+ // A writer we need to lock now.
+ if (!token->is_blocker())
+ token->add_writer(t);
+ }
+
+ // Iterate over the tokens.
+
+ typedef Task_token** iterator;
+
+ iterator
+ begin()
+ { return &this->tokens_[0]; }
+
+ iterator
+ end()
+ { return &this->tokens_[this->count_]; }
+
+ private:
+ Task_locker(const Task_locker&);
+ Task_locker& operator=(const Task_locker&);
+
+ // The number of tokens.
+ int count_;
+ // The tokens.
+ Task_token* tokens_[max_task_count];
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_TOKEN_H)
diff --git a/binutils-2.25/gold/version.cc b/binutils-2.25/gold/version.cc
new file mode 100644
index 00000000..37977e5f
--- /dev/null
+++ b/binutils-2.25/gold/version.cc
@@ -0,0 +1,82 @@
+// version.c -- print gold version information
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
+// Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <string>
+#include <cstdio>
+
+#include "../bfd/bfdver.h"
+
+namespace gold
+{
+
+// The version of gold.
+
+// FIXME: This should eventually be PACKAGE_VERSION, and get the
+// version number from configure.ac. But it's easier to just change
+// this file for now.
+
+static const char* version_string = "1.11";
+
+// Report version information.
+
+void
+print_version(bool print_short)
+{
+ // The --version output is intended to follow the GNU coding
+ // standards. We want to print something like:
+ // GNU gold (GNU binutils 2.19) 1.4
+ // BFD_VERSION_STRING looks like "(GNU Binutils) 2.19". We take off
+ // those parentheses.
+ std::string bfd_version(BFD_VERSION_STRING);
+ if (bfd_version[0] == '(')
+ {
+ bfd_version.erase(0, 1);
+ size_t pos = bfd_version.find(')');
+ if (pos != std::string::npos)
+ bfd_version.erase(pos, 1);
+ }
+
+ printf("GNU gold (%s) %s\n", bfd_version.c_str(), version_string);
+
+ if (!print_short)
+ {
+ // This output is intended to follow the GNU standards.
+ printf(_("Copyright 2013 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) a later version.\n\
+This program has absolutely no warranty.\n"));
+ }
+}
+
+// Return the version string.
+
+const char*
+get_version_string()
+{
+ return version_string;
+}
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/workqueue-internal.h b/binutils-2.25/gold/workqueue-internal.h
new file mode 100644
index 00000000..764dc91b
--- /dev/null
+++ b/binutils-2.25/gold/workqueue-internal.h
@@ -0,0 +1,109 @@
+// workqueue-internal.h -- internal work queue header for gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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_WORKQUEUE_INTERNAL_H
+#define GOLD_WORKQUEUE_INTERNAL_H
+
+#include <queue>
+#include <csignal>
+
+#include "gold-threads.h"
+#include "workqueue.h"
+
+// This is an internal header file for different gold workqueue
+// implementations.
+
+namespace gold
+{
+
+class Workqueue_thread;
+
+// The Workqueue_threader abstract class. This is the interface used
+// by the general workqueue code to manage threads.
+
+class Workqueue_threader
+{
+ public:
+ Workqueue_threader(Workqueue* workqueue)
+ : workqueue_(workqueue)
+ { }
+ virtual ~Workqueue_threader()
+ { }
+
+ // Set the number of threads to use. This is ignored when not using
+ // threads.
+ virtual void
+ set_thread_count(int) = 0;
+
+ // Return whether to cancel the current thread.
+ virtual bool
+ should_cancel_thread(int thread_number) = 0;
+
+ protected:
+ // Get the Workqueue.
+ Workqueue*
+ get_workqueue()
+ { return this->workqueue_; }
+
+ private:
+ // The Workqueue.
+ Workqueue* workqueue_;
+};
+
+// The threaded instantiation of Workqueue_threader.
+
+class Workqueue_threader_threadpool : public Workqueue_threader
+{
+ public:
+ Workqueue_threader_threadpool(Workqueue*);
+
+ ~Workqueue_threader_threadpool();
+
+ // Set the thread count.
+ void
+ set_thread_count(int);
+
+ // Return whether to cancel a thread.
+ bool
+ should_cancel_thread(int thread_number);
+
+ // Process all tasks. This keeps running until told to cancel.
+ void
+ process(int thread_number)
+ { this->get_workqueue()->process(thread_number); }
+
+ private:
+ // This is set if we need to check the thread count.
+ volatile sig_atomic_t check_thread_count_;
+
+ // Lock for the remaining members.
+ Lock lock_;
+ // The number of threads we want to create. This is set to zero
+ // when all threads should exit.
+ int desired_thread_count_;
+ // The number of threads currently running.
+ int threads_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_WORKQUEUE_INTERNAL_H)
diff --git a/binutils-2.25/gold/workqueue-threads.cc b/binutils-2.25/gold/workqueue-threads.cc
new file mode 100644
index 00000000..de2ce5be
--- /dev/null
+++ b/binutils-2.25/gold/workqueue-threads.cc
@@ -0,0 +1,199 @@
+// workqueue-threads.cc -- the threaded workqueue for gold
+
+// Copyright 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 holds the workqueue implementation which may be used when
+// using threads.
+
+#include "gold.h"
+
+#ifdef ENABLE_THREADS
+
+#include <cstring>
+#include <pthread.h>
+
+#include "debug.h"
+#include "gold-threads.h"
+#include "workqueue.h"
+#include "workqueue-internal.h"
+
+namespace gold
+{
+
+// Class Workqueue_thread represents a single thread. Creating an
+// instance of this spawns a new thread.
+
+class Workqueue_thread
+{
+ public:
+ Workqueue_thread(Workqueue_threader_threadpool*, int thread_number);
+
+ ~Workqueue_thread();
+
+ private:
+ // This class can not be copied.
+ Workqueue_thread(const Workqueue_thread&);
+ Workqueue_thread& operator=(const Workqueue_thread&);
+
+ // Check for error from a pthread function.
+ void
+ check(const char* function, int err) const;
+
+ // A function to pass to pthread_create. This is called with a
+ // pointer to an instance of this object.
+ static void*
+ thread_body(void*);
+
+ // A pointer to the threadpool that this thread is part of.
+ Workqueue_threader_threadpool* threadpool_;
+ // The thread number.
+ int thread_number_;
+ // The thread ID.
+ pthread_t tid_;
+};
+
+// Create the thread in the constructor.
+
+Workqueue_thread::Workqueue_thread(Workqueue_threader_threadpool* threadpool,
+ int thread_number)
+ : threadpool_(threadpool), thread_number_(thread_number)
+{
+ pthread_attr_t attr;
+ int err = pthread_attr_init(&attr);
+ this->check("pthread_attr_init", err);
+
+ err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ this->check("pthread_attr_setdetachstate", err);
+
+ err = pthread_create(&this->tid_, &attr, &Workqueue_thread::thread_body,
+ reinterpret_cast<void*>(this));
+ this->check("pthread_create", err);
+
+ err = pthread_attr_destroy(&attr);
+ this->check("pthread_attr_destroy", err);
+}
+
+// The destructor will be called when the thread is exiting.
+
+Workqueue_thread::~Workqueue_thread()
+{
+}
+
+// Check for an error.
+
+void
+Workqueue_thread::check(const char* function, int err) const
+{
+ if (err != 0)
+ gold_fatal(_("%s failed: %s"), function, strerror(err));
+}
+
+// Passed to pthread_create.
+
+extern "C"
+void*
+Workqueue_thread::thread_body(void* arg)
+{
+ Workqueue_thread* pwt = reinterpret_cast<Workqueue_thread*>(arg);
+
+ pwt->threadpool_->process(pwt->thread_number_);
+
+ // Delete the thread object as we exit.
+ delete pwt;
+
+ return NULL;
+}
+
+// Class Workqueue_threader_threadpool.
+
+// Constructor.
+
+Workqueue_threader_threadpool::Workqueue_threader_threadpool(
+ Workqueue* workqueue)
+ : Workqueue_threader(workqueue),
+ check_thread_count_(0),
+ lock_(),
+ desired_thread_count_(1),
+ threads_(1)
+{
+}
+
+// Destructor.
+
+Workqueue_threader_threadpool::~Workqueue_threader_threadpool()
+{
+ // Tell the threads to exit.
+ this->get_workqueue()->set_thread_count(0);
+}
+
+// Set the thread count.
+
+void
+Workqueue_threader_threadpool::set_thread_count(int thread_count)
+{
+ int create;
+ {
+ Hold_lock hl(this->lock_);
+
+ this->desired_thread_count_ = thread_count;
+ create = this->desired_thread_count_ - this->threads_;
+ if (create < 0)
+ this->check_thread_count_ = 1;
+ }
+
+ if (create > 0)
+ {
+ for (int i = 0; i < create; ++i)
+ {
+ // Note that threads delete themselves when they exit, so we
+ // don't keep pointers to them.
+ new Workqueue_thread(this, this->threads_);
+ ++this->threads_;
+ }
+ }
+}
+
+// Return whether the current thread should be cancelled.
+
+bool
+Workqueue_threader_threadpool::should_cancel_thread(int thread_number)
+{
+ // Fast exit without taking a lock.
+ if (!this->check_thread_count_)
+ return false;
+
+ {
+ Hold_lock hl(this->lock_);
+ if (thread_number > this->desired_thread_count_)
+ {
+ --this->threads_;
+ if (this->threads_ <= this->desired_thread_count_)
+ this->check_thread_count_ = 0;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // End namespace gold.
+
+#endif // defined(ENABLE_THREADS)
diff --git a/binutils-2.25/gold/workqueue.cc b/binutils-2.25/gold/workqueue.cc
new file mode 100644
index 00000000..e78e86b9
--- /dev/null
+++ b/binutils-2.25/gold/workqueue.cc
@@ -0,0 +1,521 @@
+// workqueue.cc -- the workqueue for gold
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 "debug.h"
+#include "options.h"
+#include "timer.h"
+#include "workqueue.h"
+#include "workqueue-internal.h"
+
+namespace gold
+{
+
+// Class Task_list.
+
+// Add T to the end of the list.
+
+inline void
+Task_list::push_back(Task* t)
+{
+ gold_assert(t->list_next() == NULL);
+ if (this->head_ == NULL)
+ {
+ this->head_ = t;
+ this->tail_ = t;
+ }
+ else
+ {
+ this->tail_->set_list_next(t);
+ this->tail_ = t;
+ }
+}
+
+// Add T to the front of the list.
+
+inline void
+Task_list::push_front(Task* t)
+{
+ gold_assert(t->list_next() == NULL);
+ if (this->head_ == NULL)
+ {
+ this->head_ = t;
+ this->tail_ = t;
+ }
+ else
+ {
+ t->set_list_next(this->head_);
+ this->head_ = t;
+ }
+}
+
+// Remove and return the first Task waiting for this lock to be
+// released.
+
+inline Task*
+Task_list::pop_front()
+{
+ Task* ret = this->head_;
+ if (ret != NULL)
+ {
+ if (ret == this->tail_)
+ {
+ gold_assert(ret->list_next() == NULL);
+ this->head_ = NULL;
+ this->tail_ = NULL;
+ }
+ else
+ {
+ this->head_ = ret->list_next();
+ gold_assert(this->head_ != NULL);
+ ret->clear_list_next();
+ }
+ }
+ return ret;
+}
+
+// The simple single-threaded implementation of Workqueue_threader.
+
+class Workqueue_threader_single : public Workqueue_threader
+{
+ public:
+ Workqueue_threader_single(Workqueue* workqueue)
+ : Workqueue_threader(workqueue)
+ { }
+ ~Workqueue_threader_single()
+ { }
+
+ void
+ set_thread_count(int thread_count)
+ { gold_assert(thread_count > 0); }
+
+ bool
+ should_cancel_thread(int)
+ { return false; }
+};
+
+// Workqueue methods.
+
+Workqueue::Workqueue(const General_options& options)
+ : lock_(),
+ first_tasks_(),
+ tasks_(),
+ running_(0),
+ waiting_(0),
+ condvar_(this->lock_),
+ threader_(NULL)
+{
+ bool threads = options.threads();
+#ifndef ENABLE_THREADS
+ threads = false;
+#endif
+ if (!threads)
+ this->threader_ = new Workqueue_threader_single(this);
+ else
+ {
+#ifdef ENABLE_THREADS
+ this->threader_ = new Workqueue_threader_threadpool(this);
+#else
+ gold_unreachable();
+#endif
+ }
+}
+
+Workqueue::~Workqueue()
+{
+}
+
+// Add a task to the end of a specific queue, or put it on the list
+// waiting for a Token.
+
+void
+Workqueue::add_to_queue(Task_list* queue, Task* t, bool front)
+{
+ Hold_lock hl(this->lock_);
+
+ Task_token* token = t->is_runnable();
+ if (token != NULL)
+ {
+ if (front)
+ token->add_waiting_front(t);
+ else
+ token->add_waiting(t);
+ ++this->waiting_;
+ }
+ else
+ {
+ if (front)
+ queue->push_front(t);
+ else
+ queue->push_back(t);
+ // Tell any waiting thread that there is work to do.
+ this->condvar_.signal();
+ }
+}
+
+// Add a task to the queue.
+
+void
+Workqueue::queue(Task* t)
+{
+ this->add_to_queue(&this->tasks_, t, false);
+}
+
+// Queue a task which should run soon.
+
+void
+Workqueue::queue_soon(Task* t)
+{
+ t->set_should_run_soon();
+ this->add_to_queue(&this->first_tasks_, t, false);
+}
+
+// Queue a task which should run next.
+
+void
+Workqueue::queue_next(Task* t)
+{
+ t->set_should_run_soon();
+ this->add_to_queue(&this->first_tasks_, t, true);
+}
+
+// Return whether to cancel the current thread.
+
+inline bool
+Workqueue::should_cancel_thread(int thread_number)
+{
+ return this->threader_->should_cancel_thread(thread_number);
+}
+
+// Find a runnable task in TASKS. Return NULL if none could be found.
+// If we find a Task waiting for a Token, add it to the list for that
+// Token. The workqueue lock must be held when this is called.
+
+Task*
+Workqueue::find_runnable_in_list(Task_list* tasks)
+{
+ Task* t;
+ while ((t = tasks->pop_front()) != NULL)
+ {
+ Task_token* token = t->is_runnable();
+
+ if (token == NULL)
+ return t;
+
+ token->add_waiting(t);
+ ++this->waiting_;
+ }
+
+ // We couldn't find any runnable task.
+ return NULL;
+}
+
+// Find a runnable task. Return NULL if none could be found. The
+// workqueue lock must be held when this is called.
+
+Task*
+Workqueue::find_runnable()
+{
+ Task* t = this->find_runnable_in_list(&this->first_tasks_);
+ if (t == NULL)
+ t = this->find_runnable_in_list(&this->tasks_);
+ return t;
+}
+
+// Find a runnable a task, and wait until we find one. Return NULL if
+// we should exit. The workqueue lock must be held when this is
+// called.
+
+Task*
+Workqueue::find_runnable_or_wait(int thread_number)
+{
+ Task* t = this->find_runnable();
+
+ while (t == NULL)
+ {
+ if (this->running_ == 0
+ && this->first_tasks_.empty()
+ && this->tasks_.empty())
+ {
+ // Kick all the threads to make them exit.
+ this->condvar_.broadcast();
+
+ gold_assert(this->waiting_ == 0);
+ return NULL;
+ }
+
+ if (this->should_cancel_thread(thread_number))
+ return NULL;
+
+ gold_debug(DEBUG_TASK, "%3d sleeping", thread_number);
+
+ this->condvar_.wait();
+
+ gold_debug(DEBUG_TASK, "%3d awake", thread_number);
+
+ t = this->find_runnable();
+ }
+
+ return t;
+}
+
+// Find and run tasks. If we can't find a runnable task, wait for one
+// to become available. If we run a task, and it frees up another
+// runnable task, then run that one too. This returns true if we
+// should look for another task, false if we are cancelling this
+// thread.
+
+bool
+Workqueue::find_and_run_task(int thread_number)
+{
+ Task* t;
+ Task_locker tl;
+
+ {
+ Hold_lock hl(this->lock_);
+
+ // Find a runnable task.
+ t = this->find_runnable_or_wait(thread_number);
+
+ if (t == NULL)
+ return false;
+
+ // Get the locks for the task. This must be called while we are
+ // still holding the Workqueue lock.
+ t->locks(&tl);
+
+ ++this->running_;
+ }
+
+ while (t != NULL)
+ {
+ gold_debug(DEBUG_TASK, "%3d running task %s", thread_number,
+ t->name().c_str());
+
+ Timer timer;
+ if (is_debugging_enabled(DEBUG_TASK))
+ timer.start();
+
+ t->run(this);
+
+ if (is_debugging_enabled(DEBUG_TASK))
+ {
+ Timer::TimeStats elapsed = timer.get_elapsed_time();
+
+ gold_debug(DEBUG_TASK,
+ "%3d completed task %s "
+ "(user: %ld.%06ld sys: %ld.%06ld wall: %ld.%06ld)",
+ thread_number, t->name().c_str(),
+ elapsed.user / 1000, (elapsed.user % 1000) * 1000,
+ elapsed.sys / 1000, (elapsed.sys % 1000) * 1000,
+ elapsed.wall / 1000, (elapsed.wall % 1000) * 1000);
+ }
+
+ Task* next;
+ {
+ Hold_lock hl(this->lock_);
+
+ --this->running_;
+
+ // Release the locks for the task. This must be done with the
+ // workqueue lock held. Get the next Task to run if any.
+ next = this->release_locks(t, &tl);
+
+ if (next == NULL)
+ next = this->find_runnable();
+
+ // If we have another Task to run, get the Locks. This must
+ // be called while we are still holding the Workqueue lock.
+ if (next != NULL)
+ {
+ tl.clear();
+ next->locks(&tl);
+
+ ++this->running_;
+ }
+ }
+
+ // We are done with this task.
+ delete t;
+
+ t = next;
+ }
+
+ return true;
+}
+
+// Handle the return value of release_locks, and get tasks ready to
+// run.
+
+// 1) If T is not runnable, queue it on the appropriate token.
+
+// 2) Otherwise, T is runnable. If *PRET is not NULL, then we have
+// already decided which Task to run next. Add T to the list of
+// runnable tasks, and signal another thread.
+
+// 3) Otherwise, *PRET is NULL. If IS_BLOCKER is false, then T was
+// waiting on a write lock. We can grab that lock now, so we run T
+// now.
+
+// 4) Otherwise, IS_BLOCKER is true. If we should run T soon, then
+// run it now.
+
+// 5) Otherwise, check whether there are other tasks to run. If there
+// are, then we generally get a better ordering if we run those tasks
+// now, before T. A typical example is tasks waiting on the Dirsearch
+// blocker. We don't want to run those tasks right away just because
+// the Dirsearch was unblocked.
+
+// 6) Otherwise, there are no other tasks to run, so we might as well
+// run this one now.
+
+// This function must be called with the Workqueue lock held.
+
+// Return true if we set *PRET to T, false otherwise.
+
+bool
+Workqueue::return_or_queue(Task* t, bool is_blocker, Task** pret)
+{
+ Task_token* token = t->is_runnable();
+
+ if (token != NULL)
+ {
+ token->add_waiting(t);
+ ++this->waiting_;
+ return false;
+ }
+
+ bool should_queue = false;
+ bool should_return = false;
+
+ if (*pret != NULL)
+ should_queue = true;
+ else if (!is_blocker)
+ should_return = true;
+ else if (t->should_run_soon())
+ should_return = true;
+ else if (!this->first_tasks_.empty() || !this->tasks_.empty())
+ should_queue = true;
+ else
+ should_return = true;
+
+ if (should_return)
+ {
+ gold_assert(*pret == NULL);
+ *pret = t;
+ return true;
+ }
+ else if (should_queue)
+ {
+ if (t->should_run_soon())
+ this->first_tasks_.push_back(t);
+ else
+ this->tasks_.push_back(t);
+ this->condvar_.signal();
+ return false;
+ }
+
+ gold_unreachable();
+}
+
+// Release the locks associated with a Task. Return the first
+// runnable Task that we find. If we find more runnable tasks, add
+// them to the run queue and signal any other threads. This must be
+// called with the Workqueue lock held.
+
+Task*
+Workqueue::release_locks(Task* t, Task_locker* tl)
+{
+ Task* ret = NULL;
+ for (Task_locker::iterator p = tl->begin(); p != tl->end(); ++p)
+ {
+ Task_token* token = *p;
+ if (token->is_blocker())
+ {
+ if (token->remove_blocker())
+ {
+ // The token has been unblocked. Every waiting Task may
+ // now be runnable.
+ Task* t;
+ while ((t = token->remove_first_waiting()) != NULL)
+ {
+ --this->waiting_;
+ this->return_or_queue(t, true, &ret);
+ }
+ }
+ }
+ else
+ {
+ token->remove_writer(t);
+
+ // One more waiting Task may now be runnable. If we are
+ // going to run it next, we can stop. Otherwise we need to
+ // move all the Tasks to the runnable queue, to avoid a
+ // potential deadlock if the locking status changes before
+ // we run the next thread.
+ Task* t;
+ while ((t = token->remove_first_waiting()) != NULL)
+ {
+ --this->waiting_;
+ if (this->return_or_queue(t, false, &ret))
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+// Process all the tasks on the workqueue. Keep going until the
+// workqueue is empty, or until we have been told to exit. This
+// function is called by all threads.
+
+void
+Workqueue::process(int thread_number)
+{
+ while (this->find_and_run_task(thread_number))
+ ;
+}
+
+// Set the number of threads to use for the workqueue, if we are using
+// threads.
+
+void
+Workqueue::set_thread_count(int threads)
+{
+ Hold_lock hl(this->lock_);
+
+ this->threader_->set_thread_count(threads);
+ // Wake up all the threads, since something has changed.
+ this->condvar_.broadcast();
+}
+
+// Add a new blocker to an existing Task_token.
+
+void
+Workqueue::add_blocker(Task_token* token)
+{
+ Hold_lock hl(this->lock_);
+ token->add_blocker();
+}
+
+} // End namespace gold.
diff --git a/binutils-2.25/gold/workqueue.h b/binutils-2.25/gold/workqueue.h
new file mode 100644
index 00000000..424b5e78
--- /dev/null
+++ b/binutils-2.25/gold/workqueue.h
@@ -0,0 +1,295 @@
+// workqueue.h -- the work queue for gold -*- C++ -*-
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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.
+
+// After processing the command line, everything the linker does is
+// driven from a work queue. This permits us to parallelize the
+// linker where possible.
+
+#ifndef GOLD_WORKQUEUE_H
+#define GOLD_WORKQUEUE_H
+
+#include <string>
+
+#include "gold-threads.h"
+#include "token.h"
+
+namespace gold
+{
+
+class General_options;
+class Workqueue;
+
+// The superclass for tasks to be placed on the workqueue. Each
+// specific task class will inherit from this one.
+
+class Task
+{
+ public:
+ Task()
+ : list_next_(NULL), name_(), should_run_soon_(false)
+ { }
+ virtual ~Task()
+ { }
+
+ // Check whether the Task can be run now. This method is only
+ // called with the workqueue lock held. If the Task can run, this
+ // returns NULL. Otherwise it returns a pointer to a token which
+ // must be released before the Task can run.
+ virtual Task_token*
+ is_runnable() = 0;
+
+ // Lock all the resources required by the Task, and store the locks
+ // in a Task_locker. This method does not need to do anything if no
+ // locks are required. This method is only called with the
+ // workqueue lock held.
+ virtual void
+ locks(Task_locker*) = 0;
+
+ // Run the task.
+ virtual void
+ run(Workqueue*) = 0;
+
+ // Return whether this task should run soon.
+ bool
+ should_run_soon() const
+ { return this->should_run_soon_; }
+
+ // Note that this task should run soon.
+ void
+ set_should_run_soon()
+ { this->should_run_soon_ = true; }
+
+ // Get the next Task on the list of Tasks. Called by Task_list.
+ Task*
+ list_next() const
+ { return this->list_next_; }
+
+ // Set the next Task on the list of Tasks. Called by Task_list.
+ void
+ set_list_next(Task* t)
+ {
+ gold_assert(this->list_next_ == NULL);
+ this->list_next_ = t;
+ }
+
+ // Clear the next Task on the list of Tasks. Called by Task_list.
+ void
+ clear_list_next()
+ { this->list_next_ = NULL; }
+
+ // Return the name of the Task. This is only used for debugging
+ // purposes.
+ const std::string&
+ name()
+ {
+ if (this->name_.empty())
+ this->name_ = this->get_name();
+ return this->name_;
+ }
+
+ protected:
+ // Get the name of the task. This must be implemented by the child
+ // class.
+ virtual std::string
+ get_name() const = 0;
+
+ private:
+ // Tasks may not be copied.
+ Task(const Task&);
+ Task& operator=(const Task&);
+
+ // If this Task is on a list, this is a pointer to the next Task on
+ // the list. We use this simple list structure rather than building
+ // a container, in order to avoid memory allocation while holding
+ // the Workqueue lock.
+ Task* list_next_;
+ // Task name, for debugging purposes.
+ std::string name_;
+ // Whether this Task should be executed soon. This is used for
+ // Tasks which can be run after some data is read.
+ bool should_run_soon_;
+};
+
+// An interface for Task_function. This is a convenience class to run
+// a single function.
+
+class Task_function_runner
+{
+ public:
+ virtual ~Task_function_runner()
+ { }
+
+ virtual void
+ run(Workqueue*, const Task*) = 0;
+};
+
+// A simple task which waits for a blocker and then runs a function.
+
+class Task_function : public Task
+{
+ public:
+ // RUNNER and BLOCKER should be allocated using new, and will be
+ // deleted after the task runs.
+ Task_function(Task_function_runner* runner, Task_token* blocker,
+ const char* name)
+ : runner_(runner), blocker_(blocker), name_(name)
+ { gold_assert(blocker != NULL); }
+
+ ~Task_function()
+ {
+ delete this->runner_;
+ delete this->blocker_;
+ }
+
+ // The standard task methods.
+
+ // Wait until the task is unblocked.
+ Task_token*
+ is_runnable()
+ { return this->blocker_->is_blocked() ? this->blocker_ : NULL; }
+
+ // This type of task does not normally hold any locks.
+ virtual void
+ locks(Task_locker*)
+ { }
+
+ // Run the action.
+ void
+ run(Workqueue* workqueue)
+ { this->runner_->run(workqueue, this); }
+
+ // The debugging name.
+ std::string
+ get_name() const
+ { return this->name_; }
+
+ private:
+ Task_function(const Task_function&);
+ Task_function& operator=(const Task_function&);
+
+ Task_function_runner* runner_;
+ Task_token* blocker_;
+ const char* name_;
+};
+
+// The workqueue itself.
+
+class Workqueue_threader;
+
+class Workqueue
+{
+ public:
+ Workqueue(const General_options&);
+ ~Workqueue();
+
+ // Add a new task to the work queue.
+ void
+ queue(Task*);
+
+ // Add a new task to the work queue which should run soon. If the
+ // task is ready, it will be run before any tasks added using
+ // queue().
+ void
+ queue_soon(Task*);
+
+ // Add a new task to the work queue which should run next if it is
+ // ready.
+ void
+ queue_next(Task*);
+
+ // Process all the tasks on the work queue. This function runs
+ // until all tasks have completed. The argument is the thread
+ // number, used only for debugging.
+ void
+ process(int);
+
+ // Set the desired thread count--the number of threads we want to
+ // have running.
+ void
+ set_thread_count(int);
+
+ // Add a new blocker to an existing Task_token. This must be done
+ // with the workqueue lock held. This should not be done routinely,
+ // only in special circumstances.
+ void
+ add_blocker(Task_token*);
+
+ private:
+ // This class can not be copied.
+ Workqueue(const Workqueue&);
+ Workqueue& operator=(const Workqueue&);
+
+ // Add a task to a queue.
+ void
+ add_to_queue(Task_list* queue, Task* t, bool front);
+
+ // Find a runnable task, or wait for one.
+ Task*
+ find_runnable_or_wait(int thread_number);
+
+ // Find a runnable task.
+ Task*
+ find_runnable();
+
+ // Find a runnable task in a list.
+ Task*
+ find_runnable_in_list(Task_list*);
+
+ // Find an run a task.
+ bool
+ find_and_run_task(int);
+
+ // Release the locks for a Task. Return the next Task to run.
+ Task*
+ release_locks(Task*, Task_locker*);
+
+ // Store T into *PRET, or queue it as appropriate.
+ bool
+ return_or_queue(Task* t, bool is_blocker, Task** pret);
+
+ // Return whether to cancel this thread.
+ bool
+ should_cancel_thread(int thread_number);
+
+ // Master Workqueue lock. This controls access to the following
+ // member variables.
+ Lock lock_;
+ // List of tasks to execute soon.
+ Task_list first_tasks_;
+ // List of tasks to execute after the ones in first_tasks_.
+ Task_list tasks_;
+ // Number of tasks currently running.
+ int running_;
+ // Number of tasks waiting for a lock to release.
+ int waiting_;
+ // Condition variable associated with lock_. This is signalled when
+ // there may be a new Task to execute.
+ Condvar condvar_;
+
+ // The threading implementation. This is set at construction time
+ // and not changed thereafter.
+ Workqueue_threader* threader_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_WORKQUEUE_H)
diff --git a/binutils-2.25/gold/x86_64.cc b/binutils-2.25/gold/x86_64.cc
new file mode 100644
index 00000000..b95d2ed8
--- /dev/null
+++ b/binutils-2.25/gold/x86_64.cc
@@ -0,0 +1,4836 @@
+// x86_64.cc -- x86_64 target support for gold.
+
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
+// Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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 <cstring>
+
+#include "elfcpp.h"
+#include "dwarf.h"
+#include "parameters.h"
+#include "reloc.h"
+#include "x86_64.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"
+#include "icf.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.
+
+template<int size>
+class Output_data_plt_x86_64 : public Output_section_data
+{
+ public:
+ typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, false> Reloc_section;
+
+ Output_data_plt_x86_64(Layout* layout, uint64_t addralign,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_section_data(addralign), layout_(layout), tlsdesc_rel_(NULL),
+ irelative_rel_(NULL), got_(got), got_plt_(got_plt),
+ got_irelative_(got_irelative), count_(0), irelative_count_(0),
+ tlsdesc_got_offset_(-1U), free_list_()
+ { this->init(layout); }
+
+ Output_data_plt_x86_64(Layout* layout, uint64_t plt_entry_size,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ : Output_section_data((plt_count + 1) * plt_entry_size,
+ plt_entry_size, false),
+ layout_(layout), tlsdesc_rel_(NULL), irelative_rel_(NULL), got_(got),
+ got_plt_(got_plt), got_irelative_(got_irelative), count_(plt_count),
+ irelative_count_(0), tlsdesc_got_offset_(-1U), free_list_()
+ {
+ this->init(layout);
+
+ // Initialize the free list and reserve the first entry.
+ this->free_list_.init((plt_count + 1) * plt_entry_size, false);
+ this->free_list_.remove(0, plt_entry_size);
+ }
+
+ // Initialize the PLT section.
+ void
+ init(Layout* layout);
+
+ // 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* symtab, Layout*,
+ Sized_relobj_file<size, false>* relobj,
+ unsigned int local_sym_index);
+
+ // Add the relocation for a PLT entry.
+ void
+ add_relocation(Symbol_table*, Layout*, Symbol* gsym,
+ unsigned int got_offset);
+
+ // Add the reserved TLSDESC_PLT entry to the PLT.
+ void
+ reserve_tlsdesc_entry(unsigned int got_offset)
+ { this->tlsdesc_got_offset_ = got_offset; }
+
+ // Return true if a TLSDESC_PLT entry has been reserved.
+ bool
+ has_tlsdesc_entry() const
+ { return this->tlsdesc_got_offset_ != -1U; }
+
+ // Return the GOT offset for the reserved TLSDESC_PLT entry.
+ unsigned int
+ get_tlsdesc_got_offset() const
+ { return this->tlsdesc_got_offset_; }
+
+ // Return the offset of the reserved TLSDESC_PLT entry.
+ unsigned int
+ get_tlsdesc_plt_offset() const
+ {
+ return ((this->count_ + this->irelative_count_ + 1)
+ * this->get_plt_entry_size());
+ }
+
+ // Return the .rela.plt section data.
+ Reloc_section*
+ rela_plt()
+ { return this->rel_; }
+
+ // Return where the TLSDESC relocations should go.
+ Reloc_section*
+ rela_tlsdesc(Layout*);
+
+ // Return where the IRELATIVE relocations should go in the PLT
+ // relocations.
+ Reloc_section*
+ rela_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(); }
+
+ // Reserve a slot in the PLT for an existing symbol in an incremental update.
+ void
+ reserve_slot(unsigned int plt_index)
+ {
+ this->free_list_.remove((plt_index + 1) * this->get_plt_entry_size(),
+ (plt_index + 2) * this->get_plt_entry_size());
+ }
+
+ // Return the PLT address to use for a global symbol.
+ uint64_t
+ address_for_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 in the first PLT entry.
+ void
+ fill_first_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address)
+ { this->do_fill_first_plt_entry(pov, got_address, plt_address); }
+
+ // Fill in a normal PLT entry. Returns the offset into the entry that
+ // should be the initial GOT slot value.
+ unsigned int
+ fill_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index)
+ {
+ return this->do_fill_plt_entry(pov, got_address, plt_address,
+ got_offset, plt_offset, plt_index);
+ }
+
+ // Fill in the reserved TLSDESC PLT entry.
+ void
+ fill_tlsdesc_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset)
+ {
+ this->do_fill_tlsdesc_entry(pov, got_address, plt_address, got_base,
+ tlsdesc_got_offset, plt_offset);
+ }
+
+ virtual unsigned int
+ do_get_plt_entry_size() const = 0;
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_addr,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_addr)
+ = 0;
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index) = 0;
+
+ virtual void
+ do_fill_tlsdesc_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset) = 0;
+
+ virtual void
+ do_add_eh_frame(Layout* layout) = 0;
+
+ void
+ do_adjust_output_section(Output_section* os);
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** PLT")); }
+
+ // The CIE of the .eh_frame unwind information for the PLT.
+ 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();
+
+ // Write out the PLT data.
+ void
+ do_write(Output_file*);
+
+ // 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 TLSDESC relocs, if necessary. These must follow the regular
+ // PLT relocs.
+ Reloc_section* tlsdesc_rel_;
+ // The IRELATIVE relocs, if necessary. These must follow the
+ // regular PLT relocations and the TLSDESC relocations.
+ Reloc_section* irelative_rel_;
+ // The .got section.
+ Output_data_got<64, false>* got_;
+ // 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_X86_64_IRELATIVE relocs. These
+ // follow the regular PLT entries.
+ unsigned int irelative_count_;
+ // Offset of the reserved TLSDESC_GOT entry when needed.
+ unsigned int tlsdesc_got_offset_;
+ // List of available regions within the section, for incremental
+ // update links.
+ Free_list free_list_;
+};
+
+template<int size>
+class Output_data_plt_x86_64_standard : public Output_data_plt_x86_64<size>
+{
+ public:
+ Output_data_plt_x86_64_standard(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_x86_64<size>(layout, plt_entry_size,
+ got, got_plt, got_irelative)
+ { }
+
+ Output_data_plt_x86_64_standard(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ : Output_data_plt_x86_64<size>(layout, plt_entry_size,
+ got, got_plt, got_irelative,
+ plt_count)
+ { }
+
+ protected:
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return plt_entry_size; }
+
+ virtual void
+ do_add_eh_frame(Layout* layout)
+ {
+ layout->add_eh_frame_for_plt(this,
+ this->plt_eh_frame_cie,
+ this->plt_eh_frame_cie_size,
+ plt_eh_frame_fde,
+ plt_eh_frame_fde_size);
+ }
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_addr,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_addr);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index);
+
+ virtual void
+ do_fill_tlsdesc_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset);
+
+ private:
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 16;
+
+ // The first entry in the PLT.
+ // From the AMD64 ABI: "Unlike Intel386 ABI, this ABI uses the same
+ // procedure linkage table for both programs and shared objects."
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for an executable.
+ static const unsigned char plt_entry[plt_entry_size];
+
+ // The reserved TLSDESC entry in the PLT for an executable.
+ static const unsigned char tlsdesc_plt_entry[plt_entry_size];
+
+ // The .eh_frame unwind information for the PLT.
+ static const int plt_eh_frame_fde_size = 32;
+ static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+};
+
+// The x86_64 target class.
+// See the ABI at
+// http://www.x86-64.org/documentation/abi.pdf
+// TLS info comes from
+// http://people.redhat.com/drepper/tls.pdf
+// http://www.lsd.ic.unicamp.br/~oliva/writeups/TLS/RFC-TLSDESC-x86.txt
+
+template<int size>
+class Target_x86_64 : public Sized_target<size, false>
+{
+ public:
+ // In the x86_64 ABI (p 68), it says "The AMD64 ABI architectures
+ // uses only Elf64_Rela relocation entries with explicit addends."
+ typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, false> Reloc_section;
+
+ Target_x86_64(const Target::Target_info* info = &x86_64_info)
+ : Sized_target<size, false>(info),
+ got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
+ got_tlsdesc_(NULL), global_offset_table_(NULL), rela_dyn_(NULL),
+ rela_irelative_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY),
+ got_mod_index_offset_(-1U), tlsdesc_reloc_info_(),
+ tls_base_symbol_defined_(false)
+ { }
+
+ // Hook for a new output section.
+ void
+ do_new_output_section(Output_section*) const;
+
+ // Scan the relocations to look for symbol adjustments.
+ void
+ gc_process_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols);
+
+ // Scan the relocations to look for symbol adjustments.
+ void
+ scan_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols);
+
+ // 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<size, 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,
+ typename elfcpp::Elf_types<size>::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<size, false>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols,
+ Relocatable_relocs*);
+
+ // Emit relocations for a section.
+ void
+ relocate_relocs(
+ const Relocate_info<size, false>*,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
+ const Relocatable_relocs*,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::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 the symbol index to use for a target specific relocation.
+ // The only target specific relocation is R_X86_64_TLSDESC for a
+ // local symbol, which is an absolute reloc.
+ unsigned int
+ do_reloc_symbol_index(void*, unsigned int r_type) const
+ {
+ gold_assert(r_type == elfcpp::R_X86_64_TLSDESC);
+ return 0;
+ }
+
+ // Return the addend to use for a target specific relocation.
+ uint64_t
+ do_reloc_addend(void* arg, unsigned int r_type, uint64_t addend) const;
+
+ // Return the PLT section.
+ 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); }
+
+ // This function should be defined in targets that can use relocation
+ // types to determine (implemented in local_reloc_may_be_function_pointer
+ // and global_reloc_may_be_function_pointer)
+ // if a function's pointer is taken. ICF uses this in safe mode to only
+ // fold those functions whose pointer is defintely not taken. For x86_64
+ // pie binaries, safe ICF cannot be done by looking at relocation types.
+ bool
+ do_can_check_for_function_pointers() const
+ { return !parameters->options().pie(); }
+
+ // Return the base for a DW_EH_PE_datarel encoding.
+ uint64_t
+ do_ehframe_datarel_base() 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() / 8;
+ }
+
+ // 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;
+
+ // Create the GOT section for an incremental update.
+ Output_data_got_base*
+ init_got_plt_for_update(Symbol_table* symtab,
+ Layout* layout,
+ unsigned int got_count,
+ unsigned int plt_count);
+
+ // Reserve a GOT entry for a local symbol, and regenerate any
+ // necessary dynamic relocations.
+ void
+ reserve_local_got_entry(unsigned int got_index,
+ Sized_relobj<size, false>* obj,
+ unsigned int r_sym,
+ unsigned int got_type);
+
+ // Reserve a GOT entry for a global symbol, and regenerate any
+ // necessary dynamic relocations.
+ void
+ reserve_global_got_entry(unsigned int got_index, Symbol* gsym,
+ unsigned int got_type);
+
+ // Register an existing PLT entry for a global symbol.
+ void
+ register_global_plt_entry(Symbol_table*, Layout*, unsigned int plt_index,
+ Symbol* gsym);
+
+ // Force a COPY relocation for a given symbol.
+ void
+ emit_copy_reloc(Symbol_table*, Symbol*, Output_section*, off_t);
+
+ // Apply an incremental relocation.
+ void
+ apply_relocation(const Relocate_info<size, false>* relinfo,
+ typename elfcpp::Elf_types<size>::Elf_Addr r_offset,
+ unsigned int r_type,
+ typename elfcpp::Elf_types<size>::Elf_Swxword r_addend,
+ const Symbol* gsym,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size);
+
+ // Add a new reloc argument, returning the index in the vector.
+ size_t
+ add_tlsdesc_info(Sized_relobj_file<size, false>* object, unsigned int r_sym)
+ {
+ this->tlsdesc_reloc_info_.push_back(Tlsdesc_info(object, r_sym));
+ return this->tlsdesc_reloc_info_.size() - 1;
+ }
+
+ Output_data_plt_x86_64<size>*
+ make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ {
+ return this->do_make_data_plt(layout, got, got_plt, got_irelative);
+ }
+
+ Output_data_plt_x86_64<size>*
+ make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ {
+ return this->do_make_data_plt(layout, got, got_plt, got_irelative,
+ plt_count);
+ }
+
+ virtual Output_data_plt_x86_64<size>*
+ do_make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ {
+ return new Output_data_plt_x86_64_standard<size>(layout, got, got_plt,
+ got_irelative);
+ }
+
+ virtual Output_data_plt_x86_64<size>*
+ do_make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ {
+ return new Output_data_plt_x86_64_standard<size>(layout, got, got_plt,
+ got_irelative,
+ plt_count);
+ }
+
+ private:
+ // The class which scans relocations.
+ class Scan
+ {
+ 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_x86_64* target,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, false>& reloc, unsigned int r_type,
+ const elfcpp::Sym<size, false>& lsym,
+ bool is_discarded);
+
+ inline void
+ global(Symbol_table* symtab, Layout* layout, Target_x86_64* target,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, false>& reloc, unsigned int r_type,
+ Symbol* gsym);
+
+ inline bool
+ local_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
+ Target_x86_64* target,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, false>& reloc,
+ unsigned int r_type,
+ const elfcpp::Sym<size, false>& lsym);
+
+ inline bool
+ global_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
+ Target_x86_64* target,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, false>& reloc,
+ unsigned int r_type,
+ Symbol* gsym);
+
+ private:
+ static void
+ unsupported_reloc_local(Sized_relobj_file<size, false>*,
+ unsigned int r_type);
+
+ static void
+ unsupported_reloc_global(Sized_relobj_file<size, false>*,
+ unsigned int r_type, Symbol*);
+
+ void
+ check_non_pic(Relobj*, unsigned int r_type, Symbol*);
+
+ inline bool
+ possible_function_pointer_reloc(unsigned int r_type);
+
+ bool
+ reloc_needs_plt_for_ifunc(Sized_relobj_file<size, false>*,
+ 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()
+ : skip_call_tls_get_addr_(false)
+ { }
+
+ ~Relocate()
+ {
+ if (this->skip_call_tls_get_addr_)
+ {
+ // FIXME: This needs to specify the location somehow.
+ gold_error(_("missing expected TLS relocation"));
+ }
+ }
+
+ // Do a relocation. Return false if the caller should not issue
+ // any warnings about this relocation.
+ inline bool
+ relocate(const Relocate_info<size, false>*, Target_x86_64*,
+ Output_section*,
+ size_t relnum, const elfcpp::Rela<size, false>&,
+ unsigned int r_type, const Sized_symbol<size>*,
+ const Symbol_value<size>*,
+ unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
+ section_size_type);
+
+ private:
+ // Do a TLS relocation.
+ inline void
+ relocate_tls(const Relocate_info<size, false>*, Target_x86_64*,
+ size_t relnum, const elfcpp::Rela<size, false>&,
+ unsigned int r_type, const Sized_symbol<size>*,
+ const Symbol_value<size>*,
+ unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
+ section_size_type);
+
+ // Do a TLS General-Dynamic to Initial-Exec transition.
+ inline void
+ tls_gd_to_ie(const Relocate_info<size, false>*, size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rela<size, false>&, unsigned int r_type,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr,
+ section_size_type view_size);
+
+ // Do a TLS General-Dynamic to Local-Exec transition.
+ inline void
+ tls_gd_to_le(const Relocate_info<size, false>*, size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rela<size, false>&, unsigned int r_type,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ unsigned char* view,
+ section_size_type view_size);
+
+ // Do a TLSDESC-style General-Dynamic to Initial-Exec transition.
+ inline void
+ tls_desc_gd_to_ie(const Relocate_info<size, false>*, size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rela<size, false>&, unsigned int r_type,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr,
+ section_size_type view_size);
+
+ // Do a TLSDESC-style General-Dynamic to Local-Exec transition.
+ inline void
+ tls_desc_gd_to_le(const Relocate_info<size, false>*, size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rela<size, false>&, unsigned int r_type,
+ typename elfcpp::Elf_types<size>::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<size, false>*, size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rela<size, false>&, unsigned int r_type,
+ typename elfcpp::Elf_types<size>::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<size, false>*, size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rela<size, false>&, unsigned int r_type,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ unsigned char* view,
+ section_size_type view_size);
+
+ // 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_;
+ };
+
+ // 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<64, 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<64, 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<size, 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 the reserved PLT and GOT entries for the TLS descriptor resolver.
+ void
+ reserve_tlsdesc_entries(Symbol_table* symtab, Layout* layout);
+
+ // Create a GOT entry for the TLS module index.
+ unsigned int
+ got_mod_index_entry(Symbol_table* symtab, Layout* layout,
+ Sized_relobj_file<size, false>* object);
+
+ // Get the PLT section.
+ Output_data_plt_x86_64<size>*
+ plt_section() const
+ {
+ gold_assert(this->plt_ != NULL);
+ return this->plt_;
+ }
+
+ // Get the dynamic reloc section, creating it if necessary.
+ Reloc_section*
+ rela_dyn_section(Layout*);
+
+ // Get the section to use for TLSDESC relocations.
+ Reloc_section*
+ rela_tlsdesc_section(Layout*) const;
+
+ // Get the section to use for IRELATIVE relocations.
+ Reloc_section*
+ rela_irelative_section(Layout*);
+
+ // Add a potential copy relocation.
+ void
+ copy_reloc(Symbol_table* symtab, Layout* layout,
+ Sized_relobj_file<size, false>* object,
+ unsigned int shndx, Output_section* output_section,
+ Symbol* sym, const elfcpp::Rela<size, false>& reloc)
+ {
+ this->copy_relocs_.copy_reloc(symtab, layout,
+ symtab->get_sized_symbol<size>(sym),
+ object, shndx, output_section,
+ reloc, this->rela_dyn_section(layout));
+ }
+
+ // Information about this specific target which we pass to the
+ // general Target structure.
+ static const Target::Target_info x86_64_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_OFFSET = 1, // GOT entry for TLS offset
+ GOT_TYPE_TLS_PAIR = 2, // GOT entry for TLS module/offset pair
+ GOT_TYPE_TLS_DESC = 3 // GOT entry for TLS_DESC pair
+ };
+
+ // This type is used as the argument to the target specific
+ // relocation routines. The only target specific reloc is
+ // R_X86_64_TLSDESC against a local symbol.
+ struct Tlsdesc_info
+ {
+ Tlsdesc_info(Sized_relobj_file<size, false>* a_object, unsigned int a_r_sym)
+ : object(a_object), r_sym(a_r_sym)
+ { }
+
+ // The object in which the local symbol is defined.
+ Sized_relobj_file<size, false>* object;
+ // The local symbol index in the object.
+ unsigned int r_sym;
+ };
+
+ // The GOT section.
+ Output_data_got<64, false>* got_;
+ // The PLT section.
+ Output_data_plt_x86_64<size>* 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<64, false>* got_tlsdesc_;
+ // The _GLOBAL_OFFSET_TABLE_ symbol.
+ Symbol* global_offset_table_;
+ // The dynamic reloc section.
+ Reloc_section* rela_dyn_;
+ // The section to use for IRELATIVE relocs.
+ Reloc_section* rela_irelative_;
+ // Relocs saved to avoid a COPY reloc.
+ Copy_relocs<elfcpp::SHT_RELA, size, false> copy_relocs_;
+ // Offset of the GOT entry for the TLS module index.
+ unsigned int got_mod_index_offset_;
+ // We handle R_X86_64_TLSDESC against a local symbol as a target
+ // specific relocation. Here we store the object and local symbol
+ // index for the relocation.
+ std::vector<Tlsdesc_info> tlsdesc_reloc_info_;
+ // True if the _TLS_MODULE_BASE_ symbol has been defined.
+ bool tls_base_symbol_defined_;
+};
+
+template<>
+const Target::Target_info Target_x86_64<64>::x86_64_info =
+{
+ 64, // size
+ false, // is_big_endian
+ elfcpp::EM_X86_64, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ true, // has_code_fill
+ true, // is_default_stack_executable
+ true, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/lib/ld64.so.1", // program interpreter
+ 0x400000, // default_text_segment_address
+ 0x1000, // abi_pagesize (overridable by -z max-page-size)
+ 0x1000, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx
+ 0, // small_common_section_flags
+ elfcpp::SHF_X86_64_LARGE, // large_common_section_flags
+ NULL, // attributes_section
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
+};
+
+template<>
+const Target::Target_info Target_x86_64<32>::x86_64_info =
+{
+ 32, // size
+ false, // is_big_endian
+ elfcpp::EM_X86_64, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ true, // has_code_fill
+ true, // is_default_stack_executable
+ true, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/libx32/ldx32.so.1", // program interpreter
+ 0x400000, // default_text_segment_address
+ 0x1000, // abi_pagesize (overridable by -z max-page-size)
+ 0x1000, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx
+ 0, // small_common_section_flags
+ elfcpp::SHF_X86_64_LARGE, // large_common_section_flags
+ NULL, // attributes_section
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
+};
+
+// This is called when a new output section is created. This is where
+// we handle the SHF_X86_64_LARGE.
+
+template<int size>
+void
+Target_x86_64<size>::do_new_output_section(Output_section* os) const
+{
+ if ((os->flags() & elfcpp::SHF_X86_64_LARGE) != 0)
+ os->set_is_large_section();
+}
+
+// Get the GOT section, creating it if necessary.
+
+template<int size>
+Output_data_got<64, false>*
+Target_x86_64<size>::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.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);
+
+ this->got_ = new Output_data_got<64, false>();
+
+ 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(8, "** 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 * 8);
+
+ if (!is_got_plt_relro)
+ {
+ // Those bytes can go into the relro segment.
+ layout->increase_relro(3 * 8);
+ }
+
+ // 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 entries.
+ this->got_irelative_ = new Output_data_space(8, "** 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 and IRELATIVE entries.
+ this->got_tlsdesc_ = new Output_data_got<64, 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.
+
+template<int size>
+typename Target_x86_64<size>::Reloc_section*
+Target_x86_64<size>::rela_dyn_section(Layout* layout)
+{
+ if (this->rela_dyn_ == NULL)
+ {
+ gold_assert(layout != NULL);
+ this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
+ layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
+ elfcpp::SHF_ALLOC, this->rela_dyn_,
+ ORDER_DYNAMIC_RELOCS, false);
+ }
+ return this->rela_dyn_;
+}
+
+// Get the section to use for IRELATIVE relocs, creating it if
+// necessary. These go in .rela.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.
+
+template<int size>
+typename Target_x86_64<size>::Reloc_section*
+Target_x86_64<size>::rela_irelative_section(Layout* layout)
+{
+ if (this->rela_irelative_ == NULL)
+ {
+ // Make sure we have already created the dynamic reloc section.
+ this->rela_dyn_section(layout);
+ this->rela_irelative_ = new Reloc_section(false);
+ layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
+ elfcpp::SHF_ALLOC, this->rela_irelative_,
+ ORDER_DYNAMIC_RELOCS, false);
+ gold_assert(this->rela_dyn_->output_section()
+ == this->rela_irelative_->output_section());
+ }
+ return this->rela_irelative_;
+}
+
+// Initialize the PLT section.
+
+template<int size>
+void
+Output_data_plt_x86_64<size>::init(Layout* layout)
+{
+ this->rel_ = new Reloc_section(false);
+ layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
+ elfcpp::SHF_ALLOC, this->rel_,
+ ORDER_DYNAMIC_PLT_RELOCS, false);
+}
+
+template<int size>
+void
+Output_data_plt_x86_64<size>::do_adjust_output_section(Output_section* os)
+{
+ os->set_entsize(this->get_plt_entry_size());
+}
+
+// Add an entry to the PLT.
+
+template<int size>
+void
+Output_data_plt_x86_64<size>::add_entry(Symbol_table* symtab, Layout* layout,
+ Symbol* gsym)
+{
+ gold_assert(!gsym->has_plt_offset());
+
+ unsigned int plt_index;
+ off_t plt_offset;
+ section_offset_type got_offset;
+
+ unsigned int* pcount;
+ unsigned int offset;
+ unsigned int reserved;
+ Output_data_space* got;
+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
+ && gsym->can_use_relative_reloc(false))
+ {
+ pcount = &this->irelative_count_;
+ offset = 0;
+ reserved = 0;
+ got = this->got_irelative_;
+ }
+ else
+ {
+ pcount = &this->count_;
+ offset = 1;
+ reserved = 3;
+ got = this->got_plt_;
+ }
+
+ if (!this->is_data_size_valid())
+ {
+ // Note that when setting the PLT offset for a non-IRELATIVE
+ // entry we skip the initial reserved PLT entry.
+ plt_index = *pcount + offset;
+ plt_offset = plt_index * this->get_plt_entry_size();
+
+ ++*pcount;
+
+ got_offset = (plt_index - offset + reserved) * 8;
+ gold_assert(got_offset == got->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).
+ got->set_current_data_size(got_offset + 8);
+ }
+ else
+ {
+ // FIXME: This is probably not correct for IRELATIVE relocs.
+
+ // For incremental updates, find an available slot.
+ plt_offset = this->free_list_.allocate(this->get_plt_entry_size(),
+ this->get_plt_entry_size(), 0);
+ if (plt_offset == -1)
+ gold_fallback(_("out of patch space (PLT);"
+ " relink with --incremental-full"));
+
+ // The GOT and PLT entries have a 1-1 correspondance, so the GOT offset
+ // can be calculated from the PLT index, adjusting for the three
+ // reserved entries at the beginning of the GOT.
+ plt_index = plt_offset / this->get_plt_entry_size() - 1;
+ got_offset = (plt_index - offset + reserved) * 8;
+ }
+
+ gsym->set_plt_offset(plt_offset);
+
+ // Every PLT entry needs a reloc.
+ this->add_relocation(symtab, layout, gsym, 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.
+
+template<int size>
+unsigned int
+Output_data_plt_x86_64<size>::add_local_ifunc_entry(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, 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 + 8);
+
+ // Every PLT entry needs a reloc.
+ Reloc_section* rela = this->rela_irelative(symtab, layout);
+ rela->add_symbolless_local_addend(relobj, local_sym_index,
+ elfcpp::R_X86_64_IRELATIVE,
+ this->got_irelative_, got_offset, 0);
+
+ return plt_offset;
+}
+
+// Add the relocation for a PLT entry.
+
+template<int size>
+void
+Output_data_plt_x86_64<size>::add_relocation(Symbol_table* symtab,
+ Layout* layout,
+ Symbol* gsym,
+ unsigned int got_offset)
+{
+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
+ && gsym->can_use_relative_reloc(false))
+ {
+ Reloc_section* rela = this->rela_irelative(symtab, layout);
+ rela->add_symbolless_global_addend(gsym, elfcpp::R_X86_64_IRELATIVE,
+ this->got_irelative_, got_offset, 0);
+ }
+ else
+ {
+ gsym->set_needs_dynsym_entry();
+ this->rel_->add_global(gsym, elfcpp::R_X86_64_JUMP_SLOT, this->got_plt_,
+ got_offset, 0);
+ }
+}
+
+// Return where the TLSDESC relocations should go, creating it if
+// necessary. These follow the JUMP_SLOT relocations.
+
+template<int size>
+typename Output_data_plt_x86_64<size>::Reloc_section*
+Output_data_plt_x86_64<size>::rela_tlsdesc(Layout* layout)
+{
+ if (this->tlsdesc_rel_ == NULL)
+ {
+ this->tlsdesc_rel_ = new Reloc_section(false);
+ layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
+ elfcpp::SHF_ALLOC, this->tlsdesc_rel_,
+ ORDER_DYNAMIC_PLT_RELOCS, false);
+ gold_assert(this->tlsdesc_rel_->output_section()
+ == this->rel_->output_section());
+ }
+ return this->tlsdesc_rel_;
+}
+
+// Return where the IRELATIVE relocations should go in the PLT. These
+// follow the JUMP_SLOT and the TLSDESC relocations.
+
+template<int size>
+typename Output_data_plt_x86_64<size>::Reloc_section*
+Output_data_plt_x86_64<size>::rela_irelative(Symbol_table* symtab,
+ Layout* layout)
+{
+ if (this->irelative_rel_ == NULL)
+ {
+ // Make sure we have a place for the TLSDESC relocations, in
+ // case we see any later on.
+ this->rela_tlsdesc(layout);
+ this->irelative_rel_ = new Reloc_section(false);
+ layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
+ 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 .rela.plt
+ // section to hold R_X86_64_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("__rela_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("__rela_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.
+
+template<int size>
+uint64_t
+Output_data_plt_x86_64<size>::address_for_global(const Symbol* gsym)
+{
+ uint64_t offset = 0;
+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
+ && gsym->can_use_relative_reloc(false))
+ offset = (this->count_ + 1) * 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.
+
+template<int size>
+uint64_t
+Output_data_plt_x86_64<size>::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));
+}
+
+// Set the final size.
+template<int size>
+void
+Output_data_plt_x86_64<size>::set_final_data_size()
+{
+ unsigned int count = this->count_ + this->irelative_count_;
+ if (this->has_tlsdesc_entry())
+ ++count;
+ this->set_data_size((count + 1) * this->get_plt_entry_size());
+}
+
+// The first entry in the PLT for an executable.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_standard<size>::first_plt_entry[plt_entry_size] =
+{
+ // From AMD64 ABI Draft 0.98, page 76
+ 0xff, 0x35, // pushq contents of memory address
+ 0, 0, 0, 0, // replaced with address of .got + 8
+ 0xff, 0x25, // jmp indirect
+ 0, 0, 0, 0, // replaced with address of .got + 16
+ 0x90, 0x90, 0x90, 0x90 // noop (x4)
+};
+
+template<int size>
+void
+Output_data_plt_x86_64_standard<size>::do_fill_first_plt_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+ // We do a jmp relative to the PC at the end of this instruction.
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + 8
+ - (plt_address + 6)));
+ elfcpp::Swap<32, false>::writeval(pov + 8,
+ (got_address + 16
+ - (plt_address + 12)));
+}
+
+// Subsequent entries in the PLT for an executable.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_standard<size>::plt_entry[plt_entry_size] =
+{
+ // From AMD64 ABI Draft 0.98, page 76
+ 0xff, 0x25, // jmpq indirect
+ 0, 0, 0, 0, // replaced with address of symbol in .got
+ 0x68, // pushq immediate
+ 0, 0, 0, 0, // replaced with offset into relocation table
+ 0xe9, // jmpq relative
+ 0, 0, 0, 0 // replaced with offset to start of .plt
+};
+
+template<int size>
+unsigned int
+Output_data_plt_x86_64_standard<size>::do_fill_plt_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + got_offset
+ - (plt_address + plt_offset
+ + 6)));
+
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_index);
+ elfcpp::Swap<32, false>::writeval(pov + 12,
+ - (plt_offset + plt_entry_size));
+
+ return 6;
+}
+
+// The reserved TLSDESC entry in the PLT for an executable.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_standard<size>::tlsdesc_plt_entry[plt_entry_size] =
+{
+ // From Alexandre Oliva, "Thread-Local Storage Descriptors for IA32
+ // and AMD64/EM64T", Version 0.9.4 (2005-10-10).
+ 0xff, 0x35, // pushq x(%rip)
+ 0, 0, 0, 0, // replaced with address of linkmap GOT entry (at PLTGOT + 8)
+ 0xff, 0x25, // jmpq *y(%rip)
+ 0, 0, 0, 0, // replaced with offset of reserved TLSDESC_GOT entry
+ 0x0f, 0x1f, // nop
+ 0x40, 0
+};
+
+template<int size>
+void
+Output_data_plt_x86_64_standard<size>::do_fill_tlsdesc_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset)
+{
+ memcpy(pov, tlsdesc_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + 8
+ - (plt_address + plt_offset
+ + 6)));
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 8,
+ (got_base
+ + tlsdesc_got_offset
+ - (plt_address + plt_offset
+ + 12)));
+}
+
+// The .eh_frame unwind information for the PLT.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64<size>::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.
+ 0x78, // Data alignment factor.
+ 16, // Return address column.
+ 1, // Augmentation size.
+ (elfcpp::DW_EH_PE_pcrel // FDE encoding.
+ | elfcpp::DW_EH_PE_sdata4),
+ elfcpp::DW_CFA_def_cfa, 7, 8, // DW_CFA_def_cfa: r7 (rsp) ofs 8.
+ elfcpp::DW_CFA_offset + 16, 1,// DW_CFA_offset: r16 (rip) at cfa-8.
+ elfcpp::DW_CFA_nop, // Align to 16 bytes.
+ elfcpp::DW_CFA_nop
+};
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_standard<size>::plt_eh_frame_fde[plt_eh_frame_fde_size] =
+{
+ 0, 0, 0, 0, // Replaced with offset to .plt.
+ 0, 0, 0, 0, // Replaced with size of .plt.
+ 0, // Augmentation size.
+ elfcpp::DW_CFA_def_cfa_offset, 16, // DW_CFA_def_cfa_offset: 16.
+ elfcpp::DW_CFA_advance_loc + 6, // Advance 6 to __PLT__ + 6.
+ elfcpp::DW_CFA_def_cfa_offset, 24, // DW_CFA_def_cfa_offset: 24.
+ elfcpp::DW_CFA_advance_loc + 10, // Advance 10 to __PLT__ + 16.
+ elfcpp::DW_CFA_def_cfa_expression, // DW_CFA_def_cfa_expression.
+ 11, // Block length.
+ elfcpp::DW_OP_breg7, 8, // Push %rsp + 8.
+ elfcpp::DW_OP_breg16, 0, // Push %rip.
+ elfcpp::DW_OP_lit15, // Push 0xf.
+ elfcpp::DW_OP_and, // & (%rip & 0xf).
+ elfcpp::DW_OP_lit11, // Push 0xb.
+ elfcpp::DW_OP_ge, // >= ((%rip & 0xf) >= 0xb)
+ elfcpp::DW_OP_lit3, // Push 3.
+ elfcpp::DW_OP_shl, // << (((%rip & 0xf) >= 0xb) << 3)
+ elfcpp::DW_OP_plus, // + ((((%rip&0xf)>=0xb)<<3)+%rsp+8
+ 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 specified by the AMD64 ABI.
+
+template<int size>
+void
+Output_data_plt_x86_64<size>::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;
+
+ // The base address of the .plt section.
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address = this->address();
+ // The base address of the .got section.
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base = this->got_->address();
+ // The base address of the PLT portion of the .got section,
+ // which is where the GOT pointer will point, and where the
+ // three reserved GOT entries are located.
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address
+ = this->got_plt_->address();
+
+ this->fill_first_plt_entry(pov, got_address, plt_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_x86_64::got_section.
+ Output_section* dynamic = this->layout_->dynamic_section();
+ uint32_t dynamic_addr = dynamic == NULL ? 0 : dynamic->address();
+ elfcpp::Swap<64, false>::writeval(got_pov, dynamic_addr);
+ got_pov += 8;
+ memset(got_pov, 0, 16);
+ got_pov += 16;
+
+ unsigned int plt_offset = this->get_plt_entry_size();
+ unsigned int got_offset = 24;
+ const unsigned int count = this->count_ + this->irelative_count_;
+ for (unsigned int plt_index = 0;
+ plt_index < count;
+ ++plt_index,
+ pov += this->get_plt_entry_size(),
+ got_pov += 8,
+ plt_offset += this->get_plt_entry_size(),
+ got_offset += 8)
+ {
+ // Set and adjust the PLT entry itself.
+ unsigned int lazy_offset = this->fill_plt_entry(pov,
+ got_address, plt_address,
+ got_offset, plt_offset,
+ plt_index);
+
+ // Set the entry in the GOT.
+ elfcpp::Swap<64, false>::writeval(got_pov,
+ plt_address + plt_offset + lazy_offset);
+ }
+
+ if (this->has_tlsdesc_entry())
+ {
+ // Set and adjust the reserved TLSDESC PLT entry.
+ unsigned int tlsdesc_got_offset = this->get_tlsdesc_got_offset();
+ this->fill_tlsdesc_entry(pov, got_address, plt_address, got_base,
+ tlsdesc_got_offset, plt_offset);
+ pov += this->get_plt_entry_size();
+ }
+
+ gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
+ gold_assert(static_cast<section_size_type>(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.
+
+template<int size>
+void
+Target_x86_64<size>::make_plt_section(Symbol_table* symtab, Layout* layout)
+{
+ if (this->plt_ == NULL)
+ {
+ // Create the GOT sections first.
+ this->got_section(symtab, layout);
+
+ this->plt_ = this->make_data_plt(layout, this->got_, this->got_plt_,
+ this->got_irelative_);
+
+ // Add unwind information if requested.
+ if (parameters->options().ld_generated_unwind_info())
+ this->plt_->add_eh_frame(layout);
+
+ layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_EXECINSTR),
+ this->plt_, ORDER_PLT, false);
+
+ // Make the sh_info field of .rela.plt point to .plt.
+ Output_section* rela_plt_os = this->plt_->rela_plt()->output_section();
+ rela_plt_os->set_info_section(this->plt_->output_section());
+ }
+}
+
+// Return the section for TLSDESC relocations.
+
+template<int size>
+typename Target_x86_64<size>::Reloc_section*
+Target_x86_64<size>::rela_tlsdesc_section(Layout* layout) const
+{
+ return this->plt_section()->rela_tlsdesc(layout);
+}
+
+// Create a PLT entry for a global symbol.
+
+template<int size>
+void
+Target_x86_64<size>::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.
+
+template<int size>
+void
+Target_x86_64<size>::make_local_ifunc_plt_entry(
+ Symbol_table* symtab, Layout* layout,
+ Sized_relobj_file<size, 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.
+
+template<int size>
+unsigned int
+Target_x86_64<size>::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<int size>
+unsigned int
+Target_x86_64<size>::first_plt_entry_offset() const
+{
+ return this->plt_->first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<int size>
+unsigned int
+Target_x86_64<size>::plt_entry_size() const
+{
+ return this->plt_->get_plt_entry_size();
+}
+
+// Create the GOT and PLT sections for an incremental update.
+
+template<int size>
+Output_data_got_base*
+Target_x86_64<size>::init_got_plt_for_update(Symbol_table* symtab,
+ Layout* layout,
+ unsigned int got_count,
+ unsigned int plt_count)
+{
+ gold_assert(this->got_ == NULL);
+
+ this->got_ = new Output_data_got<64, false>(got_count * 8);
+ layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_, ORDER_RELRO_LAST,
+ true);
+
+ // Add the three reserved entries.
+ this->got_plt_ = new Output_data_space((plt_count + 3) * 8, 8, "** GOT PLT");
+ layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_plt_, ORDER_NON_RELRO_FIRST,
+ false);
+
+ // 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 TLSDESC relocations, they get GOT entries in
+ // .got.plt after the jump slot entries.
+ // FIXME: Get the count for TLSDESC entries.
+ this->got_tlsdesc_ = new Output_data_got<64, false>(0);
+ layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+ this->got_tlsdesc_,
+ ORDER_NON_RELRO_FIRST, false);
+
+ // If there are any IRELATIVE relocations, they get GOT entries in
+ // .got.plt after the jump slot and TLSDESC entries.
+ this->got_irelative_ = new Output_data_space(0, 8, "** GOT IRELATIVE PLT");
+ layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+ this->got_irelative_,
+ ORDER_NON_RELRO_FIRST, false);
+
+ // Create the PLT section.
+ this->plt_ = this->make_data_plt(layout, this->got_,
+ this->got_plt_,
+ this->got_irelative_,
+ plt_count);
+
+ // Add unwind information if requested.
+ if (parameters->options().ld_generated_unwind_info())
+ this->plt_->add_eh_frame(layout);
+
+ layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR,
+ this->plt_, ORDER_PLT, false);
+
+ // Make the sh_info field of .rela.plt point to .plt.
+ Output_section* rela_plt_os = this->plt_->rela_plt()->output_section();
+ rela_plt_os->set_info_section(this->plt_->output_section());
+
+ // Create the rela_dyn section.
+ this->rela_dyn_section(layout);
+
+ return this->got_;
+}
+
+// Reserve a GOT entry for a local symbol, and regenerate any
+// necessary dynamic relocations.
+
+template<int size>
+void
+Target_x86_64<size>::reserve_local_got_entry(
+ unsigned int got_index,
+ Sized_relobj<size, false>* obj,
+ unsigned int r_sym,
+ unsigned int got_type)
+{
+ unsigned int got_offset = got_index * 8;
+ Reloc_section* rela_dyn = this->rela_dyn_section(NULL);
+
+ this->got_->reserve_local(got_index, obj, r_sym, got_type);
+ switch (got_type)
+ {
+ case GOT_TYPE_STANDARD:
+ if (parameters->options().output_is_position_independent())
+ rela_dyn->add_local_relative(obj, r_sym, elfcpp::R_X86_64_RELATIVE,
+ this->got_, got_offset, 0, false);
+ break;
+ case GOT_TYPE_TLS_OFFSET:
+ rela_dyn->add_local(obj, r_sym, elfcpp::R_X86_64_TPOFF64,
+ this->got_, got_offset, 0);
+ break;
+ case GOT_TYPE_TLS_PAIR:
+ this->got_->reserve_slot(got_index + 1);
+ rela_dyn->add_local(obj, r_sym, elfcpp::R_X86_64_DTPMOD64,
+ this->got_, got_offset, 0);
+ break;
+ case GOT_TYPE_TLS_DESC:
+ gold_fatal(_("TLS_DESC not yet supported for incremental linking"));
+ // this->got_->reserve_slot(got_index + 1);
+ // rela_dyn->add_target_specific(elfcpp::R_X86_64_TLSDESC, arg,
+ // this->got_, got_offset, 0);
+ break;
+ default:
+ gold_unreachable();
+ }
+}
+
+// Reserve a GOT entry for a global symbol, and regenerate any
+// necessary dynamic relocations.
+
+template<int size>
+void
+Target_x86_64<size>::reserve_global_got_entry(unsigned int got_index,
+ Symbol* gsym,
+ unsigned int got_type)
+{
+ unsigned int got_offset = got_index * 8;
+ Reloc_section* rela_dyn = this->rela_dyn_section(NULL);
+
+ this->got_->reserve_global(got_index, gsym, got_type);
+ switch (got_type)
+ {
+ case GOT_TYPE_STANDARD:
+ if (!gsym->final_value_is_known())
+ {
+ if (gsym->is_from_dynobj()
+ || gsym->is_undefined()
+ || gsym->is_preemptible()
+ || gsym->type() == elfcpp::STT_GNU_IFUNC)
+ rela_dyn->add_global(gsym, elfcpp::R_X86_64_GLOB_DAT,
+ this->got_, got_offset, 0);
+ else
+ rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_RELATIVE,
+ this->got_, got_offset, 0, false);
+ }
+ break;
+ case GOT_TYPE_TLS_OFFSET:
+ rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_TPOFF64,
+ this->got_, got_offset, 0, false);
+ break;
+ case GOT_TYPE_TLS_PAIR:
+ this->got_->reserve_slot(got_index + 1);
+ rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_DTPMOD64,
+ this->got_, got_offset, 0, false);
+ rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_DTPOFF64,
+ this->got_, got_offset + 8, 0, false);
+ break;
+ case GOT_TYPE_TLS_DESC:
+ this->got_->reserve_slot(got_index + 1);
+ rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_TLSDESC,
+ this->got_, got_offset, 0, false);
+ break;
+ default:
+ gold_unreachable();
+ }
+}
+
+// Register an existing PLT entry for a global symbol.
+
+template<int size>
+void
+Target_x86_64<size>::register_global_plt_entry(Symbol_table* symtab,
+ Layout* layout,
+ unsigned int plt_index,
+ Symbol* gsym)
+{
+ gold_assert(this->plt_ != NULL);
+ gold_assert(!gsym->has_plt_offset());
+
+ this->plt_->reserve_slot(plt_index);
+
+ gsym->set_plt_offset((plt_index + 1) * this->plt_entry_size());
+
+ unsigned int got_offset = (plt_index + 3) * 8;
+ this->plt_->add_relocation(symtab, layout, gsym, got_offset);
+}
+
+// Force a COPY relocation for a given symbol.
+
+template<int size>
+void
+Target_x86_64<size>::emit_copy_reloc(
+ Symbol_table* symtab, Symbol* sym, Output_section* os, off_t offset)
+{
+ this->copy_relocs_.emit_copy_reloc(symtab,
+ symtab->get_sized_symbol<size>(sym),
+ os,
+ offset,
+ this->rela_dyn_section(NULL));
+}
+
+// Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
+
+template<int size>
+void
+Target_x86_64<size>::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 the reserved PLT and GOT entries for the TLS descriptor resolver.
+
+template<int size>
+void
+Target_x86_64<size>::reserve_tlsdesc_entries(Symbol_table* symtab,
+ Layout* layout)
+{
+ if (this->plt_ == NULL)
+ this->make_plt_section(symtab, layout);
+
+ if (!this->plt_->has_tlsdesc_entry())
+ {
+ // Allocate the TLSDESC_GOT entry.
+ Output_data_got<64, false>* got = this->got_section(symtab, layout);
+ unsigned int got_offset = got->add_constant(0);
+
+ // Allocate the TLSDESC_PLT entry.
+ this->plt_->reserve_tlsdesc_entry(got_offset);
+ }
+}
+
+// Create a GOT entry for the TLS module index.
+
+template<int size>
+unsigned int
+Target_x86_64<size>::got_mod_index_entry(Symbol_table* symtab, Layout* layout,
+ Sized_relobj_file<size, false>* object)
+{
+ if (this->got_mod_index_offset_ == -1U)
+ {
+ gold_assert(symtab != NULL && layout != NULL && object != NULL);
+ Reloc_section* rela_dyn = this->rela_dyn_section(layout);
+ Output_data_got<64, false>* got = this->got_section(symtab, layout);
+ unsigned int got_offset = got->add_constant(0);
+ rela_dyn->add_local(object, 0, elfcpp::R_X86_64_DTPMOD64, got,
+ got_offset, 0);
+ got->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<int size>
+tls::Tls_optimization
+Target_x86_64<size>::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_X86_64_TLSGD:
+ case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+ case elfcpp::R_X86_64_TLSDESC_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_X86_64_TLSLD:
+ // 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_X86_64_DTPOFF32:
+ case elfcpp::R_X86_64_DTPOFF64:
+ // Another Local-Dynamic reloc.
+ return tls::TLSOPT_TO_LE;
+
+ case elfcpp::R_X86_64_GOTTPOFF:
+ // 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_X86_64_TPOFF32:
+ // 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.
+
+template<int size>
+int
+Target_x86_64<size>::Scan::get_reference_flags(unsigned int r_type)
+{
+ switch (r_type)
+ {
+ case elfcpp::R_X86_64_NONE:
+ case elfcpp::R_X86_64_GNU_VTINHERIT:
+ case elfcpp::R_X86_64_GNU_VTENTRY:
+ case elfcpp::R_X86_64_GOTPC32:
+ case elfcpp::R_X86_64_GOTPC64:
+ // No symbol reference.
+ return 0;
+
+ case elfcpp::R_X86_64_64:
+ case elfcpp::R_X86_64_32:
+ case elfcpp::R_X86_64_32S:
+ case elfcpp::R_X86_64_16:
+ case elfcpp::R_X86_64_8:
+ return Symbol::ABSOLUTE_REF;
+
+ case elfcpp::R_X86_64_PC64:
+ case elfcpp::R_X86_64_PC32:
+ case elfcpp::R_X86_64_PC16:
+ case elfcpp::R_X86_64_PC8:
+ case elfcpp::R_X86_64_GOTOFF64:
+ return Symbol::RELATIVE_REF;
+
+ case elfcpp::R_X86_64_PLT32:
+ case elfcpp::R_X86_64_PLTOFF64:
+ return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+
+ case elfcpp::R_X86_64_GOT64:
+ case elfcpp::R_X86_64_GOT32:
+ case elfcpp::R_X86_64_GOTPCREL64:
+ case elfcpp::R_X86_64_GOTPCREL:
+ case elfcpp::R_X86_64_GOTPLT64:
+ // Absolute in GOT.
+ return Symbol::ABSOLUTE_REF;
+
+ case elfcpp::R_X86_64_TLSGD: // Global-dynamic
+ case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
+ case elfcpp::R_X86_64_TLSDESC_CALL:
+ case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ case elfcpp::R_X86_64_DTPOFF32:
+ case elfcpp::R_X86_64_DTPOFF64:
+ case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
+ case elfcpp::R_X86_64_TPOFF32: // Local-exec
+ return Symbol::TLS_REF;
+
+ case elfcpp::R_X86_64_COPY:
+ case elfcpp::R_X86_64_GLOB_DAT:
+ case elfcpp::R_X86_64_JUMP_SLOT:
+ case elfcpp::R_X86_64_RELATIVE:
+ case elfcpp::R_X86_64_IRELATIVE:
+ case elfcpp::R_X86_64_TPOFF64:
+ case elfcpp::R_X86_64_DTPMOD64:
+ case elfcpp::R_X86_64_TLSDESC:
+ case elfcpp::R_X86_64_SIZE32:
+ case elfcpp::R_X86_64_SIZE64:
+ default:
+ // Not expected. We will give an error later.
+ return 0;
+ }
+}
+
+// Report an unsupported relocation against a local symbol.
+
+template<int size>
+void
+Target_x86_64<size>::Scan::unsupported_reloc_local(
+ Sized_relobj_file<size, false>* 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. If GSYM is not NULL,
+// it is the symbol the relocation is against; if it is NULL, the
+// relocation is against a local symbol.
+
+template<int size>
+void
+Target_x86_64<size>::Scan::check_non_pic(Relobj* object, unsigned int r_type,
+ Symbol* gsym)
+{
+ switch (r_type)
+ {
+ // These are the relocation types supported by glibc for x86_64
+ // which should always work.
+ case elfcpp::R_X86_64_RELATIVE:
+ case elfcpp::R_X86_64_IRELATIVE:
+ case elfcpp::R_X86_64_GLOB_DAT:
+ case elfcpp::R_X86_64_JUMP_SLOT:
+ case elfcpp::R_X86_64_DTPMOD64:
+ case elfcpp::R_X86_64_DTPOFF64:
+ case elfcpp::R_X86_64_TPOFF64:
+ case elfcpp::R_X86_64_64:
+ case elfcpp::R_X86_64_COPY:
+ return;
+
+ // glibc supports these reloc types, but they can overflow.
+ case elfcpp::R_X86_64_PC32:
+ // A PC relative reference is OK against a local symbol or if
+ // the symbol is defined locally.
+ if (gsym == NULL
+ || (!gsym->is_from_dynobj()
+ && !gsym->is_undefined()
+ && !gsym->is_preemptible()))
+ return;
+ /* Fall through. */
+ case elfcpp::R_X86_64_32:
+ // R_X86_64_32 is OK for x32.
+ if (size == 32 && r_type == elfcpp::R_X86_64_32)
+ return;
+ if (this->issued_non_pic_error_)
+ return;
+ gold_assert(parameters->options().output_is_position_independent());
+ if (gsym == NULL)
+ object->error(_("requires dynamic R_X86_64_32 reloc which may "
+ "overflow at runtime; recompile with -fPIC"));
+ else
+ object->error(_("requires dynamic %s reloc against '%s' which may "
+ "overflow at runtime; recompile with -fPIC"),
+ (r_type == elfcpp::R_X86_64_32
+ ? "R_X86_64_32"
+ : "R_X86_64_PC32"),
+ gsym->name());
+ this->issued_non_pic_error_ = true;
+ 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;
+ gold_assert(parameters->options().output_is_position_independent());
+ object->error(_("requires unsupported dynamic reloc %u; "
+ "recompile with -fPIC"),
+ r_type);
+ this->issued_non_pic_error_ = true;
+ return;
+
+ case elfcpp::R_X86_64_NONE:
+ gold_unreachable();
+ }
+}
+
+// Return whether we need to make a PLT entry for a relocation of the
+// given type against a STT_GNU_IFUNC symbol.
+
+template<int size>
+bool
+Target_x86_64<size>::Scan::reloc_needs_plt_for_ifunc(
+ Sized_relobj_file<size, 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.
+
+template<int size>
+inline void
+Target_x86_64<size>::Scan::local(Symbol_table* symtab,
+ Layout* layout,
+ Target_x86_64<size>* target,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, false>& reloc,
+ unsigned int r_type,
+ const elfcpp::Sym<size, false>& lsym,
+ bool is_discarded)
+{
+ if (is_discarded)
+ return;
+
+ // A local STT_GNU_IFUNC symbol may require a PLT entry.
+ bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
+ if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type))
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ target->make_local_ifunc_plt_entry(symtab, layout, object, r_sym);
+ }
+
+ switch (r_type)
+ {
+ case elfcpp::R_X86_64_NONE:
+ case elfcpp::R_X86_64_GNU_VTINHERIT:
+ case elfcpp::R_X86_64_GNU_VTENTRY:
+ break;
+
+ case elfcpp::R_X86_64_64:
+ // 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_X86_64_RELATIVE relocation so the dynamic loader can
+ // relocate it easily.
+ if (parameters->options().output_is_position_independent())
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_local_relative(object, r_sym,
+ (size == 32
+ ? elfcpp::R_X86_64_RELATIVE64
+ : elfcpp::R_X86_64_RELATIVE),
+ output_section, data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend(), is_ifunc);
+ }
+ break;
+
+ case elfcpp::R_X86_64_32:
+ case elfcpp::R_X86_64_32S:
+ case elfcpp::R_X86_64_16:
+ case elfcpp::R_X86_64_8:
+ // If building a shared library (or a position-independent
+ // executable), we need to create a dynamic relocation for this
+ // location. We can't use an R_X86_64_RELATIVE relocation
+ // because that is always a 64-bit relocation.
+ if (parameters->options().output_is_position_independent())
+ {
+ // Use R_X86_64_RELATIVE relocation for R_X86_64_32 under x32.
+ if (size == 32 && r_type == elfcpp::R_X86_64_32)
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_local_relative(object, r_sym,
+ elfcpp::R_X86_64_RELATIVE,
+ output_section, data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend(), is_ifunc);
+ break;
+ }
+
+ this->check_non_pic(object, r_type, NULL);
+
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ if (lsym.get_st_type() != elfcpp::STT_SECTION)
+ rela_dyn->add_local(object, r_sym, r_type, output_section,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
+ else
+ {
+ gold_assert(lsym.get_st_value() == 0);
+ 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
+ rela_dyn->add_local_section(object, shndx,
+ r_type, output_section,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ }
+ break;
+
+ case elfcpp::R_X86_64_PC64:
+ case elfcpp::R_X86_64_PC32:
+ case elfcpp::R_X86_64_PC16:
+ case elfcpp::R_X86_64_PC8:
+ break;
+
+ case elfcpp::R_X86_64_PLT32:
+ // Since we know this is a local symbol, we can handle this as a
+ // PC32 reloc.
+ break;
+
+ case elfcpp::R_X86_64_GOTPC32:
+ case elfcpp::R_X86_64_GOTOFF64:
+ case elfcpp::R_X86_64_GOTPC64:
+ case elfcpp::R_X86_64_PLTOFF64:
+ // We need a GOT section.
+ target->got_section(symtab, layout);
+ // For PLTOFF64, we'd normally want a PLT section, but since we
+ // know this is a local symbol, no PLT is needed.
+ break;
+
+ case elfcpp::R_X86_64_GOT64:
+ case elfcpp::R_X86_64_GOT32:
+ case elfcpp::R_X86_64_GOTPCREL64:
+ case elfcpp::R_X86_64_GOTPCREL:
+ case elfcpp::R_X86_64_GOTPLT64:
+ {
+ // The symbol requires a GOT entry.
+ Output_data_got<64, false>* got = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+
+ // 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 (is_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 relocation for this symbol's GOT entry.
+ if (parameters->options().output_is_position_independent())
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ // R_X86_64_RELATIVE assumes a 64-bit relocation.
+ if (r_type != elfcpp::R_X86_64_GOT32)
+ {
+ unsigned int got_offset =
+ object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
+ rela_dyn->add_local_relative(object, r_sym,
+ elfcpp::R_X86_64_RELATIVE,
+ got, got_offset, 0, is_ifunc);
+ }
+ else
+ {
+ this->check_non_pic(object, r_type, NULL);
+
+ gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
+ rela_dyn->add_local(
+ object, r_sym, r_type, got,
+ object->local_got_offset(r_sym, GOT_TYPE_STANDARD), 0);
+ }
+ }
+ }
+ // For GOTPLT64, we'd normally want a PLT section, but since
+ // we know this is a local symbol, no PLT is needed.
+ }
+ break;
+
+ case elfcpp::R_X86_64_COPY:
+ case elfcpp::R_X86_64_GLOB_DAT:
+ case elfcpp::R_X86_64_JUMP_SLOT:
+ case elfcpp::R_X86_64_RELATIVE:
+ case elfcpp::R_X86_64_IRELATIVE:
+ // These are outstanding tls relocs, which are unexpected when linking
+ case elfcpp::R_X86_64_TPOFF64:
+ case elfcpp::R_X86_64_DTPMOD64:
+ case elfcpp::R_X86_64_TLSDESC:
+ 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_X86_64_TLSGD: // Global-dynamic
+ case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
+ case elfcpp::R_X86_64_TLSDESC_CALL:
+ case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ case elfcpp::R_X86_64_DTPOFF32:
+ case elfcpp::R_X86_64_DTPOFF64:
+ case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
+ case elfcpp::R_X86_64_TPOFF32: // Local-exec
+ {
+ bool output_is_shared = parameters->options().shared();
+ const tls::Tls_optimization optimized_type
+ = Target_x86_64<size>::optimize_tls_reloc(!output_is_shared,
+ r_type);
+ switch (r_type)
+ {
+ case elfcpp::R_X86_64_TLSGD: // General-dynamic
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ 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->rela_dyn_section(layout),
+ elfcpp::R_X86_64_DTPMOD64);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_local(object, r_type);
+ break;
+
+ case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+ target->define_tls_base_symbol(symtab, layout);
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create reserved PLT and GOT entries for the resolver.
+ target->reserve_tlsdesc_entries(symtab, layout);
+
+ // Generate a double GOT entry with an
+ // R_X86_64_TLSDESC reloc. The R_X86_64_TLSDESC reloc
+ // is resolved lazily, so the GOT entry needs to be in
+ // an area in .got.plt, not .got. Call got_section to
+ // make sure the section has been created.
+ target->got_section(symtab, layout);
+ Output_data_got<64, false>* got = target->got_tlsdesc_section();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC))
+ {
+ unsigned int got_offset = got->add_constant(0);
+ got->add_constant(0);
+ object->set_local_got_offset(r_sym, GOT_TYPE_TLS_DESC,
+ got_offset);
+ Reloc_section* rt = target->rela_tlsdesc_section(layout);
+ // We store the arguments we need in a vector, and
+ // use the index into the vector as the parameter
+ // to pass to the target specific routines.
+ uintptr_t intarg = target->add_tlsdesc_info(object, r_sym);
+ void* arg = reinterpret_cast<void*>(intarg);
+ rt->add_target_specific(elfcpp::R_X86_64_TLSDESC, arg,
+ got, got_offset, 0);
+ }
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_local(object, r_type);
+ break;
+
+ case elfcpp::R_X86_64_TLSDESC_CALL:
+ break;
+
+ case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the module index.
+ target->got_mod_index_entry(symtab, layout, object);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_local(object, r_type);
+ break;
+
+ case elfcpp::R_X86_64_DTPOFF32:
+ case elfcpp::R_X86_64_DTPOFF64:
+ break;
+
+ case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
+ layout->set_has_static_tls();
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
+ target->rela_dyn_section(layout),
+ elfcpp::R_X86_64_TPOFF64);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_local(object, r_type);
+ break;
+
+ case elfcpp::R_X86_64_TPOFF32: // Local-exec
+ layout->set_has_static_tls();
+ if (output_is_shared)
+ unsupported_reloc_local(object, r_type);
+ break;
+
+ default:
+ gold_unreachable();
+ }
+ }
+ break;
+
+ case elfcpp::R_X86_64_SIZE32:
+ case elfcpp::R_X86_64_SIZE64:
+ default:
+ gold_error(_("%s: unsupported reloc %u against local symbol"),
+ object->name().c_str(), r_type);
+ break;
+ }
+}
+
+
+// Report an unsupported relocation against a global symbol.
+
+template<int size>
+void
+Target_x86_64<size>::Scan::unsupported_reloc_global(
+ Sized_relobj_file<size, 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());
+}
+
+// Returns true if this relocation type could be that of a function pointer.
+template<int size>
+inline bool
+Target_x86_64<size>::Scan::possible_function_pointer_reloc(unsigned int r_type)
+{
+ switch (r_type)
+ {
+ case elfcpp::R_X86_64_64:
+ case elfcpp::R_X86_64_32:
+ case elfcpp::R_X86_64_32S:
+ case elfcpp::R_X86_64_16:
+ case elfcpp::R_X86_64_8:
+ case elfcpp::R_X86_64_GOT64:
+ case elfcpp::R_X86_64_GOT32:
+ case elfcpp::R_X86_64_GOTPCREL64:
+ case elfcpp::R_X86_64_GOTPCREL:
+ case elfcpp::R_X86_64_GOTPLT64:
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+// For safe ICF, scan a relocation for a local symbol to check if it
+// corresponds to a function pointer being taken. In that case mark
+// the function whose pointer was taken as not foldable.
+
+template<int size>
+inline bool
+Target_x86_64<size>::Scan::local_reloc_may_be_function_pointer(
+ Symbol_table* ,
+ Layout* ,
+ Target_x86_64<size>* ,
+ Sized_relobj_file<size, false>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<size, false>& ,
+ unsigned int r_type,
+ const elfcpp::Sym<size, false>&)
+{
+ // When building a shared library, do not fold any local symbols as it is
+ // not possible to distinguish pointer taken versus a call by looking at
+ // the relocation types.
+ return (parameters->options().shared()
+ || possible_function_pointer_reloc(r_type));
+}
+
+// For safe ICF, scan a relocation for a global symbol to check if it
+// corresponds to a function pointer being taken. In that case mark
+// the function whose pointer was taken as not foldable.
+
+template<int size>
+inline bool
+Target_x86_64<size>::Scan::global_reloc_may_be_function_pointer(
+ Symbol_table*,
+ Layout* ,
+ Target_x86_64<size>* ,
+ Sized_relobj_file<size, false>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<size, false>& ,
+ unsigned int r_type,
+ Symbol* gsym)
+{
+ // When building a shared library, do not fold symbols whose visibility
+ // is hidden, internal or protected.
+ return ((parameters->options().shared()
+ && (gsym->visibility() == elfcpp::STV_INTERNAL
+ || gsym->visibility() == elfcpp::STV_PROTECTED
+ || gsym->visibility() == elfcpp::STV_HIDDEN))
+ || possible_function_pointer_reloc(r_type));
+}
+
+// Scan a relocation for a global symbol.
+
+template<int size>
+inline void
+Target_x86_64<size>::Scan::global(Symbol_table* symtab,
+ Layout* layout,
+ Target_x86_64<size>* target,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, false>& reloc,
+ unsigned int r_type,
+ Symbol* gsym)
+{
+ // 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_X86_64_NONE:
+ case elfcpp::R_X86_64_GNU_VTINHERIT:
+ case elfcpp::R_X86_64_GNU_VTENTRY:
+ break;
+
+ case elfcpp::R_X86_64_64:
+ case elfcpp::R_X86_64_32:
+ case elfcpp::R_X86_64_32S:
+ case elfcpp::R_X86_64_16:
+ case elfcpp::R_X86_64_8:
+ {
+ // Make a PLT entry if necessary.
+ if (gsym->needs_plt_entry())
+ {
+ target->make_plt_entry(symtab, layout, gsym);
+ // Since this is not a PC-relative relocation, we may be
+ // taking the address of a function. In that case we need to
+ // set the entry in the dynamic symbol table to the address of
+ // the PLT entry.
+ if (gsym->is_from_dynobj() && !parameters->options().shared())
+ gsym->set_needs_dynsym_value();
+ }
+ // Make a dynamic relocation if necessary.
+ if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+ {
+ if (gsym->may_need_copy_reloc())
+ {
+ target->copy_reloc(symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
+ }
+ else if (((size == 64 && r_type == elfcpp::R_X86_64_64)
+ || (size == 32 && r_type == elfcpp::R_X86_64_32))
+ && gsym->type() == elfcpp::STT_GNU_IFUNC
+ && 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* rela_dyn =
+ target->rela_irelative_section(layout);
+ unsigned int r_type = elfcpp::R_X86_64_IRELATIVE;
+ rela_dyn->add_symbolless_global_addend(gsym, r_type,
+ output_section, object,
+ data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ else if (((size == 64 && r_type == elfcpp::R_X86_64_64)
+ || (size == 32 && r_type == elfcpp::R_X86_64_32))
+ && gsym->can_use_relative_reloc(false))
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_RELATIVE,
+ output_section, object,
+ data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend(), false);
+ }
+ else
+ {
+ this->check_non_pic(object, r_type, gsym);
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_global(gsym, r_type, output_section, object,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ }
+ }
+ break;
+
+ case elfcpp::R_X86_64_PC64:
+ case elfcpp::R_X86_64_PC32:
+ case elfcpp::R_X86_64_PC16:
+ case elfcpp::R_X86_64_PC8:
+ {
+ // Make a PLT entry if necessary.
+ if (gsym->needs_plt_entry())
+ target->make_plt_entry(symtab, layout, gsym);
+ // Make a dynamic relocation if necessary.
+ if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+ {
+ if (gsym->may_need_copy_reloc())
+ {
+ target->copy_reloc(symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
+ }
+ else
+ {
+ this->check_non_pic(object, r_type, gsym);
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_global(gsym, r_type, output_section, object,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ }
+ }
+ break;
+
+ case elfcpp::R_X86_64_GOT64:
+ case elfcpp::R_X86_64_GOT32:
+ case elfcpp::R_X86_64_GOTPCREL64:
+ case elfcpp::R_X86_64_GOTPCREL:
+ case elfcpp::R_X86_64_GOTPLT64:
+ {
+ // The symbol requires a GOT entry.
+ Output_data_got<64, false>* got = target->got_section(symtab, layout);
+ if (gsym->final_value_is_known())
+ {
+ // 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
+ // dynamic relocation for it.
+ Reloc_section* rela_dyn = target->rela_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, rela_dyn,
+ elfcpp::R_X86_64_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);
+ rela_dyn->add_global_relative(gsym,
+ elfcpp::R_X86_64_RELATIVE,
+ got, got_off, 0, false);
+ }
+ }
+ }
+ // For GOTPLT64, we also need a PLT entry (but only if the
+ // symbol is not fully resolved).
+ if (r_type == elfcpp::R_X86_64_GOTPLT64
+ && !gsym->final_value_is_known())
+ target->make_plt_entry(symtab, layout, gsym);
+ }
+ break;
+
+ case elfcpp::R_X86_64_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_X86_64_GOTPC32:
+ case elfcpp::R_X86_64_GOTOFF64:
+ case elfcpp::R_X86_64_GOTPC64:
+ case elfcpp::R_X86_64_PLTOFF64:
+ // We need a GOT section.
+ target->got_section(symtab, layout);
+ // For PLTOFF64, we also need a PLT entry (but only if the
+ // symbol is not fully resolved).
+ if (r_type == elfcpp::R_X86_64_PLTOFF64
+ && !gsym->final_value_is_known())
+ target->make_plt_entry(symtab, layout, gsym);
+ break;
+
+ case elfcpp::R_X86_64_COPY:
+ case elfcpp::R_X86_64_GLOB_DAT:
+ case elfcpp::R_X86_64_JUMP_SLOT:
+ case elfcpp::R_X86_64_RELATIVE:
+ case elfcpp::R_X86_64_IRELATIVE:
+ // These are outstanding tls relocs, which are unexpected when linking
+ case elfcpp::R_X86_64_TPOFF64:
+ case elfcpp::R_X86_64_DTPMOD64:
+ case elfcpp::R_X86_64_TLSDESC:
+ gold_error(_("%s: unexpected reloc %u in object file"),
+ object->name().c_str(), r_type);
+ break;
+
+ // These are initial tls relocs, which are expected for global()
+ case elfcpp::R_X86_64_TLSGD: // Global-dynamic
+ case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
+ case elfcpp::R_X86_64_TLSDESC_CALL:
+ case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ case elfcpp::R_X86_64_DTPOFF32:
+ case elfcpp::R_X86_64_DTPOFF64:
+ case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
+ case elfcpp::R_X86_64_TPOFF32: // Local-exec
+ {
+ const bool is_final = gsym->final_value_is_known();
+ const tls::Tls_optimization optimized_type
+ = Target_x86_64<size>::optimize_tls_reloc(is_final, r_type);
+ switch (r_type)
+ {
+ case elfcpp::R_X86_64_TLSGD: // General-dynamic
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
+ target->rela_dyn_section(layout),
+ elfcpp::R_X86_64_DTPMOD64,
+ elfcpp::R_X86_64_DTPOFF64);
+ }
+ else if (optimized_type == tls::TLSOPT_TO_IE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ target->rela_dyn_section(layout),
+ elfcpp::R_X86_64_TPOFF64);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_global(object, r_type, gsym);
+ break;
+
+ case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+ target->define_tls_base_symbol(symtab, layout);
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create reserved PLT and GOT entries for the resolver.
+ target->reserve_tlsdesc_entries(symtab, layout);
+
+ // Create a double GOT entry with an R_X86_64_TLSDESC
+ // reloc. The R_X86_64_TLSDESC reloc is resolved
+ // lazily, so the GOT entry needs to be in an area in
+ // .got.plt, not .got. Call got_section to make sure
+ // the section has been created.
+ target->got_section(symtab, layout);
+ Output_data_got<64, false>* got = target->got_tlsdesc_section();
+ Reloc_section* rt = target->rela_tlsdesc_section(layout);
+ got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC, rt,
+ elfcpp::R_X86_64_TLSDESC, 0);
+ }
+ else if (optimized_type == tls::TLSOPT_TO_IE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ target->rela_dyn_section(layout),
+ elfcpp::R_X86_64_TPOFF64);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_global(object, r_type, gsym);
+ break;
+
+ case elfcpp::R_X86_64_TLSDESC_CALL:
+ break;
+
+ case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the module index.
+ target->got_mod_index_entry(symtab, layout, object);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_global(object, r_type, gsym);
+ break;
+
+ case elfcpp::R_X86_64_DTPOFF32:
+ case elfcpp::R_X86_64_DTPOFF64:
+ break;
+
+ case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
+ layout->set_has_static_tls();
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ target->rela_dyn_section(layout),
+ elfcpp::R_X86_64_TPOFF64);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_global(object, r_type, gsym);
+ break;
+
+ case elfcpp::R_X86_64_TPOFF32: // Local-exec
+ layout->set_has_static_tls();
+ if (parameters->options().shared())
+ unsupported_reloc_global(object, r_type, gsym);
+ break;
+
+ default:
+ gold_unreachable();
+ }
+ }
+ break;
+
+ case elfcpp::R_X86_64_SIZE32:
+ case elfcpp::R_X86_64_SIZE64:
+ default:
+ gold_error(_("%s: unsupported reloc %u against global symbol %s"),
+ object->name().c_str(), r_type,
+ gsym->demangled_name().c_str());
+ break;
+ }
+}
+
+template<int size>
+void
+Target_x86_64<size>::gc_process_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols)
+{
+
+ if (sh_type == elfcpp::SHT_REL)
+ {
+ return;
+ }
+
+ gold::gc_process_relocs<size, false, Target_x86_64<size>, elfcpp::SHT_RELA,
+ typename Target_x86_64<size>::Scan,
+ typename Target_x86_64<size>::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<int size>
+void
+Target_x86_64<size>::scan_relocs(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols)
+{
+ if (sh_type == elfcpp::SHT_REL)
+ {
+ gold_error(_("%s: unsupported REL reloc section"),
+ object->name().c_str());
+ return;
+ }
+
+ gold::scan_relocs<size, false, Target_x86_64<size>, elfcpp::SHT_RELA,
+ typename Target_x86_64<size>::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<int size>
+void
+Target_x86_64<size>::do_finalize_sections(
+ Layout* layout,
+ const Input_objects*,
+ Symbol_table* symtab)
+{
+ const Reloc_section* rel_plt = (this->plt_ == NULL
+ ? NULL
+ : this->plt_->rela_plt());
+ layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt,
+ this->rela_dyn_, true, false);
+
+ // Fill in some more dynamic tags.
+ Output_data_dynamic* const odyn = layout->dynamic_data();
+ if (odyn != NULL)
+ {
+ if (this->plt_ != NULL
+ && this->plt_->output_section() != NULL
+ && this->plt_->has_tlsdesc_entry())
+ {
+ unsigned int plt_offset = this->plt_->get_tlsdesc_plt_offset();
+ unsigned int got_offset = this->plt_->get_tlsdesc_got_offset();
+ this->got_->finalize_data_size();
+ odyn->add_section_plus_offset(elfcpp::DT_TLSDESC_PLT,
+ this->plt_, plt_offset);
+ odyn->add_section_plus_offset(elfcpp::DT_TLSDESC_GOT,
+ this->got_, got_offset);
+ }
+ }
+
+ // 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->rela_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)
+ {
+ uint64_t data_size = this->got_plt_->current_data_size();
+ symtab->get_sized_symbol<size>(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 __rela_iplt symbols
+ // were defined if necessary, even if we didn't create a PLT.
+ static const Define_symbol_in_segment syms[] =
+ {
+ {
+ "__rela_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
+ },
+ {
+ "__rela_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());
+ }
+}
+
+// Perform a relocation.
+
+template<int size>
+inline bool
+Target_x86_64<size>::Relocate::relocate(
+ const Relocate_info<size, false>* relinfo,
+ Target_x86_64<size>* target,
+ Output_section*,
+ size_t relnum,
+ const elfcpp::Rela<size, false>& rela,
+ unsigned int r_type,
+ const Sized_symbol<size>* gsym,
+ const Symbol_value<size>* psymval,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size)
+{
+ if (this->skip_call_tls_get_addr_)
+ {
+ if ((r_type != elfcpp::R_X86_64_PLT32
+ && r_type != elfcpp::R_X86_64_PC32)
+ || gsym == NULL
+ || strcmp(gsym->name(), "__tls_get_addr") != 0)
+ {
+ gold_error_at_location(relinfo, relnum, rela.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<size, false>* object = relinfo->object;
+
+ // Pick the value to use for symbols defined in the PLT.
+ Symbol_value<size> symval;
+ 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<size>(rela.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;
+ }
+ }
+
+ const elfcpp::Elf_Xword addend = rela.get_r_addend();
+
+ // 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_X86_64_GOT32:
+ case elfcpp::R_X86_64_GOT64:
+ case elfcpp::R_X86_64_GOTPLT64:
+ case elfcpp::R_X86_64_GOTPCREL:
+ case elfcpp::R_X86_64_GOTPCREL64:
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+ got_offset = gsym->got_offset(GOT_TYPE_STANDARD) - target->got_size();
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+ got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD)
+ - target->got_size());
+ }
+ have_got_offset = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (r_type)
+ {
+ case elfcpp::R_X86_64_NONE:
+ case elfcpp::R_X86_64_GNU_VTINHERIT:
+ case elfcpp::R_X86_64_GNU_VTENTRY:
+ break;
+
+ case elfcpp::R_X86_64_64:
+ Relocate_functions<size, false>::rela64(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_X86_64_PC64:
+ Relocate_functions<size, false>::pcrela64(view, object, psymval, addend,
+ address);
+ break;
+
+ case elfcpp::R_X86_64_32:
+ // FIXME: we need to verify that value + addend fits into 32 bits:
+ // uint64_t x = value + addend;
+ // x == static_cast<uint64_t>(static_cast<uint32_t>(x))
+ // Likewise for other <=32-bit relocations (but see R_X86_64_32S).
+ Relocate_functions<size, false>::rela32(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_X86_64_32S:
+ // FIXME: we need to verify that value + addend fits into 32 bits:
+ // int64_t x = value + addend; // note this quantity is signed!
+ // x == static_cast<int64_t>(static_cast<int32_t>(x))
+ Relocate_functions<size, false>::rela32(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_X86_64_PC32:
+ Relocate_functions<size, false>::pcrela32(view, object, psymval, addend,
+ address);
+ break;
+
+ case elfcpp::R_X86_64_16:
+ Relocate_functions<size, false>::rela16(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_X86_64_PC16:
+ Relocate_functions<size, false>::pcrela16(view, object, psymval, addend,
+ address);
+ break;
+
+ case elfcpp::R_X86_64_8:
+ Relocate_functions<size, false>::rela8(view, object, psymval, addend);
+ break;
+
+ case elfcpp::R_X86_64_PC8:
+ Relocate_functions<size, false>::pcrela8(view, object, psymval, addend,
+ address);
+ break;
+
+ case elfcpp::R_X86_64_PLT32:
+ gold_assert(gsym == NULL
+ || gsym->has_plt_offset()
+ || gsym->final_value_is_known()
+ || (gsym->is_defined()
+ && !gsym->is_from_dynobj()
+ && !gsym->is_preemptible()));
+ // Note: while this code looks the same as for R_X86_64_PC32, it
+ // behaves differently because psymval was set to point to
+ // the PLT entry, rather than the symbol, in Scan::global().
+ Relocate_functions<size, false>::pcrela32(view, object, psymval, addend,
+ address);
+ break;
+
+ case elfcpp::R_X86_64_PLTOFF64:
+ {
+ gold_assert(gsym);
+ gold_assert(gsym->has_plt_offset()
+ || gsym->final_value_is_known());
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address;
+ got_address = target->got_section(NULL, NULL)->address();
+ Relocate_functions<size, false>::rela64(view, object, psymval,
+ addend - got_address);
+ }
+
+ case elfcpp::R_X86_64_GOT32:
+ gold_assert(have_got_offset);
+ Relocate_functions<size, false>::rela32(view, got_offset, addend);
+ break;
+
+ case elfcpp::R_X86_64_GOTPC32:
+ {
+ gold_assert(gsym);
+ typename elfcpp::Elf_types<size>::Elf_Addr value;
+ value = target->got_plt_section()->address();
+ Relocate_functions<size, false>::pcrela32(view, value, addend, address);
+ }
+ break;
+
+ case elfcpp::R_X86_64_GOT64:
+ // The ABI doc says "Like GOT64, but indicates a PLT entry is needed."
+ // Since we always add a PLT entry, this is equivalent.
+ case elfcpp::R_X86_64_GOTPLT64:
+ gold_assert(have_got_offset);
+ Relocate_functions<size, false>::rela64(view, got_offset, addend);
+ break;
+
+ case elfcpp::R_X86_64_GOTPC64:
+ {
+ gold_assert(gsym);
+ typename elfcpp::Elf_types<size>::Elf_Addr value;
+ value = target->got_plt_section()->address();
+ Relocate_functions<size, false>::pcrela64(view, value, addend, address);
+ }
+ break;
+
+ case elfcpp::R_X86_64_GOTOFF64:
+ {
+ typename elfcpp::Elf_types<size>::Elf_Addr value;
+ value = (psymval->value(object, 0)
+ - target->got_plt_section()->address());
+ Relocate_functions<size, false>::rela64(view, value, addend);
+ }
+ break;
+
+ case elfcpp::R_X86_64_GOTPCREL:
+ {
+ gold_assert(have_got_offset);
+ typename elfcpp::Elf_types<size>::Elf_Addr value;
+ value = target->got_plt_section()->address() + got_offset;
+ Relocate_functions<size, false>::pcrela32(view, value, addend, address);
+ }
+ break;
+
+ case elfcpp::R_X86_64_GOTPCREL64:
+ {
+ gold_assert(have_got_offset);
+ typename elfcpp::Elf_types<size>::Elf_Addr value;
+ value = target->got_plt_section()->address() + got_offset;
+ Relocate_functions<size, false>::pcrela64(view, value, addend, address);
+ }
+ break;
+
+ case elfcpp::R_X86_64_COPY:
+ case elfcpp::R_X86_64_GLOB_DAT:
+ case elfcpp::R_X86_64_JUMP_SLOT:
+ case elfcpp::R_X86_64_RELATIVE:
+ case elfcpp::R_X86_64_IRELATIVE:
+ // These are outstanding tls relocs, which are unexpected when linking
+ case elfcpp::R_X86_64_TPOFF64:
+ case elfcpp::R_X86_64_DTPMOD64:
+ case elfcpp::R_X86_64_TLSDESC:
+ gold_error_at_location(relinfo, relnum, rela.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_X86_64_TLSGD: // Global-dynamic
+ case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
+ case elfcpp::R_X86_64_TLSDESC_CALL:
+ case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ case elfcpp::R_X86_64_DTPOFF32:
+ case elfcpp::R_X86_64_DTPOFF64:
+ case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
+ case elfcpp::R_X86_64_TPOFF32: // Local-exec
+ this->relocate_tls(relinfo, target, relnum, rela, r_type, gsym, psymval,
+ view, address, view_size);
+ break;
+
+ case elfcpp::R_X86_64_SIZE32:
+ case elfcpp::R_X86_64_SIZE64:
+ default:
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unsupported reloc %u"),
+ r_type);
+ break;
+ }
+
+ return true;
+}
+
+// Perform a TLS relocation.
+
+template<int size>
+inline void
+Target_x86_64<size>::Relocate::relocate_tls(
+ const Relocate_info<size, false>* relinfo,
+ Target_x86_64<size>* target,
+ size_t relnum,
+ const elfcpp::Rela<size, false>& rela,
+ unsigned int r_type,
+ const Sized_symbol<size>* gsym,
+ const Symbol_value<size>* psymval,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size)
+{
+ Output_segment* tls_segment = relinfo->layout->tls_segment();
+
+ const Sized_relobj_file<size, false>* object = relinfo->object;
+ const elfcpp::Elf_Xword addend = rela.get_r_addend();
+ elfcpp::Shdr<size, false> data_shdr(relinfo->data_shdr);
+ bool is_executable = (data_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0;
+
+ typename elfcpp::Elf_types<size>::Elf_Addr value = psymval->value(relinfo->object, 0);
+
+ const bool is_final = (gsym == NULL
+ ? !parameters->options().shared()
+ : gsym->final_value_is_known());
+ tls::Tls_optimization optimized_type
+ = Target_x86_64<size>::optimize_tls_reloc(is_final, r_type);
+ switch (r_type)
+ {
+ case elfcpp::R_X86_64_TLSGD: // Global-dynamic
+ if (!is_executable && optimized_type == tls::TLSOPT_TO_LE)
+ {
+ // If this code sequence is used in a non-executable section,
+ // we will not optimize the R_X86_64_DTPOFF32/64 relocation,
+ // on the assumption that it's being used by itself in a debug
+ // section. Therefore, in the unlikely event that the code
+ // sequence appears in a non-executable section, we simply
+ // leave it unoptimized.
+ optimized_type = tls::TLSOPT_NONE;
+ }
+ 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,
+ rela, r_type, value, view,
+ view_size);
+ break;
+ }
+ else
+ {
+ unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+ ? GOT_TYPE_TLS_OFFSET
+ : GOT_TYPE_TLS_PAIR);
+ unsigned int got_offset;
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(got_type));
+ got_offset = gsym->got_offset(got_type) - target->got_size();
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset = (object->local_got_offset(r_sym, got_type)
+ - target->got_size());
+ }
+ if (optimized_type == tls::TLSOPT_TO_IE)
+ {
+ value = target->got_plt_section()->address() + got_offset;
+ this->tls_gd_to_ie(relinfo, relnum, tls_segment, rela, r_type,
+ value, view, address, view_size);
+ break;
+ }
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Relocate the field with the offset of the pair of GOT
+ // entries.
+ value = target->got_plt_section()->address() + got_offset;
+ Relocate_functions<size, false>::pcrela32(view, value, addend,
+ address);
+ break;
+ }
+ }
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unsupported reloc %u"), r_type);
+ break;
+
+ case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
+ case elfcpp::R_X86_64_TLSDESC_CALL:
+ if (!is_executable && optimized_type == tls::TLSOPT_TO_LE)
+ {
+ // See above comment for R_X86_64_TLSGD.
+ optimized_type = tls::TLSOPT_NONE;
+ }
+ 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,
+ rela, r_type, value, view,
+ view_size);
+ break;
+ }
+ else
+ {
+ unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+ ? GOT_TYPE_TLS_OFFSET
+ : GOT_TYPE_TLS_DESC);
+ unsigned int got_offset = 0;
+ if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC
+ && 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<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset += (object->local_got_offset(r_sym, got_type)
+ - target->got_size());
+ }
+ if (optimized_type == tls::TLSOPT_TO_IE)
+ {
+ if (tls_segment == NULL)
+ {
+ gold_assert(parameters->errors()->error_count() > 0
+ || issue_undefined_symbol_error(gsym));
+ return;
+ }
+ value = target->got_plt_section()->address() + got_offset;
+ this->tls_desc_gd_to_ie(relinfo, relnum, tls_segment,
+ rela, r_type, value, view, address,
+ view_size);
+ break;
+ }
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
+ {
+ // Relocate the field with the offset of the pair of GOT
+ // entries.
+ value = target->got_plt_section()->address() + got_offset;
+ Relocate_functions<size, false>::pcrela32(view, value, addend,
+ address);
+ }
+ break;
+ }
+ }
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unsupported reloc %u"), r_type);
+ break;
+
+ case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ if (!is_executable && optimized_type == tls::TLSOPT_TO_LE)
+ {
+ // See above comment for R_X86_64_TLSGD.
+ optimized_type = tls::TLSOPT_NONE;
+ }
+ 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, rela, r_type,
+ value, view, view_size);
+ break;
+ }
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Relocate the field with the offset of the GOT entry for
+ // the module index.
+ unsigned int got_offset;
+ got_offset = (target->got_mod_index_entry(NULL, NULL, NULL)
+ - target->got_size());
+ value = target->got_plt_section()->address() + got_offset;
+ Relocate_functions<size, false>::pcrela32(view, value, addend,
+ address);
+ break;
+ }
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unsupported reloc %u"), r_type);
+ break;
+
+ case elfcpp::R_X86_64_DTPOFF32:
+ // This relocation type is used in debugging information.
+ // In that case we need to not optimize the value. If the
+ // section is not executable, then we assume we should not
+ // optimize this reloc. See comments above for R_X86_64_TLSGD,
+ // R_X86_64_GOTPC32_TLSDESC, R_X86_64_TLSDESC_CALL, and
+ // R_X86_64_TLSLD.
+ if (optimized_type == tls::TLSOPT_TO_LE && is_executable)
+ {
+ if (tls_segment == NULL)
+ {
+ gold_assert(parameters->errors()->error_count() > 0
+ || issue_undefined_symbol_error(gsym));
+ return;
+ }
+ value -= tls_segment->memsz();
+ }
+ Relocate_functions<size, false>::rela32(view, value, addend);
+ break;
+
+ case elfcpp::R_X86_64_DTPOFF64:
+ // See R_X86_64_DTPOFF32, just above, for why we check for is_executable.
+ if (optimized_type == tls::TLSOPT_TO_LE && is_executable)
+ {
+ if (tls_segment == NULL)
+ {
+ gold_assert(parameters->errors()->error_count() > 0
+ || issue_undefined_symbol_error(gsym));
+ return;
+ }
+ value -= tls_segment->memsz();
+ }
+ Relocate_functions<size, false>::rela64(view, value, addend);
+ break;
+
+ case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
+ 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_x86_64<size>::Relocate::tls_ie_to_le(relinfo, relnum,
+ tls_segment, rela,
+ r_type, value, view,
+ view_size);
+ break;
+ }
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Relocate the field with the offset of the GOT entry for
+ // the tp-relative offset of the symbol.
+ unsigned int got_offset;
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
+ got_offset = (gsym->got_offset(GOT_TYPE_TLS_OFFSET)
+ - target->got_size());
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym,
+ GOT_TYPE_TLS_OFFSET));
+ got_offset = (object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET)
+ - target->got_size());
+ }
+ value = target->got_plt_section()->address() + got_offset;
+ Relocate_functions<size, false>::pcrela32(view, value, addend,
+ address);
+ break;
+ }
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unsupported reloc type %u"),
+ r_type);
+ break;
+
+ case elfcpp::R_X86_64_TPOFF32: // Local-exec
+ if (tls_segment == NULL)
+ {
+ gold_assert(parameters->errors()->error_count() > 0
+ || issue_undefined_symbol_error(gsym));
+ return;
+ }
+ value -= tls_segment->memsz();
+ Relocate_functions<size, false>::rela32(view, value, addend);
+ break;
+ }
+}
+
+// Do a relocation in which we convert a TLS General-Dynamic to an
+// Initial-Exec.
+
+template<int size>
+inline void
+Target_x86_64<size>::Relocate::tls_gd_to_ie(
+ const Relocate_info<size, false>* relinfo,
+ size_t relnum,
+ Output_segment*,
+ const elfcpp::Rela<size, false>& rela,
+ unsigned int,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size)
+{
+ // For SIZE == 64:
+ // .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
+ // .word 0x6666; rex64; call __tls_get_addr
+ // ==> movq %fs:0,%rax; addq x@gottpoff(%rip),%rax
+ // For SIZE == 32:
+ // leaq foo@tlsgd(%rip),%rdi;
+ // .word 0x6666; rex64; call __tls_get_addr
+ // ==> movl %fs:0,%eax; addq x@gottpoff(%rip),%rax
+
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12);
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0));
+
+ if (size == 64)
+ {
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size,
+ -4);
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0));
+ memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0\0",
+ 16);
+ }
+ else
+ {
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size,
+ -3);
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ (memcmp(view - 3, "\x48\x8d\x3d", 3) == 0));
+ memcpy(view - 3, "\x64\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0\0",
+ 15);
+ }
+
+ const elfcpp::Elf_Xword addend = rela.get_r_addend();
+ Relocate_functions<size, false>::pcrela32(view + 8, value, addend - 8,
+ address);
+
+ // 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 a
+// Local-Exec.
+
+template<int size>
+inline void
+Target_x86_64<size>::Relocate::tls_gd_to_le(
+ const Relocate_info<size, false>* relinfo,
+ size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rela<size, false>& rela,
+ unsigned int,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ unsigned char* view,
+ section_size_type view_size)
+{
+ // For SIZE == 64:
+ // .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
+ // .word 0x6666; rex64; call __tls_get_addr
+ // ==> movq %fs:0,%rax; leaq x@tpoff(%rax),%rax
+ // For SIZE == 32:
+ // leaq foo@tlsgd(%rip),%rdi;
+ // .word 0x6666; rex64; call __tls_get_addr
+ // ==> movl %fs:0,%eax; leaq x@tpoff(%rax),%rax
+
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12);
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0));
+
+ if (size == 64)
+ {
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size,
+ -4);
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0));
+ memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0\0",
+ 16);
+ }
+ else
+ {
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size,
+ -3);
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ (memcmp(view - 3, "\x48\x8d\x3d", 3) == 0));
+
+ memcpy(view - 3, "\x64\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0\0",
+ 15);
+ }
+
+ value -= tls_segment->memsz();
+ Relocate_functions<size, false>::rela32(view + 8, value, 0);
+
+ // 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 TLSDESC-style General-Dynamic to Initial-Exec transition.
+
+template<int size>
+inline void
+Target_x86_64<size>::Relocate::tls_desc_gd_to_ie(
+ const Relocate_info<size, false>* relinfo,
+ size_t relnum,
+ Output_segment*,
+ const elfcpp::Rela<size, false>& rela,
+ unsigned int r_type,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size)
+{
+ if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
+ {
+ // leaq foo@tlsdesc(%rip), %rax
+ // ==> movq foo@gottpoff(%rip), %rax
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05);
+ view[-2] = 0x8b;
+ const elfcpp::Elf_Xword addend = rela.get_r_addend();
+ Relocate_functions<size, false>::pcrela32(view, value, addend, address);
+ }
+ else
+ {
+ // call *foo@tlscall(%rax)
+ // ==> nop; nop
+ gold_assert(r_type == elfcpp::R_X86_64_TLSDESC_CALL);
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 2);
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ view[0] == 0xff && view[1] == 0x10);
+ view[0] = 0x66;
+ view[1] = 0x90;
+ }
+}
+
+// Do a TLSDESC-style General-Dynamic to Local-Exec transition.
+
+template<int size>
+inline void
+Target_x86_64<size>::Relocate::tls_desc_gd_to_le(
+ const Relocate_info<size, false>* relinfo,
+ size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rela<size, false>& rela,
+ unsigned int r_type,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ unsigned char* view,
+ section_size_type view_size)
+{
+ if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
+ {
+ // leaq foo@tlsdesc(%rip), %rax
+ // ==> movq foo@tpoff, %rax
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05);
+ view[-2] = 0xc7;
+ view[-1] = 0xc0;
+ value -= tls_segment->memsz();
+ Relocate_functions<size, false>::rela32(view, value, 0);
+ }
+ else
+ {
+ // call *foo@tlscall(%rax)
+ // ==> nop; nop
+ gold_assert(r_type == elfcpp::R_X86_64_TLSDESC_CALL);
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 2);
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ view[0] == 0xff && view[1] == 0x10);
+ view[0] = 0x66;
+ view[1] = 0x90;
+ }
+}
+
+template<int size>
+inline void
+Target_x86_64<size>::Relocate::tls_ld_to_le(
+ const Relocate_info<size, false>* relinfo,
+ size_t relnum,
+ Output_segment*,
+ const elfcpp::Rela<size, false>& rela,
+ unsigned int,
+ typename elfcpp::Elf_types<size>::Elf_Addr,
+ unsigned char* view,
+ section_size_type view_size)
+{
+ // leaq foo@tlsld(%rip),%rdi; call __tls_get_addr@plt;
+ // For SIZE == 64:
+ // ... leq foo@dtpoff(%rax),%reg
+ // ==> .word 0x6666; .byte 0x66; movq %fs:0,%rax ... leaq x@tpoff(%rax),%rdx
+ // For SIZE == 32:
+ // ... leq foo@dtpoff(%rax),%reg
+ // ==> nopl 0x0(%rax); movl %fs:0,%eax ... leaq x@tpoff(%rax),%rdx
+
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 9);
+
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x3d);
+
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(), view[4] == 0xe8);
+
+ if (size == 64)
+ memcpy(view - 3, "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0\0", 12);
+ else
+ memcpy(view - 3, "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0\0", 12);
+
+ // 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.
+
+template<int size>
+inline void
+Target_x86_64<size>::Relocate::tls_ie_to_le(
+ const Relocate_info<size, false>* relinfo,
+ size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rela<size, false>& rela,
+ unsigned int,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ unsigned char* view,
+ section_size_type view_size)
+{
+ // We need to examine the opcodes to figure out which instruction we
+ // are looking at.
+
+ // movq foo@gottpoff(%rip),%reg ==> movq $YY,%reg
+ // addq foo@gottpoff(%rip),%reg ==> addq $YY,%reg
+
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
+
+ unsigned char op1 = view[-3];
+ unsigned char op2 = view[-2];
+ unsigned char op3 = view[-1];
+ unsigned char reg = op3 >> 3;
+
+ if (op2 == 0x8b)
+ {
+ // movq
+ if (op1 == 0x4c)
+ view[-3] = 0x49;
+ view[-2] = 0xc7;
+ view[-1] = 0xc0 | reg;
+ }
+ else if (reg == 4)
+ {
+ // Special handling for %rsp.
+ if (op1 == 0x4c)
+ view[-3] = 0x49;
+ view[-2] = 0x81;
+ view[-1] = 0xc0 | reg;
+ }
+ else
+ {
+ // addq
+ if (op1 == 0x4c)
+ view[-3] = 0x4d;
+ view[-2] = 0x8d;
+ view[-1] = 0x80 | reg | (reg << 3);
+ }
+
+ value -= tls_segment->memsz();
+ Relocate_functions<size, false>::rela32(view, value, 0);
+}
+
+// Relocate section data.
+
+template<int size>
+void
+Target_x86_64<size>::relocate_section(
+ const Relocate_info<size, 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,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size,
+ const Reloc_symbol_changes* reloc_symbol_changes)
+{
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+
+ gold::relocate_section<size, false, Target_x86_64<size>, elfcpp::SHT_RELA,
+ typename Target_x86_64<size>::Relocate,
+ gold::Default_comdat_behavior>(
+ relinfo,
+ this,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ view,
+ address,
+ view_size,
+ reloc_symbol_changes);
+}
+
+// Apply an incremental relocation. Incremental relocations always refer
+// to global symbols.
+
+template<int size>
+void
+Target_x86_64<size>::apply_relocation(
+ const Relocate_info<size, false>* relinfo,
+ typename elfcpp::Elf_types<size>::Elf_Addr r_offset,
+ unsigned int r_type,
+ typename elfcpp::Elf_types<size>::Elf_Swxword r_addend,
+ const Symbol* gsym,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size)
+{
+ gold::apply_relocation<size, false, Target_x86_64<size>,
+ typename Target_x86_64<size>::Relocate>(
+ relinfo,
+ this,
+ r_offset,
+ r_type,
+ r_addend,
+ gsym,
+ view,
+ address,
+ view_size);
+}
+
+// Return the size of a relocation while scanning during a relocatable
+// link.
+
+template<int size>
+unsigned int
+Target_x86_64<size>::Relocatable_size_for_reloc::get_size_for_reloc(
+ unsigned int r_type,
+ Relobj* object)
+{
+ switch (r_type)
+ {
+ case elfcpp::R_X86_64_NONE:
+ case elfcpp::R_X86_64_GNU_VTINHERIT:
+ case elfcpp::R_X86_64_GNU_VTENTRY:
+ case elfcpp::R_X86_64_TLSGD: // Global-dynamic
+ case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
+ case elfcpp::R_X86_64_TLSDESC_CALL:
+ case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ case elfcpp::R_X86_64_DTPOFF32:
+ case elfcpp::R_X86_64_DTPOFF64:
+ case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
+ case elfcpp::R_X86_64_TPOFF32: // Local-exec
+ return 0;
+
+ case elfcpp::R_X86_64_64:
+ case elfcpp::R_X86_64_PC64:
+ case elfcpp::R_X86_64_GOTOFF64:
+ case elfcpp::R_X86_64_GOTPC64:
+ case elfcpp::R_X86_64_PLTOFF64:
+ case elfcpp::R_X86_64_GOT64:
+ case elfcpp::R_X86_64_GOTPCREL64:
+ case elfcpp::R_X86_64_GOTPCREL:
+ case elfcpp::R_X86_64_GOTPLT64:
+ return 8;
+
+ case elfcpp::R_X86_64_32:
+ case elfcpp::R_X86_64_32S:
+ case elfcpp::R_X86_64_PC32:
+ case elfcpp::R_X86_64_PLT32:
+ case elfcpp::R_X86_64_GOTPC32:
+ case elfcpp::R_X86_64_GOT32:
+ return 4;
+
+ case elfcpp::R_X86_64_16:
+ case elfcpp::R_X86_64_PC16:
+ return 2;
+
+ case elfcpp::R_X86_64_8:
+ case elfcpp::R_X86_64_PC8:
+ return 1;
+
+ case elfcpp::R_X86_64_COPY:
+ case elfcpp::R_X86_64_GLOB_DAT:
+ case elfcpp::R_X86_64_JUMP_SLOT:
+ case elfcpp::R_X86_64_RELATIVE:
+ case elfcpp::R_X86_64_IRELATIVE:
+ // These are outstanding tls relocs, which are unexpected when linking
+ case elfcpp::R_X86_64_TPOFF64:
+ case elfcpp::R_X86_64_DTPMOD64:
+ case elfcpp::R_X86_64_TLSDESC:
+ object->error(_("unexpected reloc %u in object file"), r_type);
+ return 0;
+
+ case elfcpp::R_X86_64_SIZE32:
+ case elfcpp::R_X86_64_SIZE64:
+ default:
+ object->error(_("unsupported reloc %u against local symbol"), r_type);
+ return 0;
+ }
+}
+
+// Scan the relocs during a relocatable link.
+
+template<int size>
+void
+Target_x86_64<size>::scan_relocatable_relocs(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols,
+ Relocatable_relocs* rr)
+{
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+
+ typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
+ Relocatable_size_for_reloc> Scan_relocatable_relocs;
+
+ gold::scan_relocatable_relocs<size, false, elfcpp::SHT_RELA,
+ Scan_relocatable_relocs>(
+ symtab,
+ layout,
+ object,
+ data_shndx,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ local_symbol_count,
+ plocal_symbols,
+ rr);
+}
+
+// Relocate a section during a relocatable link.
+
+template<int size>
+void
+Target_x86_64<size>::relocate_relocs(
+ const Relocate_info<size, false>* relinfo,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
+ const Relocatable_relocs* rr,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::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_RELA);
+
+ gold::relocate_relocs<size, false, elfcpp::SHT_RELA>(
+ 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.
+
+template<int size>
+uint64_t
+Target_x86_64<size>::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.
+
+template<int size>
+std::string
+Target_x86_64<size>::do_code_fill(section_size_type length) const
+{
+ if (length >= 16)
+ {
+ // Build a jmpq 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<char*>(&jmp[0]), 5)
+ + std::string(length - 5, static_cast<char>(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] = { '\x0f', '\x1f', '\x00' }; // nop (%rax)
+ const char nop4[4] = { '\x0f', '\x1f', '\x40', // nop 0(%rax)
+ '\x00'};
+ const char nop5[5] = { '\x0f', '\x1f', '\x44', // nop 0(%rax,%rax,1)
+ '\x00', '\x00' };
+ const char nop6[6] = { '\x66', '\x0f', '\x1f', // nopw 0(%rax,%rax,1)
+ '\x44', '\x00', '\x00' };
+ const char nop7[7] = { '\x0f', '\x1f', '\x80', // nopl 0L(%rax)
+ '\x00', '\x00', '\x00',
+ '\x00' };
+ const char nop8[8] = { '\x0f', '\x1f', '\x84', // nopl 0L(%rax,%rax,1)
+ '\x00', '\x00', '\x00',
+ '\x00', '\x00' };
+ const char nop9[9] = { '\x66', '\x0f', '\x1f', // nopw 0L(%rax,%rax,1)
+ '\x84', '\x00', '\x00',
+ '\x00', '\x00', '\x00' };
+ const char nop10[10] = { '\x66', '\x2e', '\x0f', // nopw %cs:0L(%rax,%rax,1)
+ '\x1f', '\x84', '\x00',
+ '\x00', '\x00', '\x00',
+ '\x00' };
+ const char nop11[11] = { '\x66', '\x66', '\x2e', // data16
+ '\x0f', '\x1f', '\x84', // nopw %cs:0L(%rax,%rax,1)
+ '\x00', '\x00', '\x00',
+ '\x00', '\x00' };
+ const char nop12[12] = { '\x66', '\x66', '\x66', // data16; data16
+ '\x2e', '\x0f', '\x1f', // nopw %cs:0L(%rax,%rax,1)
+ '\x84', '\x00', '\x00',
+ '\x00', '\x00', '\x00' };
+ const char nop13[13] = { '\x66', '\x66', '\x66', // data16; data16; data16
+ '\x66', '\x2e', '\x0f', // nopw %cs:0L(%rax,%rax,1)
+ '\x1f', '\x84', '\x00',
+ '\x00', '\x00', '\x00',
+ '\x00' };
+ const char nop14[14] = { '\x66', '\x66', '\x66', // data16; data16; data16
+ '\x66', '\x66', '\x2e', // data16
+ '\x0f', '\x1f', '\x84', // nopw %cs:0L(%rax,%rax,1)
+ '\x00', '\x00', '\x00',
+ '\x00', '\x00' };
+ const char nop15[15] = { '\x66', '\x66', '\x66', // data16; data16; data16
+ '\x66', '\x66', '\x66', // data16; data16
+ '\x2e', '\x0f', '\x1f', // nopw %cs:0L(%rax,%rax,1)
+ '\x84', '\x00', '\x00',
+ '\x00', '\x00', '\x00' };
+
+ 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 addend to use for a target specific relocation. The
+// only target specific relocation is R_X86_64_TLSDESC for a local
+// symbol. We want to set the addend is the offset of the local
+// symbol in the TLS segment.
+
+template<int size>
+uint64_t
+Target_x86_64<size>::do_reloc_addend(void* arg, unsigned int r_type,
+ uint64_t) const
+{
+ gold_assert(r_type == elfcpp::R_X86_64_TLSDESC);
+ uintptr_t intarg = reinterpret_cast<uintptr_t>(arg);
+ gold_assert(intarg < this->tlsdesc_reloc_info_.size());
+ const Tlsdesc_info& ti(this->tlsdesc_reloc_info_[intarg]);
+ const Symbol_value<size>* psymval = ti.object->local_symbol(ti.r_sym);
+ gold_assert(psymval->is_tls_symbol());
+ // The value of a TLS symbol is the offset in the TLS segment.
+ return psymval->value(ti.object, 0);
+}
+
+// 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.
+
+template<int size>
+uint64_t
+Target_x86_64<size>::do_ehframe_datarel_base() const
+{
+ gold_assert(this->global_offset_table_ != NULL);
+ Symbol* sym = this->global_offset_table_;
+ Sized_symbol<size>* ssym = static_cast<Sized_symbol<size>*>(sym);
+ return ssym->value();
+}
+
+// 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.
+
+template<int size>
+void
+Target_x86_64<size>::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 %fs:NN,%rsp
+ if (this->match_view(view, view_size, fnoffset, "\x64\x48\x3b\x24\x25", 5)
+ && fnsize > 9)
+ {
+ // 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, 8);
+ }
+ // lea NN(%rsp),%r10
+ // lea NN(%rsp),%r11
+ else if ((this->match_view(view, view_size, fnoffset,
+ "\x4c\x8d\x94\x24", 4)
+ || this->match_view(view, view_size, fnoffset,
+ "\x4c\x8d\x9c\x24", 4))
+ && fnsize > 8)
+ {
+ // 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 + 4;
+ 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<size_t>(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 x86_64 object files. Note this is never instantiated
+// directly. It's only used in Target_selector_x86_64_nacl, below.
+
+template<int size>
+class Target_selector_x86_64 : public Target_selector_freebsd
+{
+public:
+ Target_selector_x86_64()
+ : Target_selector_freebsd(elfcpp::EM_X86_64, size, false,
+ (size == 64
+ ? "elf64-x86-64" : "elf32-x86-64"),
+ (size == 64
+ ? "elf64-x86-64-freebsd"
+ : "elf32-x86-64-freebsd"),
+ (size == 64 ? "elf_x86_64" : "elf32_x86_64"))
+ { }
+
+ Target*
+ do_instantiate_target()
+ { return new Target_x86_64<size>(); }
+
+};
+
+// NaCl variant. It uses different PLT contents.
+
+template<int size>
+class Output_data_plt_x86_64_nacl : public Output_data_plt_x86_64<size>
+{
+ public:
+ Output_data_plt_x86_64_nacl(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_x86_64<size>(layout, plt_entry_size,
+ got, got_plt, got_irelative)
+ { }
+
+ Output_data_plt_x86_64_nacl(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ : Output_data_plt_x86_64<size>(layout, plt_entry_size,
+ got, got_plt, got_irelative,
+ plt_count)
+ { }
+
+ protected:
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return plt_entry_size; }
+
+ virtual void
+ do_add_eh_frame(Layout* layout)
+ {
+ layout->add_eh_frame_for_plt(this,
+ this->plt_eh_frame_cie,
+ this->plt_eh_frame_cie_size,
+ plt_eh_frame_fde,
+ plt_eh_frame_fde_size);
+ }
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_addr,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_addr);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index);
+
+ virtual void
+ do_fill_tlsdesc_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset);
+
+ private:
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 64;
+
+ // The first entry in the PLT.
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for an executable.
+ static const unsigned char plt_entry[plt_entry_size];
+
+ // The reserved TLSDESC entry in the PLT for an executable.
+ static const unsigned char tlsdesc_plt_entry[plt_entry_size];
+
+ // The .eh_frame unwind information for the PLT.
+ static const int plt_eh_frame_fde_size = 32;
+ static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+};
+
+template<int size>
+class Target_x86_64_nacl : public Target_x86_64<size>
+{
+ public:
+ Target_x86_64_nacl()
+ : Target_x86_64<size>(&x86_64_nacl_info)
+ { }
+
+ virtual Output_data_plt_x86_64<size>*
+ do_make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ {
+ return new Output_data_plt_x86_64_nacl<size>(layout, got, got_plt,
+ got_irelative);
+ }
+
+ virtual Output_data_plt_x86_64<size>*
+ do_make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ {
+ return new Output_data_plt_x86_64_nacl<size>(layout, got, got_plt,
+ got_irelative,
+ plt_count);
+ }
+
+ virtual std::string
+ do_code_fill(section_size_type length) const;
+
+ private:
+ static const Target::Target_info x86_64_nacl_info;
+};
+
+template<>
+const Target::Target_info Target_x86_64_nacl<64>::x86_64_nacl_info =
+{
+ 64, // size
+ false, // is_big_endian
+ elfcpp::EM_X86_64, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ true, // has_code_fill
+ true, // is_default_stack_executable
+ true, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/lib64/ld-nacl-x86-64.so.1", // dynamic_linker
+ 0x20000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // common_pagesize (overridable by -z common-page-size)
+ true, // isolate_execinstr
+ 0x10000000, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx
+ 0, // small_common_section_flags
+ elfcpp::SHF_X86_64_LARGE, // large_common_section_flags
+ NULL, // attributes_section
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
+};
+
+template<>
+const Target::Target_info Target_x86_64_nacl<32>::x86_64_nacl_info =
+{
+ 32, // size
+ false, // is_big_endian
+ elfcpp::EM_X86_64, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ true, // has_code_fill
+ true, // is_default_stack_executable
+ true, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/lib/ld-nacl-x86-64.so.1", // dynamic_linker
+ 0x20000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // common_pagesize (overridable by -z common-page-size)
+ true, // isolate_execinstr
+ 0x10000000, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx
+ 0, // small_common_section_flags
+ elfcpp::SHF_X86_64_LARGE, // large_common_section_flags
+ NULL, // attributes_section
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
+};
+
+#define NACLMASK 0xe0 // 32-byte alignment mask.
+
+// The first entry in the PLT.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_nacl<size>::first_plt_entry[plt_entry_size] =
+{
+ 0xff, 0x35, // pushq contents of memory address
+ 0, 0, 0, 0, // replaced with address of .got + 8
+ 0x4c, 0x8b, 0x1d, // mov GOT+16(%rip), %r11
+ 0, 0, 0, 0, // replaced with address of .got + 16
+ 0x41, 0x83, 0xe3, NACLMASK, // and $-32, %r11d
+ 0x4d, 0x01, 0xfb, // add %r15, %r11
+ 0x41, 0xff, 0xe3, // jmpq *%r11
+
+ // 9-byte nop sequence to pad out to the next 32-byte boundary.
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopl %cs:0x0(%rax,%rax,1)
+
+ // 32 bytes of nop to pad out to the standard size
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x66, // excess data32 prefix
+ 0x90 // nop
+};
+
+template<int size>
+void
+Output_data_plt_x86_64_nacl<size>::do_fill_first_plt_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + 8
+ - (plt_address + 2 + 4)));
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 9,
+ (got_address + 16
+ - (plt_address + 9 + 4)));
+}
+
+// Subsequent entries in the PLT.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_nacl<size>::plt_entry[plt_entry_size] =
+{
+ 0x4c, 0x8b, 0x1d, // mov name@GOTPCREL(%rip),%r11
+ 0, 0, 0, 0, // replaced with address of symbol in .got
+ 0x41, 0x83, 0xe3, NACLMASK, // and $-32, %r11d
+ 0x4d, 0x01, 0xfb, // add %r15, %r11
+ 0x41, 0xff, 0xe3, // jmpq *%r11
+
+ // 15-byte nop sequence to pad out to the next 32-byte boundary.
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+
+ // Lazy GOT entries point here (32-byte aligned).
+ 0x68, // pushq immediate
+ 0, 0, 0, 0, // replaced with index into relocation table
+ 0xe9, // jmp relative
+ 0, 0, 0, 0, // replaced with offset to start of .plt0
+
+ // 22 bytes of nop to pad out to the standard size.
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x0f, 0x1f, 0x80, 0, 0, 0, 0, // nopl 0x0(%rax)
+};
+
+template<int size>
+unsigned int
+Output_data_plt_x86_64_nacl<size>::do_fill_plt_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 3,
+ (got_address + got_offset
+ - (plt_address + plt_offset
+ + 3 + 4)));
+
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 33, plt_index);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 38,
+ - (plt_offset + 38 + 4));
+
+ return 32;
+}
+
+// The reserved TLSDESC entry in the PLT.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_nacl<size>::tlsdesc_plt_entry[plt_entry_size] =
+{
+ 0xff, 0x35, // pushq x(%rip)
+ 0, 0, 0, 0, // replaced with address of linkmap GOT entry (at PLTGOT + 8)
+ 0x4c, 0x8b, 0x1d, // mov y(%rip),%r11
+ 0, 0, 0, 0, // replaced with offset of reserved TLSDESC_GOT entry
+ 0x41, 0x83, 0xe3, NACLMASK, // and $-32, %r11d
+ 0x4d, 0x01, 0xfb, // add %r15, %r11
+ 0x41, 0xff, 0xe3, // jmpq *%r11
+
+ // 41 bytes of nop to pad out to the standard size.
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+};
+
+template<int size>
+void
+Output_data_plt_x86_64_nacl<size>::do_fill_tlsdesc_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset)
+{
+ memcpy(pov, tlsdesc_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + 8
+ - (plt_address + plt_offset
+ + 2 + 4)));
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 9,
+ (got_base
+ + tlsdesc_got_offset
+ - (plt_address + plt_offset
+ + 9 + 4)));
+}
+
+// The .eh_frame unwind information for the PLT.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_nacl<size>::plt_eh_frame_fde[plt_eh_frame_fde_size] =
+{
+ 0, 0, 0, 0, // Replaced with offset to .plt.
+ 0, 0, 0, 0, // Replaced with size of .plt.
+ 0, // Augmentation size.
+ elfcpp::DW_CFA_def_cfa_offset, 16, // DW_CFA_def_cfa_offset: 16.
+ elfcpp::DW_CFA_advance_loc + 6, // Advance 6 to __PLT__ + 6.
+ elfcpp::DW_CFA_def_cfa_offset, 24, // DW_CFA_def_cfa_offset: 24.
+ elfcpp::DW_CFA_advance_loc + 58, // Advance 58 to __PLT__ + 64.
+ elfcpp::DW_CFA_def_cfa_expression, // DW_CFA_def_cfa_expression.
+ 13, // Block length.
+ elfcpp::DW_OP_breg7, 8, // Push %rsp + 8.
+ elfcpp::DW_OP_breg16, 0, // Push %rip.
+ elfcpp::DW_OP_const1u, 63, // Push 0x3f.
+ elfcpp::DW_OP_and, // & (%rip & 0x3f).
+ elfcpp::DW_OP_const1u, 37, // Push 0x25.
+ elfcpp::DW_OP_ge, // >= ((%rip & 0x3f) >= 0x25)
+ elfcpp::DW_OP_lit3, // Push 3.
+ elfcpp::DW_OP_shl, // << (((%rip & 0x3f) >= 0x25) << 3)
+ elfcpp::DW_OP_plus, // + ((((%rip&0x3f)>=0x25)<<3)+%rsp+8
+ elfcpp::DW_CFA_nop, // Align to 32 bytes.
+ elfcpp::DW_CFA_nop
+};
+
+// 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.
+template<int size>
+std::string
+Target_x86_64_nacl<size>::do_code_fill(section_size_type length) const
+{
+ return std::string(length, static_cast<char>(0x90));
+}
+
+// The selector for x86_64-nacl object files.
+
+template<int size>
+class Target_selector_x86_64_nacl
+ : public Target_selector_nacl<Target_selector_x86_64<size>,
+ Target_x86_64_nacl<size> >
+{
+ public:
+ Target_selector_x86_64_nacl()
+ : Target_selector_nacl<Target_selector_x86_64<size>,
+ Target_x86_64_nacl<size> >("x86-64",
+ size == 64
+ ? "elf64-x86-64-nacl"
+ : "elf32-x86-64-nacl",
+ size == 64
+ ? "elf_x86_64_nacl"
+ : "elf32_x86_64_nacl")
+ { }
+};
+
+Target_selector_x86_64_nacl<64> target_selector_x86_64;
+Target_selector_x86_64_nacl<32> target_selector_x32;
+
+} // End anonymous namespace.
diff --git a/binutils-2.25/gold/yyscript.y b/binutils-2.25/gold/yyscript.y
new file mode 100644
index 00000000..51c755ba
--- /dev/null
+++ b/binutils-2.25/gold/yyscript.y
@@ -0,0 +1,1133 @@
+/* yyscript.y -- linker script grammar for gold. */
+
+/* Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>.
+
+ 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 is a bison grammar to parse a subset of the original GNU ld
+ linker script language. */
+
+%{
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "script-c.h"
+
+%}
+
+/* We need to use a pure parser because we might be multi-threaded.
+ We pass some arguments through the parser to the lexer. */
+
+%pure-parser
+
+%parse-param {void* closure}
+%lex-param {void* closure}
+
+/* Since we require bison anyhow, we take advantage of it. */
+
+%error-verbose
+
+/* The values associated with tokens. */
+
+%union {
+ /* A string. */
+ struct Parser_string string;
+ /* A number. */
+ uint64_t integer;
+ /* An expression. */
+ Expression_ptr expr;
+ /* An output section header. */
+ struct Parser_output_section_header output_section_header;
+ /* An output section trailer. */
+ struct Parser_output_section_trailer output_section_trailer;
+ /* A section constraint. */
+ enum Section_constraint constraint;
+ /* A complete input section specification. */
+ struct Input_section_spec input_section_spec;
+ /* A list of wildcard specifications, with exclusions. */
+ struct Wildcard_sections wildcard_sections;
+ /* A single wildcard specification. */
+ struct Wildcard_section wildcard_section;
+ /* A list of strings. */
+ String_list_ptr string_list;
+ /* Information for a program header. */
+ struct Phdr_info phdr_info;
+ /* Used for version scripts and within VERSION {}. */
+ struct Version_dependency_list* deplist;
+ struct Version_expression_list* versyms;
+ struct Version_tree* versnode;
+ enum Script_section_type section_type;
+}
+
+/* Operators, including a precedence table for expressions. */
+
+%right PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ
+%right '?' ':'
+%left OROR
+%left ANDAND
+%left '|'
+%left '^'
+%left '&'
+%left EQ NE
+%left '<' '>' LE GE
+%left LSHIFT RSHIFT
+%left '+' '-'
+%left '*' '/' '%'
+
+/* A fake operator used to indicate unary operator precedence. */
+%right UNARY
+
+/* Constants. */
+
+%token <string> STRING
+%token <string> QUOTED_STRING
+%token <integer> INTEGER
+
+/* Keywords. This list is taken from ldgram.y and ldlex.l in the old
+ GNU linker, with the keywords which only appear in MRI mode
+ removed. Not all these keywords are actually used in this grammar.
+ In most cases the keyword is recognized as the token name in upper
+ case. The comments indicate where this is not the case. */
+
+%token ABSOLUTE
+%token ADDR
+%token ALIGN_K /* ALIGN */
+%token ALIGNOF
+%token ASSERT_K /* ASSERT */
+%token AS_NEEDED
+%token AT
+%token BIND
+%token BLOCK
+%token BYTE
+%token CONSTANT
+%token CONSTRUCTORS
+%token COPY
+%token CREATE_OBJECT_SYMBOLS
+%token DATA_SEGMENT_ALIGN
+%token DATA_SEGMENT_END
+%token DATA_SEGMENT_RELRO_END
+%token DEFINED
+%token DSECT
+%token ENTRY
+%token EXCLUDE_FILE
+%token EXTERN
+%token FILL
+%token FLOAT
+%token FORCE_COMMON_ALLOCATION
+%token GLOBAL /* global */
+%token GROUP
+%token HLL
+%token INCLUDE
+%token INHIBIT_COMMON_ALLOCATION
+%token INFO
+%token INPUT
+%token KEEP
+%token LEN
+%token LENGTH /* LENGTH, l, len */
+%token LOADADDR
+%token LOCAL /* local */
+%token LONG
+%token MAP
+%token MAX_K /* MAX */
+%token MEMORY
+%token MIN_K /* MIN */
+%token NEXT
+%token NOCROSSREFS
+%token NOFLOAT
+%token NOLOAD
+%token ONLY_IF_RO
+%token ONLY_IF_RW
+%token ORG
+%token ORIGIN /* ORIGIN, o, org */
+%token OUTPUT
+%token OUTPUT_ARCH
+%token OUTPUT_FORMAT
+%token OVERLAY
+%token PHDRS
+%token PROVIDE
+%token PROVIDE_HIDDEN
+%token QUAD
+%token SEARCH_DIR
+%token SECTIONS
+%token SEGMENT_START
+%token SHORT
+%token SIZEOF
+%token SIZEOF_HEADERS /* SIZEOF_HEADERS, sizeof_headers */
+%token SORT_BY_ALIGNMENT
+%token SORT_BY_NAME
+%token SPECIAL
+%token SQUAD
+%token STARTUP
+%token SUBALIGN
+%token SYSLIB
+%token TARGET_K /* TARGET */
+%token TRUNCATE
+%token VERSIONK /* VERSION */
+
+/* Keywords, part 2. These are keywords that are unique to gold,
+ and not present in the old GNU linker. As before, unless the
+ comments say otherwise, the keyword is recognized as the token
+ name in upper case. */
+
+%token OPTION
+
+/* Special tokens used to tell the grammar what type of tokens we are
+ parsing. The token stream always begins with one of these tokens.
+ We do this because version scripts can appear embedded within
+ linker scripts, and because --defsym uses the expression
+ parser. */
+%token PARSING_LINKER_SCRIPT
+%token PARSING_VERSION_SCRIPT
+%token PARSING_DEFSYM
+%token PARSING_DYNAMIC_LIST
+
+/* Non-terminal types, where needed. */
+
+%type <expr> parse_exp exp
+%type <expr> opt_at opt_align opt_subalign opt_fill
+%type <output_section_header> section_header opt_address_and_section_type
+%type <section_type> section_type
+%type <output_section_trailer> section_trailer
+%type <constraint> opt_constraint
+%type <string_list> opt_phdr
+%type <integer> data_length
+%type <input_section_spec> input_section_no_keep
+%type <wildcard_sections> wildcard_sections
+%type <wildcard_section> wildcard_file wildcard_section
+%type <string_list> exclude_names
+%type <string> wildcard_name
+%type <integer> phdr_type memory_attr
+%type <phdr_info> phdr_info
+%type <versyms> vers_defns
+%type <versnode> vers_tag
+%type <deplist> verdep
+%type <string> string
+
+%%
+
+/* Read the special token to see what to read next. */
+top:
+ PARSING_LINKER_SCRIPT linker_script
+ | PARSING_VERSION_SCRIPT version_script
+ | PARSING_DEFSYM defsym_expr
+ | PARSING_DYNAMIC_LIST dynamic_list_expr
+ ;
+
+/* A file contains a list of commands. */
+linker_script:
+ linker_script file_cmd
+ | /* empty */
+ ;
+
+/* A command which may appear at top level of a linker script. */
+file_cmd:
+ EXTERN '(' extern_name_list ')'
+ | FORCE_COMMON_ALLOCATION
+ { script_set_common_allocation(closure, 1); }
+ | GROUP
+ { script_start_group(closure); }
+ '(' input_list ')'
+ { script_end_group(closure); }
+ | INHIBIT_COMMON_ALLOCATION
+ { script_set_common_allocation(closure, 0); }
+ | INPUT '(' input_list ')'
+ | MEMORY '{' memory_defs '}'
+ | OPTION '(' string ')'
+ { script_parse_option(closure, $3.value, $3.length); }
+ | OUTPUT_FORMAT '(' string ')'
+ {
+ if (!script_check_output_format(closure, $3.value, $3.length,
+ NULL, 0, NULL, 0))
+ YYABORT;
+ }
+ | OUTPUT_FORMAT '(' string ',' string ',' string ')'
+ {
+ if (!script_check_output_format(closure, $3.value, $3.length,
+ $5.value, $5.length,
+ $7.value, $7.length))
+ YYABORT;
+ }
+ | PHDRS '{' phdrs_defs '}'
+ | SEARCH_DIR '(' string ')'
+ { script_add_search_dir(closure, $3.value, $3.length); }
+ | SECTIONS '{'
+ { script_start_sections(closure); }
+ sections_block '}'
+ { script_finish_sections(closure); }
+ | TARGET_K '(' string ')'
+ { script_set_target(closure, $3.value, $3.length); }
+ | VERSIONK '{'
+ { script_push_lex_into_version_mode(closure); }
+ version_script '}'
+ { script_pop_lex_mode(closure); }
+ | file_or_sections_cmd
+ | ignore_cmd
+ | ';'
+ ;
+
+/* Top level commands which we ignore. The GNU linker uses these to
+ select the output format, but we don't offer a choice. Ignoring
+ these is more-or-less OK since most scripts simply explicitly
+ choose the default. */
+ignore_cmd:
+ OUTPUT_ARCH '(' string ')'
+ ;
+
+/* A list of external undefined symbols. We put the lexer into
+ expression mode so that commas separate names; this is what the GNU
+ linker does. */
+
+extern_name_list:
+ { script_push_lex_into_expression_mode(closure); }
+ extern_name_list_body
+ { script_pop_lex_mode(closure); }
+ ;
+
+extern_name_list_body:
+ string
+ { script_add_extern(closure, $1.value, $1.length); }
+ | extern_name_list_body string
+ { script_add_extern(closure, $2.value, $2.length); }
+ | extern_name_list_body ',' string
+ { script_add_extern(closure, $3.value, $3.length); }
+ ;
+
+/* A list of input file names. */
+input_list:
+ input_list_element
+ | input_list opt_comma input_list_element
+ ;
+
+/* An input file name. */
+input_list_element:
+ string
+ { script_add_file(closure, $1.value, $1.length); }
+ | '-' STRING
+ { script_add_library(closure, $2.value, $2.length); }
+ | AS_NEEDED
+ { script_start_as_needed(closure); }
+ '(' input_list ')'
+ { script_end_as_needed(closure); }
+ ;
+
+/* Commands in a SECTIONS block. */
+sections_block:
+ sections_block section_block_cmd
+ | /* empty */
+ ;
+
+/* A command which may appear within a SECTIONS block. */
+section_block_cmd:
+ file_or_sections_cmd
+ | string section_header
+ { script_start_output_section(closure, $1.value, $1.length, &$2); }
+ '{' section_cmds '}' section_trailer
+ { script_finish_output_section(closure, &$7); }
+ ;
+
+/* The header of an output section in a SECTIONS block--everything
+ after the name. */
+section_header:
+ { script_push_lex_into_expression_mode(closure); }
+ opt_address_and_section_type opt_at opt_align opt_subalign
+ { script_pop_lex_mode(closure); }
+ opt_constraint
+ {
+ $$.address = $2.address;
+ $$.section_type = $2.section_type;
+ $$.load_address = $3;
+ $$.align = $4;
+ $$.subalign = $5;
+ $$.constraint = $7;
+ }
+ ;
+
+/* The optional address followed by the optional section type. This
+ is a separate nonterminal to avoid a shift/reduce conflict on
+ '(' in section_header. */
+
+opt_address_and_section_type:
+ ':'
+ {
+ $$.address = NULL;
+ $$.section_type = SCRIPT_SECTION_TYPE_NONE;
+ }
+ | '(' ')' ':'
+ {
+ $$.address = NULL;
+ $$.section_type = SCRIPT_SECTION_TYPE_NONE;
+ }
+ | exp ':'
+ {
+ $$.address = $1;
+ $$.section_type = SCRIPT_SECTION_TYPE_NONE;
+ }
+ | exp '(' ')' ':'
+ {
+ $$.address = $1;
+ $$.section_type = SCRIPT_SECTION_TYPE_NONE;
+ }
+ | '(' section_type ')' ':'
+ {
+ $$.address = NULL;
+ $$.section_type = $2;
+ }
+ | exp '(' section_type ')' ':'
+ {
+ $$.address = $1;
+ $$.section_type = $3;
+ }
+ ;
+
+/* We only support NOLOAD. */
+section_type:
+ NOLOAD
+ { $$ = SCRIPT_SECTION_TYPE_NOLOAD; }
+ | DSECT
+ {
+ yyerror(closure, "DSECT section type is unsupported");
+ $$ = SCRIPT_SECTION_TYPE_DSECT;
+ }
+ | COPY
+ {
+ yyerror(closure, "COPY section type is unsupported");
+ $$ = SCRIPT_SECTION_TYPE_COPY;
+ }
+ | INFO
+ {
+ yyerror(closure, "INFO section type is unsupported");
+ $$ = SCRIPT_SECTION_TYPE_INFO;
+ }
+ | OVERLAY
+ {
+ yyerror(closure, "OVERLAY section type is unsupported");
+ $$ = SCRIPT_SECTION_TYPE_OVERLAY;
+ }
+ ;
+
+/* The address at which an output section should be loaded. */
+opt_at:
+ /* empty */
+ { $$ = NULL; }
+ | AT '(' exp ')'
+ { $$ = $3; }
+ ;
+
+/* The alignment of an output section. */
+opt_align:
+ /* empty */
+ { $$ = NULL; }
+ | ALIGN_K '(' exp ')'
+ { $$ = $3; }
+ ;
+
+/* The input section alignment within an output section. */
+opt_subalign:
+ /* empty */
+ { $$ = NULL; }
+ | SUBALIGN '(' exp ')'
+ { $$ = $3; }
+ ;
+
+/* A section constraint. */
+opt_constraint:
+ /* empty */
+ { $$ = CONSTRAINT_NONE; }
+ | ONLY_IF_RO
+ { $$ = CONSTRAINT_ONLY_IF_RO; }
+ | ONLY_IF_RW
+ { $$ = CONSTRAINT_ONLY_IF_RW; }
+ | SPECIAL
+ { $$ = CONSTRAINT_SPECIAL; }
+ ;
+
+/* The trailer of an output section in a SECTIONS block. */
+section_trailer:
+ opt_memspec opt_at_memspec opt_phdr opt_fill opt_comma
+ {
+ $$.fill = $4;
+ $$.phdrs = $3;
+ }
+ ;
+
+/* A memory specification for an output section. */
+opt_memspec:
+ '>' string
+ { script_set_section_region(closure, $2.value, $2.length, 1); }
+ | /* empty */
+ ;
+
+/* A memory specification for where to load an output section. */
+opt_at_memspec:
+ AT '>' string
+ { script_set_section_region(closure, $3.value, $3.length, 0); }
+ | /* empty */
+ ;
+
+/* The program segment an output section should go into. */
+opt_phdr:
+ opt_phdr ':' string
+ { $$ = script_string_list_push_back($1, $3.value, $3.length); }
+ | /* empty */
+ { $$ = NULL; }
+ ;
+
+/* The value to use to fill an output section. FIXME: This does not
+ handle a string of arbitrary length. */
+opt_fill:
+ '=' parse_exp
+ { $$ = $2; }
+ | /* empty */
+ { $$ = NULL; }
+ ;
+
+/* Commands which may appear within the description of an output
+ section in a SECTIONS block. */
+section_cmds:
+ /* empty */
+ | section_cmds section_cmd
+ ;
+
+/* A command which may appear within the description of an output
+ section in a SECTIONS block. */
+section_cmd:
+ assignment end
+ | input_section_spec
+ | data_length '(' parse_exp ')'
+ { script_add_data(closure, $1, $3); }
+ | ASSERT_K '(' parse_exp ',' string ')'
+ { script_add_assertion(closure, $3, $5.value, $5.length); }
+ | FILL '(' parse_exp ')'
+ { script_add_fill(closure, $3); }
+ | CONSTRUCTORS
+ {
+ /* The GNU linker uses CONSTRUCTORS for the a.out object
+ file format. It does nothing when using ELF. Since
+ some ELF linker scripts use it although it does
+ nothing, we accept it and ignore it. */
+ }
+ | SORT_BY_NAME '(' CONSTRUCTORS ')'
+ | INCLUDE string
+ { script_include_directive(closure, $2.value, $2.length); }
+ | ';'
+ ;
+
+/* The length of data which may appear within the description of an
+ output section in a SECTIONS block. */
+data_length:
+ QUAD
+ { $$ = QUAD; }
+ | SQUAD
+ { $$ = SQUAD; }
+ | LONG
+ { $$ = LONG; }
+ | SHORT
+ { $$ = SHORT; }
+ | BYTE
+ { $$ = BYTE; }
+ ;
+
+/* An input section specification. This may appear within the
+ description of an output section in a SECTIONS block. */
+input_section_spec:
+ input_section_no_keep
+ { script_add_input_section(closure, &$1, 0); }
+ | KEEP '(' input_section_no_keep ')'
+ { script_add_input_section(closure, &$3, 1); }
+ ;
+
+/* An input section specification within a KEEP clause. */
+input_section_no_keep:
+ string
+ {
+ $$.file.name = $1;
+ $$.file.sort = SORT_WILDCARD_NONE;
+ $$.input_sections.sections = NULL;
+ $$.input_sections.exclude = NULL;
+ }
+ | wildcard_file '(' wildcard_sections ')'
+ {
+ $$.file = $1;
+ $$.input_sections = $3;
+ }
+ ;
+
+/* A wildcard file specification. */
+wildcard_file:
+ wildcard_name
+ {
+ $$.name = $1;
+ $$.sort = SORT_WILDCARD_NONE;
+ }
+ | SORT_BY_NAME '(' wildcard_name ')'
+ {
+ $$.name = $3;
+ $$.sort = SORT_WILDCARD_BY_NAME;
+ }
+ ;
+
+/* A list of wild card section specifications. */
+wildcard_sections:
+ wildcard_sections opt_comma wildcard_section
+ {
+ $$.sections = script_string_sort_list_add($1.sections, &$3);
+ $$.exclude = $1.exclude;
+ }
+ | wildcard_section
+ {
+ $$.sections = script_new_string_sort_list(&$1);
+ $$.exclude = NULL;
+ }
+ | wildcard_sections opt_comma EXCLUDE_FILE '(' exclude_names ')'
+ {
+ $$.sections = $1.sections;
+ $$.exclude = script_string_list_append($1.exclude, $5);
+ }
+ | EXCLUDE_FILE '(' exclude_names ')'
+ {
+ $$.sections = NULL;
+ $$.exclude = $3;
+ }
+ ;
+
+/* A single wild card specification. */
+wildcard_section:
+ wildcard_name
+ {
+ $$.name = $1;
+ $$.sort = SORT_WILDCARD_NONE;
+ }
+ | SORT_BY_NAME '(' wildcard_section ')'
+ {
+ $$.name = $3.name;
+ switch ($3.sort)
+ {
+ case SORT_WILDCARD_NONE:
+ $$.sort = SORT_WILDCARD_BY_NAME;
+ break;
+ case SORT_WILDCARD_BY_NAME:
+ case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT:
+ break;
+ case SORT_WILDCARD_BY_ALIGNMENT:
+ case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME:
+ $$.sort = SORT_WILDCARD_BY_NAME_BY_ALIGNMENT;
+ break;
+ default:
+ abort();
+ }
+ }
+ | SORT_BY_ALIGNMENT '(' wildcard_section ')'
+ {
+ $$.name = $3.name;
+ switch ($3.sort)
+ {
+ case SORT_WILDCARD_NONE:
+ $$.sort = SORT_WILDCARD_BY_ALIGNMENT;
+ break;
+ case SORT_WILDCARD_BY_ALIGNMENT:
+ case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME:
+ break;
+ case SORT_WILDCARD_BY_NAME:
+ case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT:
+ $$.sort = SORT_WILDCARD_BY_ALIGNMENT_BY_NAME;
+ break;
+ default:
+ abort();
+ }
+ }
+ ;
+
+/* A list of file names to exclude. */
+exclude_names:
+ exclude_names opt_comma wildcard_name
+ { $$ = script_string_list_push_back($1, $3.value, $3.length); }
+ | wildcard_name
+ { $$ = script_new_string_list($1.value, $1.length); }
+ ;
+
+/* A single wildcard name. We recognize '*' and '?' specially since
+ they are expression tokens. */
+wildcard_name:
+ string
+ { $$ = $1; }
+ | '*'
+ {
+ $$.value = "*";
+ $$.length = 1;
+ }
+ | '?'
+ {
+ $$.value = "?";
+ $$.length = 1;
+ }
+ ;
+
+/* A command which may appear at the top level of a linker script, or
+ within a SECTIONS block. */
+file_or_sections_cmd:
+ ENTRY '(' string ')'
+ { script_set_entry(closure, $3.value, $3.length); }
+ | assignment end
+ | ASSERT_K '(' parse_exp ',' string ')'
+ { script_add_assertion(closure, $3, $5.value, $5.length); }
+ | INCLUDE string
+ { script_include_directive(closure, $2.value, $2.length); }
+ ;
+
+/* A list of MEMORY definitions. */
+memory_defs:
+ memory_defs opt_comma memory_def
+ | /* empty */
+ ;
+
+/* A single MEMORY definition. */
+memory_def:
+ string memory_attr ':' memory_origin '=' parse_exp opt_comma memory_length '=' parse_exp
+ { script_add_memory(closure, $1.value, $1.length, $2, $6, $10); }
+ |
+ /* LD supports an INCLUDE directive here, currently GOLD does not. */
+ INCLUDE string
+ { script_include_directive(closure, $2.value, $2.length); }
+ |
+ ;
+
+/* The (optional) attributes of a MEMORY region. */
+memory_attr:
+ '(' string ')'
+ { $$ = script_parse_memory_attr(closure, $2.value, $2.length, 0); }
+ | /* Inverted attributes. */
+ '(' '!' string ')'
+ { $$ = script_parse_memory_attr(closure, $3.value, $3.length, 1); }
+ | /* empty */
+ { $$ = 0; }
+ ;
+
+memory_origin:
+ ORIGIN
+ |
+ ORG
+ |
+ 'o'
+ ;
+
+memory_length:
+ LENGTH
+ |
+ LEN
+ |
+ 'l'
+ ;
+
+/* A list of program header definitions. */
+phdrs_defs:
+ phdrs_defs phdr_def
+ | /* empty */
+ ;
+
+/* A program header definition. */
+phdr_def:
+ string phdr_type phdr_info ';'
+ { script_add_phdr(closure, $1.value, $1.length, $2, &$3); }
+ ;
+
+/* A program header type. The GNU linker accepts a general expression
+ here, but that would be a pain because we would have to dig into
+ the expression structure. It's unlikely that anybody uses anything
+ other than a string or a number here, so that is all we expect. */
+phdr_type:
+ string
+ { $$ = script_phdr_string_to_type(closure, $1.value, $1.length); }
+ | INTEGER
+ { $$ = $1; }
+ ;
+
+/* Additional information for a program header. */
+phdr_info:
+ /* empty */
+ { memset(&$$, 0, sizeof(struct Phdr_info)); }
+ | string phdr_info
+ {
+ $$ = $2;
+ if ($1.length == 7 && strncmp($1.value, "FILEHDR", 7) == 0)
+ $$.includes_filehdr = 1;
+ else
+ yyerror(closure, "PHDRS syntax error");
+ }
+ | PHDRS phdr_info
+ {
+ $$ = $2;
+ $$.includes_phdrs = 1;
+ }
+ | string '(' INTEGER ')' phdr_info
+ {
+ $$ = $5;
+ if ($1.length == 5 && strncmp($1.value, "FLAGS", 5) == 0)
+ {
+ $$.is_flags_valid = 1;
+ $$.flags = $3;
+ }
+ else
+ yyerror(closure, "PHDRS syntax error");
+ }
+ | AT '(' parse_exp ')' phdr_info
+ {
+ $$ = $5;
+ $$.load_address = $3;
+ }
+ ;
+
+/* Set a symbol to a value. */
+assignment:
+ string '=' parse_exp
+ { script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
+ | string PLUSEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_add(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | string MINUSEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_sub(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | string MULTEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_mult(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | string DIVEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_div(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | string LSHIFTEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_lshift(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | string RSHIFTEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_rshift(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | string ANDEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_bitwise_and(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | string OREQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_bitwise_or(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | PROVIDE '(' string '=' parse_exp ')'
+ { script_set_symbol(closure, $3.value, $3.length, $5, 1, 0); }
+ | PROVIDE_HIDDEN '(' string '=' parse_exp ')'
+ { script_set_symbol(closure, $3.value, $3.length, $5, 1, 1); }
+ ;
+
+/* Parse an expression, putting the lexer into the right mode. */
+parse_exp:
+ { script_push_lex_into_expression_mode(closure); }
+ exp
+ {
+ script_pop_lex_mode(closure);
+ $$ = $2;
+ }
+ ;
+
+/* An expression. */
+exp:
+ '(' exp ')'
+ { $$ = $2; }
+ | '-' exp %prec UNARY
+ { $$ = script_exp_unary_minus($2); }
+ | '!' exp %prec UNARY
+ { $$ = script_exp_unary_logical_not($2); }
+ | '~' exp %prec UNARY
+ { $$ = script_exp_unary_bitwise_not($2); }
+ | '+' exp %prec UNARY
+ { $$ = $2; }
+ | exp '*' exp
+ { $$ = script_exp_binary_mult($1, $3); }
+ | exp '/' exp
+ { $$ = script_exp_binary_div($1, $3); }
+ | exp '%' exp
+ { $$ = script_exp_binary_mod($1, $3); }
+ | exp '+' exp
+ { $$ = script_exp_binary_add($1, $3); }
+ | exp '-' exp
+ { $$ = script_exp_binary_sub($1, $3); }
+ | exp LSHIFT exp
+ { $$ = script_exp_binary_lshift($1, $3); }
+ | exp RSHIFT exp
+ { $$ = script_exp_binary_rshift($1, $3); }
+ | exp EQ exp
+ { $$ = script_exp_binary_eq($1, $3); }
+ | exp NE exp
+ { $$ = script_exp_binary_ne($1, $3); }
+ | exp LE exp
+ { $$ = script_exp_binary_le($1, $3); }
+ | exp GE exp
+ { $$ = script_exp_binary_ge($1, $3); }
+ | exp '<' exp
+ { $$ = script_exp_binary_lt($1, $3); }
+ | exp '>' exp
+ { $$ = script_exp_binary_gt($1, $3); }
+ | exp '&' exp
+ { $$ = script_exp_binary_bitwise_and($1, $3); }
+ | exp '^' exp
+ { $$ = script_exp_binary_bitwise_xor($1, $3); }
+ | exp '|' exp
+ { $$ = script_exp_binary_bitwise_or($1, $3); }
+ | exp ANDAND exp
+ { $$ = script_exp_binary_logical_and($1, $3); }
+ | exp OROR exp
+ { $$ = script_exp_binary_logical_or($1, $3); }
+ | exp '?' exp ':' exp
+ { $$ = script_exp_trinary_cond($1, $3, $5); }
+ | INTEGER
+ { $$ = script_exp_integer($1); }
+ | string
+ { $$ = script_symbol(closure, $1.value, $1.length); }
+ | MAX_K '(' exp ',' exp ')'
+ { $$ = script_exp_function_max($3, $5); }
+ | MIN_K '(' exp ',' exp ')'
+ { $$ = script_exp_function_min($3, $5); }
+ | DEFINED '(' string ')'
+ { $$ = script_exp_function_defined($3.value, $3.length); }
+ | SIZEOF_HEADERS
+ { $$ = script_exp_function_sizeof_headers(); }
+ | ALIGNOF '(' string ')'
+ { $$ = script_exp_function_alignof($3.value, $3.length); }
+ | SIZEOF '(' string ')'
+ { $$ = script_exp_function_sizeof($3.value, $3.length); }
+ | ADDR '(' string ')'
+ { $$ = script_exp_function_addr($3.value, $3.length); }
+ | LOADADDR '(' string ')'
+ { $$ = script_exp_function_loadaddr($3.value, $3.length); }
+ | ORIGIN '(' string ')'
+ { $$ = script_exp_function_origin(closure, $3.value, $3.length); }
+ | LENGTH '(' string ')'
+ { $$ = script_exp_function_length(closure, $3.value, $3.length); }
+ | CONSTANT '(' string ')'
+ { $$ = script_exp_function_constant($3.value, $3.length); }
+ | ABSOLUTE '(' exp ')'
+ { $$ = script_exp_function_absolute($3); }
+ | ALIGN_K '(' exp ')'
+ { $$ = script_exp_function_align(script_exp_string(".", 1), $3); }
+ | ALIGN_K '(' exp ',' exp ')'
+ { $$ = script_exp_function_align($3, $5); }
+ | BLOCK '(' exp ')'
+ { $$ = script_exp_function_align(script_exp_string(".", 1), $3); }
+ | DATA_SEGMENT_ALIGN '(' exp ',' exp ')'
+ {
+ script_data_segment_align(closure);
+ $$ = script_exp_function_data_segment_align($3, $5);
+ }
+ | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')'
+ {
+ script_data_segment_relro_end(closure);
+ $$ = script_exp_function_data_segment_relro_end($3, $5);
+ }
+ | DATA_SEGMENT_END '(' exp ')'
+ { $$ = script_exp_function_data_segment_end($3); }
+ | SEGMENT_START '(' string ',' exp ')'
+ {
+ $$ = script_exp_function_segment_start($3.value, $3.length, $5);
+ /* We need to take note of any SEGMENT_START expressions
+ because they change the behaviour of -Ttext, -Tdata and
+ -Tbss options. */
+ script_saw_segment_start_expression(closure);
+ }
+ | ASSERT_K '(' exp ',' string ')'
+ { $$ = script_exp_function_assert($3, $5.value, $5.length); }
+ ;
+
+/* Handle the --defsym option. */
+defsym_expr:
+ string '=' parse_exp
+ { script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
+ ;
+
+/* Handle the --dynamic-list option. A dynamic list has the format
+ { sym1; sym2; extern "C++" { namespace::sym3 }; };
+ We store the symbol we see in the "local" list; that is where
+ Command_line::in_dynamic_list() will look to do its check.
+ TODO(csilvers): More than one of these brace-lists can appear, and
+ should just be merged and treated as a single list. */
+dynamic_list_expr: dynamic_list_nodes ;
+
+dynamic_list_nodes:
+ dynamic_list_node
+ | dynamic_list_nodes dynamic_list_node
+ ;
+
+dynamic_list_node:
+ '{' vers_defns ';' '}' ';'
+ { script_new_vers_node (closure, NULL, $2); }
+ ;
+
+/* A version script. */
+version_script:
+ vers_nodes
+ ;
+
+vers_nodes:
+ vers_node
+ | vers_nodes vers_node
+ ;
+
+vers_node:
+ '{' vers_tag '}' ';'
+ {
+ script_register_vers_node (closure, NULL, 0, $2, NULL);
+ }
+ | string '{' vers_tag '}' ';'
+ {
+ script_register_vers_node (closure, $1.value, $1.length, $3,
+ NULL);
+ }
+ | string '{' vers_tag '}' verdep ';'
+ {
+ script_register_vers_node (closure, $1.value, $1.length, $3, $5);
+ }
+ ;
+
+verdep:
+ string
+ {
+ $$ = script_add_vers_depend (closure, NULL, $1.value, $1.length);
+ }
+ | verdep string
+ {
+ $$ = script_add_vers_depend (closure, $1, $2.value, $2.length);
+ }
+ ;
+
+vers_tag:
+ /* empty */
+ { $$ = script_new_vers_node (closure, NULL, NULL); }
+ | vers_defns ';'
+ { $$ = script_new_vers_node (closure, $1, NULL); }
+ | GLOBAL ':' vers_defns ';'
+ { $$ = script_new_vers_node (closure, $3, NULL); }
+ | LOCAL ':' vers_defns ';'
+ { $$ = script_new_vers_node (closure, NULL, $3); }
+ | GLOBAL ':' vers_defns ';' LOCAL ':' vers_defns ';'
+ { $$ = script_new_vers_node (closure, $3, $7); }
+ ;
+
+/* Here is one of the rare places we care about the distinction
+ between STRING and QUOTED_STRING. For QUOTED_STRING, we do exact
+ matching on the pattern, so we pass in true for the exact_match
+ parameter. For STRING, we do glob matching and pass in false. */
+vers_defns:
+ STRING
+ {
+ $$ = script_new_vers_pattern (closure, NULL, $1.value,
+ $1.length, 0);
+ }
+ | QUOTED_STRING
+ {
+ $$ = script_new_vers_pattern (closure, NULL, $1.value,
+ $1.length, 1);
+ }
+ | vers_defns ';' STRING
+ {
+ $$ = script_new_vers_pattern (closure, $1, $3.value,
+ $3.length, 0);
+ }
+ | vers_defns ';' QUOTED_STRING
+ {
+ $$ = script_new_vers_pattern (closure, $1, $3.value,
+ $3.length, 1);
+ }
+ | /* Push string on the language stack. */
+ EXTERN string '{'
+ { version_script_push_lang (closure, $2.value, $2.length); }
+ vers_defns opt_semicolon '}'
+ {
+ $$ = $5;
+ version_script_pop_lang(closure);
+ }
+ | /* Push string on the language stack. This is more complicated
+ than the other cases because we need to merge the linked-list
+ state from the pre-EXTERN defns and the post-EXTERN defns. */
+ vers_defns ';' EXTERN string '{'
+ { version_script_push_lang (closure, $4.value, $4.length); }
+ vers_defns opt_semicolon '}'
+ {
+ $$ = script_merge_expressions ($1, $7);
+ version_script_pop_lang(closure);
+ }
+ | EXTERN // "extern" as a symbol name
+ {
+ $$ = script_new_vers_pattern (closure, NULL, "extern",
+ sizeof("extern") - 1, 1);
+ }
+ | vers_defns ';' EXTERN
+ {
+ $$ = script_new_vers_pattern (closure, $1, "extern",
+ sizeof("extern") - 1, 1);
+ }
+ ;
+
+/* A string can be either a STRING or a QUOTED_STRING. Almost all the
+ time we don't care, and we use this rule. */
+string:
+ STRING
+ { $$ = $1; }
+ | QUOTED_STRING
+ { $$ = $1; }
+ ;
+
+/* Some statements require a terminator, which may be a semicolon or a
+ comma. */
+end:
+ ';'
+ | ','
+ ;
+
+/* An optional semicolon. */
+opt_semicolon:
+ ';'
+ | /* empty */
+ ;
+
+/* An optional comma. */
+opt_comma:
+ ','
+ | /* empty */
+ ;
+
+%%