From 25e4902b49aefc82a7e5360482d56badf30ff603 Mon Sep 17 00:00:00 2001 From: Antonio Huete Jimenez Date: Tue, 22 Dec 2015 08:34:47 -0800 Subject: [PATCH] Import gdb-7.10.1 --- contrib/gdb-7/README | 47 - contrib/gdb-7/bfd/README | 55 - contrib/gdb-7/bfd/archive.c | 129 +- contrib/gdb-7/bfd/archive64.c | 13 +- contrib/gdb-7/bfd/archures.c | 65 +- contrib/gdb-7/bfd/bfd-in.h | 121 +- contrib/gdb-7/bfd/bfd-in2.h | 1104 +- contrib/gdb-7/bfd/bfd.c | 353 +- contrib/gdb-7/bfd/bfdio.c | 6 +- contrib/gdb-7/bfd/bfdwin.c | 3 +- contrib/gdb-7/bfd/binary.c | 7 +- contrib/gdb-7/bfd/cache.c | 45 +- contrib/gdb-7/bfd/coff-bfd.c | 99 + contrib/gdb-7/bfd/coff-bfd.h | 86 + contrib/gdb-7/bfd/coffgen.c | 820 +- contrib/gdb-7/bfd/compress.c | 441 +- contrib/gdb-7/bfd/config.bfd | 1264 +- contrib/gdb-7/bfd/corefile.c | 3 +- contrib/gdb-7/bfd/cpu-ft32.c | 41 + contrib/gdb-7/bfd/cpu-i386.c | 71 +- contrib/gdb-7/bfd/{cpu-l1om.c => cpu-iamcu.c} | 35 +- contrib/gdb-7/bfd/cpu-l1om.c | 3 +- contrib/gdb-7/bfd/cpu-nds32.c | 45 + contrib/gdb-7/bfd/cpu-or1k.c | 59 + contrib/gdb-7/bfd/{init.c => cpu-visium.c} | 54 +- .../__init__.py => bfd/development.sh} | 9 +- contrib/gdb-7/bfd/dwarf1.c | 5 +- contrib/gdb-7/bfd/dwarf2.c | 1434 +- contrib/gdb-7/bfd/elf-attrs.c | 72 +- contrib/gdb-7/bfd/elf-bfd.h | 259 +- contrib/gdb-7/bfd/elf-eh-frame.c | 751 +- contrib/gdb-7/bfd/elf-ifunc.c | 201 +- contrib/gdb-7/bfd/elf-linux-psinfo.h | 2 +- contrib/gdb-7/bfd/elf-nacl.c | 305 +- contrib/gdb-7/bfd/elf-nacl.h | 3 +- contrib/gdb-7/bfd/elf-strtab.c | 3 +- contrib/gdb-7/bfd/elf-vxworks.c | 2 +- contrib/gdb-7/bfd/elf-vxworks.h | 2 +- contrib/gdb-7/bfd/elf.c | 1577 +- contrib/gdb-7/bfd/elf32-ft32.c | 380 + contrib/gdb-7/bfd/elf32-gen.c | 7 +- contrib/gdb-7/bfd/elf32-i386.c | 622 +- contrib/gdb-7/bfd/elf32-nds32.c | 15755 ++ contrib/gdb-7/bfd/elf32-nds32.h | 155 + .../mach-o/reloc.h => bfd/elf32-nios2.h} | 31 +- contrib/gdb-7/bfd/elf32-or1k.c | 2857 + contrib/gdb-7/bfd/{elf32.c => elf32-rx.h} | 11 +- contrib/gdb-7/bfd/elf32-visium.c | 903 + contrib/gdb-7/bfd/elf32.c | 3 +- contrib/gdb-7/bfd/elf64-gen.c | 7 +- contrib/gdb-7/bfd/elf64-x86-64.c | 1476 +- contrib/gdb-7/bfd/elf64.c | 2 +- contrib/gdb-7/bfd/elfcode.h | 169 +- contrib/gdb-7/bfd/elfcore.h | 3 +- contrib/gdb-7/bfd/elflink.c | 2087 +- contrib/gdb-7/bfd/elfnn-aarch64.c | 8632 + contrib/gdb-7/bfd/elfxx-aarch64.c | 606 + contrib/gdb-7/bfd/elfxx-aarch64.h | 67 + contrib/gdb-7/bfd/elfxx-target.h | 60 +- contrib/gdb-7/bfd/format.c | 25 +- contrib/gdb-7/bfd/genlink.h | 2 +- contrib/gdb-7/bfd/hash.c | 11 +- contrib/gdb-7/bfd/ihex.c | 8 +- contrib/gdb-7/bfd/init.c | 3 +- contrib/gdb-7/bfd/libaout.h | 8 +- contrib/gdb-7/bfd/libbfd.c | 200 +- contrib/gdb-7/bfd/libbfd.h | 388 +- contrib/gdb-7/bfd/libcoff.h | 108 +- contrib/gdb-7/bfd/libecoff.h | 12 +- contrib/gdb-7/bfd/linker.c | 612 +- contrib/gdb-7/bfd/merge.c | 56 +- contrib/gdb-7/bfd/opncls.c | 341 +- contrib/gdb-7/bfd/reloc.c | 992 +- contrib/gdb-7/bfd/section.c | 44 +- contrib/gdb-7/bfd/simple.c | 86 +- contrib/gdb-7/bfd/srec.c | 33 +- contrib/gdb-7/bfd/stab-syms.c | 3 +- contrib/gdb-7/bfd/stabs.c | 5 +- contrib/gdb-7/bfd/syms.c | 104 +- contrib/gdb-7/bfd/sysdep.h | 11 +- contrib/gdb-7/bfd/targets.c | 1433 +- contrib/gdb-7/bfd/tekhex.c | 161 +- contrib/gdb-7/bfd/verilog.c | 6 +- contrib/gdb-7/bfd/version.h | 2 +- contrib/gdb-7/bfd/version.m4 | 1 + contrib/gdb-7/gdb/README | 665 - contrib/gdb-7/gdb/ada-exp.c | 3063 +- contrib/gdb-7/gdb/ada-exp.y | 561 +- contrib/gdb-7/gdb/ada-lang.c | 2079 +- contrib/gdb-7/gdb/ada-lang.h | 50 +- contrib/gdb-7/gdb/ada-lex.c | 296 +- contrib/gdb-7/gdb/ada-operator.def | 2 +- contrib/gdb-7/gdb/ada-tasks.c | 54 +- contrib/gdb-7/gdb/ada-typeprint.c | 129 +- contrib/gdb-7/gdb/ada-valprint.c | 1069 +- contrib/gdb-7/gdb/ada-varobj.c | 186 +- contrib/gdb-7/gdb/ada-varobj.h | 55 - contrib/gdb-7/gdb/addrmap.c | 63 +- contrib/gdb-7/gdb/addrmap.h | 2 +- contrib/gdb-7/gdb/agent.c | 2 +- contrib/gdb-7/gdb/amd64-nat.c | 5 +- contrib/gdb-7/gdb/amd64-nat.h | 2 +- contrib/gdb-7/gdb/amd64-tdep.c | 567 +- contrib/gdb-7/gdb/amd64-tdep.h | 27 +- contrib/gdb-7/gdb/amd64bsd-nat.c | 61 +- contrib/gdb-7/gdb/amd64bsd-nat.h | 5 +- contrib/gdb-7/gdb/annotate.c | 25 +- contrib/gdb-7/gdb/annotate.h | 2 +- contrib/gdb-7/gdb/arch-utils.c | 109 +- contrib/gdb-7/gdb/arch-utils.h | 51 +- contrib/gdb-7/gdb/auto-load.c | 712 +- contrib/gdb-7/gdb/auto-load.h | 29 +- contrib/gdb-7/gdb/auxv.c | 117 +- contrib/gdb-7/gdb/auxv.h | 17 +- contrib/gdb-7/gdb/ax-gdb.c | 123 +- contrib/gdb-7/gdb/ax-gdb.h | 14 +- contrib/gdb-7/gdb/ax-general.c | 7 +- contrib/gdb-7/gdb/ax.h | 19 +- contrib/gdb-7/gdb/bcache.c | 27 +- contrib/gdb-7/gdb/bcache.h | 2 +- contrib/gdb-7/gdb/bfd-target.c | 18 +- contrib/gdb-7/gdb/bfd-target.h | 2 +- contrib/gdb-7/gdb/block.c | 303 +- contrib/gdb-7/gdb/block.h | 109 +- contrib/gdb-7/gdb/blockframe.c | 86 +- contrib/gdb-7/gdb/break-catch-sig.c | 18 +- contrib/gdb-7/gdb/break-catch-syscall.c | 659 + contrib/gdb-7/gdb/break-catch-throw.c | 601 + contrib/gdb-7/gdb/breakpoint.c | 3337 +- contrib/gdb-7/gdb/breakpoint.h | 238 +- contrib/gdb-7/gdb/bsd-kvm.c | 38 +- contrib/gdb-7/gdb/bsd-kvm.h | 2 +- contrib/gdb-7/gdb/bsd-uthread.c | 41 +- contrib/gdb-7/gdb/bsd-uthread.h | 2 +- contrib/gdb-7/gdb/btrace.c | 3049 +- contrib/gdb-7/gdb/btrace.h | 424 +- contrib/gdb-7/gdb/build-id.c | 169 + contrib/gdb-7/gdb/build-id.h | 48 + contrib/gdb-7/gdb/build-with-cxx.m4 | 41 + contrib/gdb-7/gdb/buildsym.c | 860 +- contrib/gdb-7/gdb/buildsym.h | 106 +- contrib/gdb-7/gdb/c-exp.y | 1186 +- contrib/gdb-7/gdb/c-lang.c | 59 +- contrib/gdb-7/gdb/c-lang.h | 26 +- contrib/gdb-7/gdb/c-typeprint.c | 62 +- contrib/gdb-7/gdb/c-valprint.c | 56 +- contrib/gdb-7/gdb/c-varobj.c | 973 + contrib/gdb-7/gdb/charset-list.h | 2 +- contrib/gdb-7/gdb/charset.c | 43 +- contrib/gdb-7/gdb/charset.h | 2 +- contrib/gdb-7/gdb/cli-out.c | 108 +- contrib/gdb-7/gdb/cli-out.h | 6 +- contrib/gdb-7/gdb/cli/cli-cmds.c | 225 +- contrib/gdb-7/gdb/cli/cli-cmds.h | 8 +- contrib/gdb-7/gdb/cli/cli-decode.c | 324 +- contrib/gdb-7/gdb/cli/cli-decode.h | 137 +- contrib/gdb-7/gdb/cli/cli-dump.c | 123 +- contrib/gdb-7/gdb/cli/cli-interp.c | 112 +- contrib/gdb-7/gdb/cli/cli-logging.c | 16 +- contrib/gdb-7/gdb/cli/cli-script.c | 219 +- contrib/gdb-7/gdb/cli/cli-script.h | 8 +- contrib/gdb-7/gdb/cli/cli-setshow.c | 109 +- contrib/gdb-7/gdb/cli/cli-setshow.h | 14 +- contrib/gdb-7/gdb/cli/cli-utils.c | 100 +- contrib/gdb-7/gdb/cli/cli-utils.h | 39 +- contrib/gdb-7/gdb/coff-pe-read.c | 87 +- contrib/gdb-7/gdb/coff-pe-read.h | 2 +- contrib/gdb-7/gdb/coffread.c | 278 +- contrib/gdb-7/gdb/command.h | 126 +- contrib/gdb-7/gdb/common/agent.c | 143 +- contrib/gdb-7/gdb/common/agent.h | 5 +- contrib/gdb-7/gdb/common/ax.def | 4 +- .../{gdb_vfork.h => common/break-common.h} | 20 +- contrib/gdb-7/gdb/common/btrace-common.c | 180 + contrib/gdb-7/gdb/common/btrace-common.h | 184 +- contrib/gdb-7/gdb/common/buffer.c | 15 +- contrib/gdb-7/gdb/common/buffer.h | 6 +- contrib/gdb-7/gdb/{ => common}/cleanups.c | 26 +- contrib/gdb-7/gdb/{ => common}/cleanups.h | 2 +- .../common-debug.c} | 24 +- contrib/gdb-7/gdb/common/common-debug.h | 41 + contrib/gdb-7/gdb/common/common-defs.h | 63 + contrib/gdb-7/gdb/common/common-exceptions.c | 388 + contrib/gdb-7/gdb/common/common-exceptions.h | 271 + .../common/{gdb_vecs.h => common-regcache.h} | 32 +- contrib/gdb-7/gdb/common/common-types.h | 61 + contrib/gdb-7/gdb/common/common-utils.c | 151 +- contrib/gdb-7/gdb/common/common-utils.h | 62 +- .../__init__.py => common/common.host} | 24 +- contrib/gdb-7/gdb/common/common.m4 | 47 + contrib/gdb-7/gdb/common/create-version.sh | 38 + contrib/gdb-7/gdb/common/errors.c | 69 + contrib/gdb-7/gdb/common/errors.h | 90 + contrib/gdb-7/gdb/common/fileio.c | 255 + contrib/gdb-7/gdb/common/fileio.h | 73 + contrib/gdb-7/gdb/common/filestuff.c | 427 + contrib/gdb-7/gdb/common/filestuff.h | 74 + contrib/gdb-7/gdb/common/format.c | 21 +- contrib/gdb-7/gdb/common/format.h | 2 +- contrib/gdb-7/gdb/common/gdb_assert.h | 23 +- contrib/gdb-7/gdb/common/gdb_dirent.h | 40 - contrib/gdb-7/gdb/common/gdb_locale.h | 2 +- .../gdb/{gdb_regex.h => common/gdb_setjmp.h} | 28 +- contrib/gdb-7/gdb/common/gdb_signals.h | 6 +- contrib/gdb-7/gdb/common/gdb_stat.h | 59 - contrib/gdb-7/gdb/common/gdb_string.h | 69 - contrib/gdb-7/gdb/common/gdb_vecs.c | 68 +- contrib/gdb-7/gdb/common/gdb_vecs.h | 7 +- contrib/gdb-7/gdb/common/gdb_wait.h | 2 +- contrib/gdb-7/gdb/common/host-defs.h | 23 +- contrib/gdb-7/gdb/common/i386-xstate.h | 42 - contrib/gdb-7/gdb/common/linux-btrace.c | 610 - contrib/gdb-7/gdb/common/linux-btrace.h | 77 - contrib/gdb-7/gdb/common/linux-procfs.c | 120 - contrib/gdb-7/gdb/common/linux-procfs.h | 43 - contrib/gdb-7/gdb/common/linux-ptrace.c | 238 - contrib/gdb-7/gdb/common/linux-ptrace.h | 73 - contrib/gdb-7/gdb/common/mingw-strerror.c | 64 + .../mi-cmd-info.c => common/posix-strerror.c} | 34 +- contrib/gdb-7/gdb/common/print-utils.c | 325 + contrib/gdb-7/gdb/common/print-utils.h | 70 + contrib/gdb-7/gdb/common/ptid.c | 63 +- contrib/gdb-7/gdb/common/ptid.h | 83 +- contrib/gdb-7/gdb/common/queue.h | 5 +- contrib/gdb-7/gdb/common/rsp-low.c | 246 + contrib/gdb-7/gdb/common/rsp-low.h | 83 + contrib/gdb-7/gdb/common/signals.c | 134 +- contrib/gdb-7/gdb/common/symbol.h | 37 + contrib/gdb-7/gdb/common/vec.c | 9 +- contrib/gdb-7/gdb/common/vec.h | 9 +- contrib/gdb-7/gdb/{ => common}/version.h | 2 +- contrib/gdb-7/gdb/common/x86-xstate.h | 67 + contrib/gdb-7/gdb/common/xml-utils.c | 11 +- contrib/gdb-7/gdb/common/xml-utils.h | 2 +- contrib/gdb-7/gdb/compile/compile-c-support.c | 441 + contrib/gdb-7/gdb/compile/compile-c-symbols.c | 772 + contrib/gdb-7/gdb/compile/compile-c-types.c | 437 + contrib/gdb-7/gdb/compile/compile-internal.h | 151 + contrib/gdb-7/gdb/compile/compile-loc2c.c | 1161 + .../gdb-7/gdb/compile/compile-object-load.c | 847 + .../gdb-7/gdb/compile/compile-object-load.h | 60 + .../gdb-7/gdb/compile/compile-object-run.c | 193 + .../compile-object-run.h} | 18 +- contrib/gdb-7/gdb/compile/compile.c | 763 + contrib/gdb-7/gdb/compile/compile.h | 106 + contrib/gdb-7/gdb/complaints.c | 23 +- contrib/gdb-7/gdb/complaints.h | 2 +- contrib/gdb-7/gdb/completer.c | 915 +- contrib/gdb-7/gdb/completer.h | 147 +- contrib/gdb-7/gdb/config.in | 161 +- contrib/gdb-7/gdb/config/aarch64/linux.mh | 5 +- contrib/gdb-7/gdb/config/i386/cygwin64.mh | 4 +- contrib/gdb-7/gdb/config/tilegx/linux.mh | 3 +- contrib/gdb-7/gdb/configure.ac | 2353 - contrib/gdb-7/gdb/configure.host | 223 - contrib/gdb-7/gdb/configure.tgt | 705 - contrib/gdb-7/gdb/continuations.c | 14 +- contrib/gdb-7/gdb/continuations.h | 2 +- contrib/gdb-7/gdb/copyright.py | 8 +- contrib/gdb-7/gdb/corefile.c | 173 +- contrib/gdb-7/gdb/corelow.c | 344 +- contrib/gdb-7/gdb/cp-abi.c | 82 +- contrib/gdb-7/gdb/cp-abi.h | 29 +- contrib/gdb-7/gdb/cp-name-parser.y | 28 +- contrib/gdb-7/gdb/cp-namespace.c | 792 +- contrib/gdb-7/gdb/cp-support.c | 273 +- contrib/gdb-7/gdb/cp-support.h | 33 +- contrib/gdb-7/gdb/cp-valprint.c | 164 +- contrib/gdb-7/gdb/cris-linux-tdep.c | 57 + .../gdb/{ravenscar-thread.h => cris-tdep.h} | 24 +- contrib/gdb-7/gdb/ctf.c | 1740 + contrib/gdb-7/gdb/{gdb_vfork.h => ctf.h} | 15 +- contrib/gdb-7/gdb/d-exp.c | 3400 + contrib/gdb-7/gdb/d-exp.y | 1636 + contrib/gdb-7/gdb/d-lang.c | 394 +- contrib/gdb-7/gdb/d-lang.h | 48 +- contrib/gdb-7/gdb/d-valprint.c | 8 +- contrib/gdb-7/gdb/data-directory/Makefile.in | 203 +- contrib/gdb-7/gdb/dbxread.c | 245 +- contrib/gdb-7/gdb/dcache.c | 194 +- contrib/gdb-7/gdb/dcache.h | 17 +- contrib/gdb-7/gdb/{gdb_vfork.h => debug.c} | 18 +- contrib/gdb-7/gdb/defs.h | 378 +- contrib/gdb-7/gdb/demangle.c | 164 +- contrib/gdb-7/gdb/dfp.c | 2 +- contrib/gdb-7/gdb/dfp.h | 2 +- contrib/gdb-7/gdb/dictionary.c | 5 +- contrib/gdb-7/gdb/dictionary.h | 2 +- contrib/gdb-7/gdb/disasm.c | 20 +- contrib/gdb-7/gdb/disasm.h | 10 +- contrib/gdb-7/gdb/doc/Doxyfile-base.in | 92 + contrib/gdb-7/gdb/doc/Doxyfile-gdb-api.in | 39 + .../__init__.py => doc/Doxyfile-gdb-xref.in} | 30 +- contrib/gdb-7/gdb/doc/Doxyfile-gdbserver.in | 45 + contrib/gdb-7/gdb/doc/LRS | 197 - contrib/gdb-7/gdb/doc/a4rc.sed | 11 - contrib/gdb-7/gdb/doc/agentexpr.texi | 767 - contrib/gdb-7/gdb/doc/all-cfg.texi | 45 - contrib/gdb-7/gdb/doc/annotate.texinfo | 852 - contrib/gdb-7/gdb/doc/doxy-index.in | 76 + contrib/gdb-7/gdb/doc/filter-for-doxygen | 14 + contrib/gdb-7/gdb/doc/filter-params.pl | 11 + contrib/gdb-7/gdb/doc/gcore.1 | 188 + contrib/gdb-7/gdb/doc/gdb.1 | 405 + contrib/gdb-7/gdb/doc/gdb.texinfo | 41708 ----- contrib/gdb-7/gdb/doc/gdbinit.5 | 209 + contrib/gdb-7/gdb/doc/gdbint.texinfo | 8155 - contrib/gdb-7/gdb/doc/gdbserver.1 | 377 + contrib/gdb-7/gdb/doc/gpl.texi | 735 - contrib/gdb-7/gdb/doc/observer.texi | 50 +- contrib/gdb-7/gdb/doc/stabs.texinfo | 4125 - contrib/gdb-7/gdb/doc/stack_frame.txt | 39 - contrib/gdb-7/gdb/doublest.c | 104 +- contrib/gdb-7/gdb/doublest.h | 2 +- contrib/gdb-7/gdb/dtrace-probe.c | 921 + contrib/gdb-7/gdb/dummy-frame.c | 161 +- contrib/gdb-7/gdb/dummy-frame.h | 30 +- contrib/gdb-7/gdb/dwarf2-frame-tailcall.c | 12 +- contrib/gdb-7/gdb/dwarf2-frame-tailcall.h | 2 +- contrib/gdb-7/gdb/dwarf2-frame.c | 240 +- contrib/gdb-7/gdb/dwarf2-frame.h | 31 +- contrib/gdb-7/gdb/dwarf2expr.c | 24 +- contrib/gdb-7/gdb/dwarf2expr.h | 17 +- contrib/gdb-7/gdb/dwarf2loc.c | 811 +- contrib/gdb-7/gdb/dwarf2loc.h | 120 +- contrib/gdb-7/gdb/dwarf2read.c | 7972 +- contrib/gdb-7/gdb/elfread.c | 617 +- contrib/gdb-7/gdb/environ.c | 11 +- contrib/gdb-7/gdb/environ.h | 4 +- contrib/gdb-7/gdb/eval.c | 356 +- contrib/gdb-7/gdb/event-loop.c | 483 +- contrib/gdb-7/gdb/event-loop.h | 16 +- contrib/gdb-7/gdb/event-top.c | 142 +- contrib/gdb-7/gdb/event-top.h | 18 +- contrib/gdb-7/gdb/exceptions.c | 363 +- contrib/gdb-7/gdb/exceptions.h | 171 +- contrib/gdb-7/gdb/exec.c | 589 +- contrib/gdb-7/gdb/exec.h | 57 +- contrib/gdb-7/gdb/expprint.c | 38 +- contrib/gdb-7/gdb/expression.h | 12 +- contrib/gdb-7/gdb/extension-priv.h | 354 + contrib/gdb-7/gdb/extension.c | 1069 + contrib/gdb-7/gdb/extension.h | 267 + contrib/gdb-7/gdb/f-exp.y | 346 +- contrib/gdb-7/gdb/f-lang.c | 11 +- contrib/gdb-7/gdb/f-lang.h | 5 +- contrib/gdb-7/gdb/f-typeprint.c | 5 +- contrib/gdb-7/gdb/f-valprint.c | 27 +- contrib/gdb-7/gdb/fbsd-nat.c | 435 +- contrib/gdb-7/gdb/fbsd-nat.h | 20 +- contrib/gdb-7/gdb/fbsd-tdep.c | 135 + .../gdb-7/gdb/{solib-target.h => fbsd-tdep.h} | 13 +- contrib/gdb-7/gdb/features/btrace-conf.dtd | 14 + contrib/gdb-7/gdb/features/btrace.dtd | 16 +- contrib/gdb-7/gdb/features/feature_to_c.sh | 10 +- contrib/gdb-7/gdb/features/gdb-target.dtd | 2 +- contrib/gdb-7/gdb/features/i386/32bit-avx.xml | 2 +- .../gdb-7/gdb/features/i386/32bit-avx512.xml | 30 + .../gdb-7/gdb/features/i386/32bit-core.xml | 2 +- .../gdb-7/gdb/features/i386/32bit-linux.xml | 2 +- contrib/gdb-7/gdb/features/i386/32bit-mpx.xml | 43 + contrib/gdb-7/gdb/features/i386/32bit-sse.xml | 2 +- contrib/gdb-7/gdb/features/i386/64bit-avx.xml | 2 +- .../gdb-7/gdb/features/i386/64bit-avx512.xml | 102 + .../gdb-7/gdb/features/i386/64bit-core.xml | 2 +- .../gdb-7/gdb/features/i386/64bit-linux.xml | 2 +- contrib/gdb-7/gdb/features/i386/64bit-mpx.xml | 43 + contrib/gdb-7/gdb/features/i386/64bit-sse.xml | 2 +- .../gdb/features/i386/amd64-avx-linux.xml | 2 +- contrib/gdb-7/gdb/features/i386/amd64-avx.xml | 2 +- .../gdb/features/i386/amd64-avx512-linux.c | 322 + ...4-avx-linux.xml => amd64-avx512-linux.xml} | 6 +- .../gdb-7/gdb/features/i386/amd64-avx512.c | 317 + .../i386/{amd64-avx.xml => amd64-avx512.xml} | 6 +- .../gdb-7/gdb/features/i386/amd64-linux.xml | 2 +- .../gdb-7/gdb/features/i386/amd64-mpx-linux.c | 211 + ...md64-avx-linux.xml => amd64-mpx-linux.xml} | 5 +- contrib/gdb-7/gdb/features/i386/amd64-mpx.c | 206 + .../i386/{amd64-avx.xml => amd64-mpx.xml} | 5 +- contrib/gdb-7/gdb/features/i386/amd64.xml | 2 +- .../gdb/features/i386/i386-avx-linux.xml | 2 +- contrib/gdb-7/gdb/features/i386/i386-avx.xml | 2 +- .../gdb/features/i386/i386-avx512-linux.c | 208 + ...86-avx-linux.xml => i386-avx512-linux.xml} | 6 +- contrib/gdb-7/gdb/features/i386/i386-avx512.c | 203 + .../i386/{i386-avx.xml => i386-avx512.xml} | 6 +- .../gdb-7/gdb/features/i386/i386-linux.xml | 2 +- .../gdb/features/i386/i386-mmx-linux.xml | 2 +- contrib/gdb-7/gdb/features/i386/i386-mmx.xml | 2 +- .../gdb-7/gdb/features/i386/i386-mpx-linux.c | 187 + ...{i386-avx-linux.xml => i386-mpx-linux.xml} | 5 +- contrib/gdb-7/gdb/features/i386/i386-mpx.c | 182 + .../i386/{i386-avx.xml => i386-mpx.xml} | 5 +- contrib/gdb-7/gdb/features/i386/i386.xml | 2 +- .../gdb-7/gdb/features/i386/x32-avx-linux.xml | 2 +- contrib/gdb-7/gdb/features/i386/x32-avx.xml | 2 +- .../gdb/features/i386/x32-avx512-linux.c | 322 + ...x32-avx-linux.xml => x32-avx512-linux.xml} | 6 +- contrib/gdb-7/gdb/features/i386/x32-avx512.c | 317 + .../i386/{x32-avx.xml => x32-avx512.xml} | 6 +- contrib/gdb-7/gdb/features/i386/x32-core.xml | 2 +- contrib/gdb-7/gdb/features/i386/x32-linux.xml | 2 +- contrib/gdb-7/gdb/features/i386/x32.xml | 2 +- .../gdb-7/gdb/features/library-list-aix.dtd | 18 + .../gdb-7/gdb/features/library-list-svr4.dtd | 2 +- contrib/gdb-7/gdb/features/library-list.dtd | 2 +- .../gdb-7/gdb/features/microblaze-core.xml | 67 + ...linux.xml => microblaze-stack-protect.xml} | 7 +- .../features/microblaze-with-stack-protect.c | 79 + ....xml => microblaze-with-stack-protect.xml} | 8 +- contrib/gdb-7/gdb/features/microblaze.c | 75 + .../{i386/i386-mmx.xml => microblaze.xml} | 7 +- contrib/gdb-7/gdb/features/nios2-cpu.xml | 59 + contrib/gdb-7/gdb/features/nios2-linux.c | 71 + .../{i386/i386-mmx.xml => nios2-linux.xml} | 9 +- contrib/gdb-7/gdb/features/nios2.c | 69 + .../features/{i386/i386-mmx.xml => nios2.xml} | 8 +- contrib/gdb-7/gdb/features/osdata.dtd | 2 +- contrib/gdb-7/gdb/features/s390-tdb.xml | 30 + contrib/gdb-7/gdb/features/s390-te-linux64.c | 118 + .../gdb-7/gdb/features/s390-te-linux64.xml | 25 + .../gdb-7/gdb/features/s390-tevx-linux64.c | 188 + .../gdb-7/gdb/features/s390-tevx-linux64.xml | 26 + contrib/gdb-7/gdb/features/s390-vx-linux64.c | 166 + .../gdb-7/gdb/features/s390-vx-linux64.xml | 25 + contrib/gdb-7/gdb/features/s390-vx.xml | 59 + contrib/gdb-7/gdb/features/s390x-te-linux64.c | 102 + .../gdb-7/gdb/features/s390x-te-linux64.xml | 24 + .../gdb-7/gdb/features/s390x-tevx-linux64.c | 172 + .../gdb-7/gdb/features/s390x-tevx-linux64.xml | 25 + contrib/gdb-7/gdb/features/s390x-vx-linux64.c | 150 + .../gdb-7/gdb/features/s390x-vx-linux64.xml | 24 + contrib/gdb-7/gdb/features/threads.dtd | 2 +- .../gdb-7/gdb/features/traceframe-info.dtd | 7 +- contrib/gdb-7/gdb/features/xinclude.dtd | 2 +- contrib/gdb-7/gdb/filesystem.c | 2 +- contrib/gdb-7/gdb/filesystem.h | 2 +- contrib/gdb-7/gdb/findcmd.c | 3 +- contrib/gdb-7/gdb/findvar.c | 171 +- contrib/gdb-7/gdb/fork-child.c | 38 +- contrib/gdb-7/gdb/frame-base.c | 2 +- contrib/gdb-7/gdb/frame-base.h | 2 +- contrib/gdb-7/gdb/frame-unwind.c | 118 +- contrib/gdb-7/gdb/frame-unwind.h | 2 +- contrib/gdb-7/gdb/frame.c | 651 +- contrib/gdb-7/gdb/frame.h | 94 +- contrib/gdb-7/gdb/ft32-tdep.c | 547 + .../gdb-7/gdb/{solib-target.h => ft32-tdep.h} | 16 +- contrib/gdb-7/gdb/gcore | 103 + contrib/gdb-7/gdb/gcore.c | 87 +- contrib/gdb-7/gdb/gcore.h | 7 +- contrib/gdb-7/gdb/gcore.in | 103 + contrib/gdb-7/gdb/gdb-code-style.el | 2 +- contrib/gdb-7/gdb/gdb-demangle.h | 5 +- contrib/gdb-7/gdb/gdb-dlfcn.c | 4 +- contrib/gdb-7/gdb/gdb-dlfcn.h | 4 +- contrib/gdb-7/gdb/gdb-gdb.py | 5 +- contrib/gdb-7/gdb/gdb-stabs.h | 19 +- contrib/gdb-7/gdb/gdb.1 | 403 - contrib/gdb-7/gdb/gdb.c | 4 +- contrib/gdb-7/gdb/gdb.h | 2 +- contrib/gdb-7/gdb/gdb_bfd.c | 391 +- contrib/gdb-7/gdb/gdb_bfd.h | 84 +- contrib/gdb-7/gdb/gdb_curses.h | 14 +- contrib/gdb-7/gdb/gdb_obstack.c | 2 +- contrib/gdb-7/gdb/gdb_obstack.h | 8 +- contrib/gdb-7/gdb/gdb_ptrace.h | 12 +- contrib/gdb-7/gdb/gdb_regex.h | 4 +- contrib/gdb-7/gdb/gdb_select.h | 2 +- contrib/gdb-7/gdb/gdb_usleep.c | 3 +- contrib/gdb-7/gdb/gdb_usleep.h | 2 +- contrib/gdb-7/gdb/gdb_vfork.h | 2 +- contrib/gdb-7/gdb/gdb_wchar.h | 12 +- contrib/gdb-7/gdb/gdbarch.c | 1097 +- contrib/gdb-7/gdb/gdbarch.h | 363 +- contrib/gdb-7/gdb/gdbcmd.h | 10 +- contrib/gdb-7/gdb/gdbcore.h | 49 +- contrib/gdb-7/gdb/gdbthread.h | 155 +- contrib/gdb-7/gdb/gdbtypes.c | 1311 +- contrib/gdb-7/gdb/gdbtypes.h | 1444 +- contrib/gdb-7/gdb/gnu-v2-abi.c | 21 +- contrib/gdb-7/gdb/gnu-v3-abi.c | 361 +- .../gdb-7/gdb/gnulib/import/basename-lgpl.c | 75 + .../gdb/gnulib/import/canonicalize-lgpl.c | 411 + contrib/gdb-7/gdb/gnulib/import/dirent.in.h | 258 + .../{solib-target.h => gnulib/import/dirfd.c} | 26 +- .../gdb-7/gdb/gnulib/import/dirname-lgpl.c | 86 + contrib/gdb-7/gdb/gnulib/import/dirname.h | 46 + contrib/gdb-7/gdb/gnulib/import/dosname.h | 53 + contrib/gdb-7/gdb/gnulib/import/errno.in.h | 279 + .../gnulib/import/extra/snippet/_Noreturn.h | 10 + contrib/gdb-7/gdb/gnulib/import/float+.h | 147 + contrib/gdb-7/gdb/gnulib/import/float.c | 33 + contrib/gdb-7/gdb/gnulib/import/float.in.h | 188 + contrib/gdb-7/gdb/gnulib/import/fpucw.h | 108 + contrib/gdb-7/gdb/gnulib/import/frexp.c | 168 + .../import/frexpl.c} | 28 +- contrib/gdb-7/gdb/gnulib/import/isnan.c | 177 + .../import/isnand-nolibm.h} | 37 +- .../{gdb_vfork.h => gnulib/import/isnand.c} | 17 +- .../gdb-7/gdb/gnulib/import/isnanl-nolibm.h | 33 + .../{gdb_vfork.h => gnulib/import/isnanl.c} | 18 +- .../gdb/{gcore.h => gnulib/import/itold.c} | 25 +- contrib/gdb-7/gdb/gnulib/import/lstat.c | 97 + .../gdb/gnulib/import/m4/canonicalize.m4 | 124 + .../gdb-7/gdb/gnulib/import/m4/dirent_h.m4 | 64 + contrib/gdb-7/gdb/gnulib/import/m4/dirfd.m4 | 83 + contrib/gdb-7/gdb/gnulib/import/m4/dirname.m4 | 19 + .../gdb/gnulib/import/m4/double-slash-root.m4 | 38 + contrib/gdb-7/gdb/gnulib/import/m4/eealloc.m4 | 31 + contrib/gdb-7/gdb/gnulib/import/m4/errno_h.m4 | 137 + .../gdb-7/gdb/gnulib/import/m4/exponentd.m4 | 116 + .../gdb-7/gdb/gnulib/import/m4/exponentl.m4 | 98 + contrib/gdb-7/gdb/gnulib/import/m4/float_h.m4 | 98 + contrib/gdb-7/gdb/gnulib/import/m4/fpieee.m4 | 54 + contrib/gdb-7/gdb/gnulib/import/m4/frexp.m4 | 170 + contrib/gdb-7/gdb/gnulib/import/m4/frexpl.m4 | 231 + contrib/gdb-7/gdb/gnulib/import/m4/isnand.m4 | 96 + contrib/gdb-7/gdb/gnulib/import/m4/isnanl.m4 | 255 + .../gdb-7/gdb/gnulib/import/m4/largefile.m4 | 149 + contrib/gdb-7/gdb/gnulib/import/m4/lstat.m4 | 73 + contrib/gdb-7/gdb/gnulib/import/m4/malloc.m4 | 98 + contrib/gdb-7/gdb/gnulib/import/m4/malloca.m4 | 15 + contrib/gdb-7/gdb/gnulib/import/m4/math_h.m4 | 353 + contrib/gdb-7/gdb/gnulib/import/m4/nocrash.m4 | 130 + contrib/gdb-7/gdb/gnulib/import/m4/off_t.m4 | 18 + contrib/gdb-7/gdb/gnulib/import/m4/pathmax.m4 | 42 + .../gdb-7/gdb/gnulib/import/m4/readlink.m4 | 71 + contrib/gdb-7/gdb/gnulib/import/m4/rename.m4 | 225 + contrib/gdb-7/gdb/gnulib/import/m4/rmdir.m4 | 49 + contrib/gdb-7/gdb/gnulib/import/m4/ssize_t.m4 | 23 + contrib/gdb-7/gdb/gnulib/import/m4/stat.m4 | 71 + contrib/gdb-7/gdb/gnulib/import/m4/stdio_h.m4 | 194 + .../gdb-7/gdb/gnulib/import/m4/stdlib_h.m4 | 115 + contrib/gdb-7/gdb/gnulib/import/m4/strstr.m4 | 130 + .../gdb-7/gdb/gnulib/import/m4/strtok_r.m4 | 74 + .../gdb-7/gdb/gnulib/import/m4/sys_stat_h.m4 | 96 + .../gdb-7/gdb/gnulib/import/m4/sys_types_h.m4 | 24 + contrib/gdb-7/gdb/gnulib/import/m4/time_h.m4 | 109 + .../gdb-7/gdb/gnulib/import/m4/unistd_h.m4 | 186 + contrib/gdb-7/gdb/gnulib/import/malloc.c | 56 + contrib/gdb-7/gdb/gnulib/import/malloca.c | 140 + contrib/gdb-7/gdb/gnulib/import/malloca.h | 133 + .../gdb-7/gdb/gnulib/import/malloca.valgrind | 7 + contrib/gdb-7/gdb/gnulib/import/math.c | 3 + contrib/gdb-7/gdb/gnulib/import/math.in.h | 2275 + contrib/gdb-7/gdb/gnulib/import/pathmax.h | 83 + contrib/gdb-7/gdb/gnulib/import/readlink.c | 74 + contrib/gdb-7/gdb/gnulib/import/rename.c | 473 + contrib/gdb-7/gdb/gnulib/import/rmdir.c | 53 + .../import/same-inode.h} | 32 +- contrib/gdb-7/gdb/gnulib/import/stat.c | 138 + contrib/gdb-7/gdb/gnulib/import/stdio.c | 3 + contrib/gdb-7/gdb/gnulib/import/stdio.in.h | 1345 + contrib/gdb-7/gdb/gnulib/import/stdlib.in.h | 937 + contrib/gdb-7/gdb/gnulib/import/stripslash.c | 45 + contrib/gdb-7/gdb/gnulib/import/strstr.c | 82 + contrib/gdb-7/gdb/gnulib/import/strtok_r.c | 76 + contrib/gdb-7/gdb/gnulib/import/sys_stat.in.h | 728 + .../gdb-7/gdb/gnulib/import/sys_types.in.h | 51 + contrib/gdb-7/gdb/gnulib/import/time.in.h | 248 + contrib/gdb-7/gdb/gnulib/import/unistd.c | 3 + contrib/gdb-7/gdb/gnulib/import/unistd.in.h | 1541 + contrib/gdb-7/gdb/gnulib/import/verify.h | 245 + contrib/gdb-7/gdb/go-exp.c | 2196 +- contrib/gdb-7/gdb/go-exp.y | 298 +- contrib/gdb-7/gdb/go-lang.c | 17 +- contrib/gdb-7/gdb/go-lang.h | 6 +- contrib/gdb-7/gdb/go-typeprint.c | 2 +- contrib/gdb-7/gdb/go-valprint.c | 2 +- contrib/gdb-7/gdb/gregset.h | 2 +- contrib/gdb-7/gdb/guile/guile-internal.h | 626 + contrib/gdb-7/gdb/guile/guile.c | 894 + .../gdb/{tui/tui-command.h => guile/guile.h} | 17 +- contrib/gdb-7/gdb/guile/lib/gdb.scm | 510 + contrib/gdb-7/gdb/guile/lib/gdb/boot.scm | 41 + .../gdb-7/gdb/guile/lib/gdb/experimental.scm | 34 + contrib/gdb-7/gdb/guile/lib/gdb/init.scm | 168 + contrib/gdb-7/gdb/guile/lib/gdb/iterator.scm | 81 + contrib/gdb-7/gdb/guile/lib/gdb/printing.scm | 60 + contrib/gdb-7/gdb/guile/lib/gdb/support.scm | 33 + contrib/gdb-7/gdb/guile/lib/gdb/types.scm | 78 + contrib/gdb-7/gdb/guile/scm-arch.c | 656 + contrib/gdb-7/gdb/guile/scm-auto-load.c | 79 + contrib/gdb-7/gdb/guile/scm-block.c | 805 + contrib/gdb-7/gdb/guile/scm-breakpoint.c | 1323 + contrib/gdb-7/gdb/guile/scm-cmd.c | 890 + contrib/gdb-7/gdb/guile/scm-disasm.c | 358 + contrib/gdb-7/gdb/guile/scm-exception.c | 701 + contrib/gdb-7/gdb/guile/scm-frame.c | 1178 + contrib/gdb-7/gdb/guile/scm-gsmob.c | 293 + contrib/gdb-7/gdb/guile/scm-iterator.c | 360 + contrib/gdb-7/gdb/guile/scm-lazy-string.c | 362 + contrib/gdb-7/gdb/guile/scm-math.c | 1011 + contrib/gdb-7/gdb/guile/scm-objfile.c | 439 + contrib/gdb-7/gdb/guile/scm-param.c | 1196 + contrib/gdb-7/gdb/guile/scm-ports.c | 1423 + contrib/gdb-7/gdb/guile/scm-pretty-print.c | 1132 + contrib/gdb-7/gdb/guile/scm-progspace.c | 426 + contrib/gdb-7/gdb/guile/scm-safe-call.c | 467 + contrib/gdb-7/gdb/guile/scm-string.c | 283 + contrib/gdb-7/gdb/guile/scm-symbol.c | 824 + contrib/gdb-7/gdb/guile/scm-symtab.c | 698 + contrib/gdb-7/gdb/guile/scm-type.c | 1522 + contrib/gdb-7/gdb/guile/scm-utils.c | 642 + contrib/gdb-7/gdb/guile/scm-value.c | 1596 + contrib/gdb-7/gdb/hppaobsd-nat.c | 265 + ...rc-ravenscar-thread.h => i386-linux-nat.h} | 12 +- contrib/gdb-7/gdb/i386-nat.c | 886 - contrib/gdb-7/gdb/i386-nat.h | 123 - contrib/gdb-7/gdb/i386-tdep.c | 1913 +- contrib/gdb-7/gdb/i386-tdep.h | 164 +- contrib/gdb-7/gdb/i386bsd-nat.c | 79 +- contrib/gdb-7/gdb/i386bsd-nat.h | 5 +- contrib/gdb-7/gdb/i386bsd-tdep.c | 4 +- contrib/gdb-7/gdb/i386fbsd-tdep.c | 274 +- .../gdb-7/gdb/{gcore.h => i386fbsd-tdep.h} | 20 +- contrib/gdb-7/gdb/i387-tdep.c | 553 +- contrib/gdb-7/gdb/i387-tdep.h | 32 +- contrib/gdb-7/gdb/inf-child.c | 322 +- contrib/gdb-7/gdb/inf-child.h | 23 +- contrib/gdb-7/gdb/inf-loop.c | 54 +- contrib/gdb-7/gdb/inf-loop.h | 2 +- contrib/gdb-7/gdb/inf-ptrace.c | 171 +- contrib/gdb-7/gdb/inf-ptrace.h | 2 +- contrib/gdb-7/gdb/infcall.c | 313 +- contrib/gdb-7/gdb/infcall.h | 23 +- contrib/gdb-7/gdb/infcmd.c | 897 +- contrib/gdb-7/gdb/inferior.c | 38 +- contrib/gdb-7/gdb/inferior.h | 262 +- contrib/gdb-7/gdb/inflow.c | 106 +- contrib/gdb-7/gdb/inflow.h | 2 +- contrib/gdb-7/gdb/infrun.c | 3979 +- contrib/gdb-7/gdb/infrun.h | 192 + contrib/gdb-7/gdb/inline-frame.c | 28 +- contrib/gdb-7/gdb/inline-frame.h | 2 +- contrib/gdb-7/gdb/interps.c | 121 +- contrib/gdb-7/gdb/interps.h | 12 +- contrib/gdb-7/gdb/jit-reader.in | 2 +- contrib/gdb-7/gdb/jit.c | 154 +- contrib/gdb-7/gdb/jit.h | 2 +- contrib/gdb-7/gdb/jv-exp.y | 413 +- contrib/gdb-7/gdb/jv-lang.c | 49 +- contrib/gdb-7/gdb/jv-lang.h | 5 +- contrib/gdb-7/gdb/jv-typeprint.c | 13 +- contrib/gdb-7/gdb/jv-valprint.c | 48 +- contrib/gdb-7/gdb/jv-varobj.c | 107 + contrib/gdb-7/gdb/language.c | 165 +- contrib/gdb-7/gdb/language.h | 84 +- contrib/gdb-7/gdb/libiberty.m4 | 31 + contrib/gdb-7/gdb/libmcheck.m4 | 43 + contrib/gdb-7/gdb/linespec.c | 492 +- contrib/gdb-7/gdb/linespec.h | 6 +- contrib/gdb-7/gdb/m2-exp.y | 292 +- contrib/gdb-7/gdb/m2-lang.c | 7 +- contrib/gdb-7/gdb/m2-lang.h | 5 +- contrib/gdb-7/gdb/m2-typeprint.c | 15 +- contrib/gdb-7/gdb/m2-valprint.c | 8 +- contrib/gdb-7/gdb/machoread.c | 139 +- contrib/gdb-7/gdb/macrocmd.c | 60 +- contrib/gdb-7/gdb/macroexp.c | 21 +- contrib/gdb-7/gdb/macroexp.h | 4 +- contrib/gdb-7/gdb/macroscope.c | 13 +- contrib/gdb-7/gdb/macroscope.h | 2 +- contrib/gdb-7/gdb/macrotab.c | 35 +- contrib/gdb-7/gdb/macrotab.h | 9 +- contrib/gdb-7/gdb/main.c | 466 +- contrib/gdb-7/gdb/main.h | 11 +- contrib/gdb-7/gdb/maint.c | 446 +- contrib/gdb-7/gdb/{gdb_usleep.h => maint.h} | 19 +- contrib/gdb-7/gdb/make-target-delegates | 357 + contrib/gdb-7/gdb/mdebugread.c | 308 +- contrib/gdb-7/gdb/mdebugread.h | 2 +- contrib/gdb-7/gdb/mem-break.c | 72 +- contrib/gdb-7/gdb/memattr.c | 36 +- contrib/gdb-7/gdb/memattr.h | 2 +- contrib/gdb-7/gdb/memory-map.c | 6 +- contrib/gdb-7/gdb/memory-map.h | 2 +- contrib/gdb-7/gdb/memrange.c | 11 +- contrib/gdb-7/gdb/memrange.h | 7 +- contrib/gdb-7/gdb/mi/mi-cmd-break.c | 171 +- contrib/gdb-7/gdb/mi/mi-cmd-break.h | 2 +- contrib/gdb-7/gdb/mi/mi-cmd-catch.c | 144 +- contrib/gdb-7/gdb/mi/mi-cmd-disas.c | 3 +- contrib/gdb-7/gdb/mi/mi-cmd-env.c | 6 +- contrib/gdb-7/gdb/mi/mi-cmd-file.c | 15 +- contrib/gdb-7/gdb/mi/mi-cmd-info.c | 82 +- contrib/gdb-7/gdb/mi/mi-cmd-stack.c | 430 +- contrib/gdb-7/gdb/mi/mi-cmd-target.c | 2 +- contrib/gdb-7/gdb/mi/mi-cmd-var.c | 94 +- contrib/gdb-7/gdb/mi/mi-cmds.c | 21 +- contrib/gdb-7/gdb/mi/mi-cmds.h | 13 +- contrib/gdb-7/gdb/mi/mi-common.c | 3 +- contrib/gdb-7/gdb/mi/mi-common.h | 7 +- contrib/gdb-7/gdb/mi/mi-console.c | 13 +- contrib/gdb-7/gdb/mi/mi-console.h | 2 +- contrib/gdb-7/gdb/mi/mi-getopt.c | 37 +- contrib/gdb-7/gdb/mi/mi-getopt.h | 10 +- contrib/gdb-7/gdb/mi/mi-interp.c | 392 +- contrib/gdb-7/gdb/mi/mi-main.c | 784 +- contrib/gdb-7/gdb/mi/mi-main.h | 6 +- contrib/gdb-7/gdb/mi/mi-out.c | 17 +- contrib/gdb-7/gdb/mi/mi-out.h | 2 +- contrib/gdb-7/gdb/mi/mi-parse.c | 55 +- contrib/gdb-7/gdb/mi/mi-parse.h | 10 +- contrib/gdb-7/gdb/mi/mi-symbol-cmds.c | 13 +- contrib/gdb-7/gdb/minidebug.c | 30 +- contrib/gdb-7/gdb/minsyms.c | 539 +- contrib/gdb-7/gdb/minsyms.h | 96 +- contrib/gdb-7/gdb/mips-sde-tdep.c | 270 + contrib/gdb-7/gdb/mipsread.c | 34 +- contrib/gdb-7/gdb/msp430-tdep.c | 1040 + contrib/gdb-7/gdb/nat/gdb_thread_db.h | 16 + .../gdb_thread_db.h => nat/glibc_thread_db.h} | 89 +- contrib/gdb-7/gdb/nat/linux-btrace.c | 1145 + contrib/gdb-7/gdb/nat/linux-btrace.h | 129 + contrib/gdb-7/gdb/nat/linux-namespaces.c | 1057 + contrib/gdb-7/gdb/nat/linux-namespaces.h | 76 + contrib/gdb-7/gdb/nat/linux-nat.h | 83 + .../gdb-7/gdb/{common => nat}/linux-osdata.c | 263 +- .../gdb-7/gdb/{common => nat}/linux-osdata.h | 6 +- contrib/gdb-7/gdb/nat/linux-personality.c | 94 + .../cli-dump.h => nat/linux-personality.h} | 25 +- contrib/gdb-7/gdb/nat/linux-procfs.c | 275 + contrib/gdb-7/gdb/nat/linux-procfs.h | 76 + contrib/gdb-7/gdb/nat/linux-ptrace.c | 611 + contrib/gdb-7/gdb/nat/linux-ptrace.h | 171 + contrib/gdb-7/gdb/nat/linux-waitpid.c | 151 + .../gdb/{bfd-target.h => nat/linux-waitpid.h} | 22 +- contrib/gdb-7/gdb/nat/mips-linux-watch.c | 349 + contrib/gdb-7/gdb/nat/mips-linux-watch.h | 118 + contrib/gdb-7/gdb/nat/ppc-linux.c | 75 + contrib/gdb-7/gdb/nat/ppc-linux.h | 91 + contrib/gdb-7/gdb/nat/x86-cpuid.h | 63 + contrib/gdb-7/gdb/nat/x86-dregs.c | 655 + contrib/gdb-7/gdb/nat/x86-dregs.h | 131 + contrib/gdb-7/gdb/nat/x86-gcc-cpuid.h | 278 + contrib/gdb-7/gdb/nat/x86-linux-dregs.c | 183 + contrib/gdb-7/gdb/nat/x86-linux-dregs.h | 53 + contrib/gdb-7/gdb/nat/x86-linux.c | 74 + contrib/gdb-7/gdb/nat/x86-linux.h | 46 + contrib/gdb-7/gdb/nios2-linux-tdep.c | 230 + contrib/gdb-7/gdb/nios2-tdep.c | 1829 + contrib/gdb-7/gdb/nios2-tdep.h | 80 + contrib/gdb-7/gdb/objc-lang.c | 154 +- contrib/gdb-7/gdb/objc-lang.h | 8 +- contrib/gdb-7/gdb/objfiles.c | 412 +- contrib/gdb-7/gdb/objfiles.h | 285 +- contrib/gdb-7/gdb/obsd-nat.c | 186 + contrib/gdb-7/gdb/{gdb_vfork.h => obsd-nat.h} | 15 +- contrib/gdb-7/gdb/observer.c | 6 +- contrib/gdb-7/gdb/observer.sh | 2 +- contrib/gdb-7/gdb/opencl-lang.c | 82 +- contrib/gdb-7/gdb/osabi.c | 180 +- contrib/gdb-7/gdb/osabi.h | 6 +- contrib/gdb-7/gdb/osdata.c | 7 +- contrib/gdb-7/gdb/osdata.h | 2 +- contrib/gdb-7/gdb/p-exp.y | 473 +- contrib/gdb-7/gdb/p-lang.c | 16 +- contrib/gdb-7/gdb/p-lang.h | 5 +- contrib/gdb-7/gdb/p-typeprint.c | 16 +- contrib/gdb-7/gdb/p-valprint.c | 66 +- contrib/gdb-7/gdb/parse.c | 410 +- contrib/gdb-7/gdb/parser-defs.h | 117 +- contrib/gdb-7/gdb/posix-hdep.c | 24 +- contrib/gdb-7/gdb/ppc-ravenscar-thread.c | 8 +- contrib/gdb-7/gdb/ppc-ravenscar-thread.h | 2 +- contrib/gdb-7/gdb/printcmd.c | 404 +- contrib/gdb-7/gdb/probe.c | 550 +- contrib/gdb-7/gdb/probe.h | 116 +- contrib/gdb-7/gdb/proc-service.list | 2 +- contrib/gdb-7/gdb/progspace.c | 65 +- contrib/gdb-7/gdb/progspace.h | 14 +- contrib/gdb-7/gdb/prologue-value.c | 4 +- contrib/gdb-7/gdb/prologue-value.h | 43 +- contrib/gdb-7/gdb/psympriv.h | 41 +- contrib/gdb-7/gdb/psymtab.c | 493 +- contrib/gdb-7/gdb/psymtab.h | 8 +- contrib/gdb-7/gdb/python/lib/gdb/__init__.py | 124 - .../gdb/python/lib/gdb/command/explore.py | 760 - .../python/lib/gdb/command/pretty_printers.py | 368 - .../gdb/python/lib/gdb/command/prompt.py | 66 - .../python/lib/gdb/command/type_printers.py | 125 - .../gdb/python/lib/gdb/function/strfns.py | 108 - contrib/gdb-7/gdb/python/lib/gdb/printing.py | 263 - contrib/gdb-7/gdb/python/lib/gdb/prompt.py | 148 - contrib/gdb-7/gdb/python/lib/gdb/types.py | 176 - contrib/gdb-7/gdb/python/py-arch.c | 294 - contrib/gdb-7/gdb/python/py-auto-load.c | 293 - contrib/gdb-7/gdb/python/py-block.c | 548 - contrib/gdb-7/gdb/python/py-bpevent.c | 58 - contrib/gdb-7/gdb/python/py-breakpoint.c | 1021 - contrib/gdb-7/gdb/python/py-cmd.c | 697 - contrib/gdb-7/gdb/python/py-continueevent.c | 54 - contrib/gdb-7/gdb/python/py-event.c | 183 - contrib/gdb-7/gdb/python/py-event.h | 120 - contrib/gdb-7/gdb/python/py-events.h | 59 - contrib/gdb-7/gdb/python/py-evtregistry.c | 171 - contrib/gdb-7/gdb/python/py-evts.c | 96 - contrib/gdb-7/gdb/python/py-exitedevent.c | 91 - .../gdb-7/gdb/python/py-finishbreakpoint.c | 466 - contrib/gdb-7/gdb/python/py-frame.c | 724 - contrib/gdb-7/gdb/python/py-function.c | 248 - contrib/gdb-7/gdb/python/py-gdb-readline.c | 113 - contrib/gdb-7/gdb/python/py-inferior.c | 946 - contrib/gdb-7/gdb/python/py-infthread.c | 341 - contrib/gdb-7/gdb/python/py-lazy-string.c | 249 - contrib/gdb-7/gdb/python/py-newobjfileevent.c | 73 - contrib/gdb-7/gdb/python/py-objfile.c | 318 - contrib/gdb-7/gdb/python/py-param.c | 821 - contrib/gdb-7/gdb/python/py-prettyprint.c | 849 - contrib/gdb-7/gdb/python/py-progspace.c | 305 - contrib/gdb-7/gdb/python/py-signalevent.c | 60 - contrib/gdb-7/gdb/python/py-stopevent.c | 119 - contrib/gdb-7/gdb/python/py-stopevent.h | 36 - contrib/gdb-7/gdb/python/py-symbol.c | 595 - contrib/gdb-7/gdb/python/py-symtab.c | 621 - contrib/gdb-7/gdb/python/py-threadevent.c | 77 - contrib/gdb-7/gdb/python/py-type.c | 1817 - contrib/gdb-7/gdb/python/py-utils.c | 404 - contrib/gdb-7/gdb/python/py-value.c | 1548 - contrib/gdb-7/gdb/python/python-config.py | 78 - contrib/gdb-7/gdb/python/python-internal.h | 388 - contrib/gdb-7/gdb/python/python.c | 1860 - contrib/gdb-7/gdb/python/python.h | 58 - contrib/gdb-7/gdb/ravenscar-thread.c | 68 +- contrib/gdb-7/gdb/ravenscar-thread.h | 2 +- contrib/gdb-7/gdb/record-btrace.c | 2402 +- contrib/gdb-7/gdb/record-full.c | 557 +- contrib/gdb-7/gdb/record-full.h | 6 +- contrib/gdb-7/gdb/record.c | 237 +- contrib/gdb-7/gdb/record.h | 44 +- contrib/gdb-7/gdb/regcache.c | 203 +- contrib/gdb-7/gdb/regcache.h | 61 +- .../gdb/regformats/i386/amd64-avx-linux.dat | 3 +- .../gdb-7/gdb/regformats/i386/amd64-avx.dat | 3 +- .../regformats/i386/amd64-avx512-linux.dat | 157 + .../gdb/regformats/i386/amd64-avx512.dat | 156 + .../gdb-7/gdb/regformats/i386/amd64-linux.dat | 3 +- ...{x32-avx-linux.dat => amd64-mpx-linux.dat} | 13 +- .../i386/{x32-avx-linux.dat => amd64-mpx.dat} | 14 +- contrib/gdb-7/gdb/regformats/i386/amd64.dat | 3 +- .../gdb/regformats/i386/i386-avx-linux.dat | 3 +- .../gdb-7/gdb/regformats/i386/i386-avx.dat | 3 +- ...86-avx-linux.dat => i386-avx512-linux.dat} | 29 +- .../{i386-avx-linux.dat => i386-avx512.dat} | 30 +- .../gdb-7/gdb/regformats/i386/i386-linux.dat | 3 +- .../gdb/regformats/i386/i386-mmx-linux.dat | 3 +- .../gdb-7/gdb/regformats/i386/i386-mmx.dat | 3 +- ...{i386-avx-linux.dat => i386-mpx-linux.dat} | 13 +- .../i386/{i386-avx-linux.dat => i386-mpx.dat} | 14 +- contrib/gdb-7/gdb/regformats/i386/i386.dat | 3 +- .../gdb/regformats/i386/x32-avx-linux.dat | 3 +- contrib/gdb-7/gdb/regformats/i386/x32-avx.dat | 3 +- .../gdb/regformats/i386/x32-avx512-linux.dat | 157 + .../gdb-7/gdb/regformats/i386/x32-avx512.dat | 156 + .../gdb-7/gdb/regformats/i386/x32-linux.dat | 3 +- contrib/gdb-7/gdb/regformats/i386/x32.dat | 3 +- .../microblaze-with-stack-protect.dat | 64 + contrib/gdb-7/gdb/regformats/nios2-linux.dat | 54 + contrib/gdb-7/gdb/regformats/regdat.sh | 46 +- contrib/gdb-7/gdb/regformats/regdef.h | 2 +- .../gdb-7/gdb/regformats/s390-te-linux64.dat | 95 + .../gdb/regformats/s390-tevx-linux64.dat | 127 + .../gdb-7/gdb/regformats/s390-vx-linux64.dat | 107 + .../gdb-7/gdb/regformats/s390x-te-linux64.dat | 79 + .../gdb/regformats/s390x-tevx-linux64.dat | 111 + .../gdb-7/gdb/regformats/s390x-vx-linux64.dat | 91 + contrib/gdb-7/gdb/reggroups.c | 48 +- contrib/gdb-7/gdb/reggroups.h | 11 +- contrib/gdb-7/gdb/registry.c | 11 +- contrib/gdb-7/gdb/registry.h | 9 +- contrib/gdb-7/gdb/regset.c | 44 - contrib/gdb-7/gdb/regset.h | 32 +- contrib/gdb-7/gdb/remote-fileio.c | 251 +- contrib/gdb-7/gdb/remote-fileio.h | 8 +- contrib/gdb-7/gdb/remote-notif.c | 133 +- contrib/gdb-7/gdb/remote-notif.h | 58 +- contrib/gdb-7/gdb/remote.c | 4835 +- contrib/gdb-7/gdb/remote.h | 16 +- contrib/gdb-7/gdb/reverse.c | 21 +- .../gdb-7/gdb/{gcore.h => rs6000-aix-tdep.h} | 19 +- contrib/gdb-7/gdb/s390-linux-nat.c | 747 + contrib/gdb-7/gdb/s390-linux-tdep.c | 3371 + contrib/gdb-7/gdb/s390-linux-tdep.h | 219 + contrib/gdb-7/gdb/sentinel-frame.c | 2 +- contrib/gdb-7/gdb/sentinel-frame.h | 2 +- contrib/gdb-7/gdb/ser-base.c | 25 +- contrib/gdb-7/gdb/ser-base.h | 7 +- contrib/gdb-7/gdb/ser-pipe.c | 74 +- contrib/gdb-7/gdb/ser-tcp.c | 94 +- contrib/gdb-7/gdb/ser-tcp.h | 2 +- contrib/gdb-7/gdb/ser-unix.c | 115 +- contrib/gdb-7/gdb/ser-unix.h | 2 +- contrib/gdb-7/gdb/serial.c | 125 +- contrib/gdb-7/gdb/serial.h | 26 +- contrib/gdb-7/gdb/sim-regno.h | 2 +- contrib/gdb-7/gdb/skip.c | 8 +- contrib/gdb-7/gdb/skip.h | 2 +- contrib/gdb-7/gdb/solib-aix.c | 848 + .../gdb-7/gdb/{gdb_vfork.h => solib-aix.h} | 16 +- contrib/gdb-7/gdb/solib-svr4.c | 1058 +- contrib/gdb-7/gdb/solib-svr4.h | 2 +- contrib/gdb-7/gdb/solib-target.c | 34 +- contrib/gdb-7/gdb/solib-target.h | 2 +- contrib/gdb-7/gdb/solib.c | 546 +- contrib/gdb-7/gdb/solib.h | 14 +- contrib/gdb-7/gdb/solist.h | 33 +- contrib/gdb-7/gdb/somread.c | 433 - contrib/gdb-7/gdb/source.c | 249 +- contrib/gdb-7/gdb/source.h | 9 +- contrib/gdb-7/gdb/sparc-ravenscar-thread.c | 8 +- contrib/gdb-7/gdb/sparc-ravenscar-thread.h | 2 +- contrib/gdb-7/gdb/sparc64obsd-nat.c | 131 + contrib/gdb-7/gdb/stabsread.c | 308 +- contrib/gdb-7/gdb/stabsread.h | 7 +- contrib/gdb-7/gdb/stack.c | 506 +- contrib/gdb-7/gdb/stack.h | 8 +- contrib/gdb-7/gdb/stap-probe.c | 807 +- contrib/gdb-7/gdb/stap-probe.h | 8 +- contrib/gdb-7/gdb/std-operator.def | 16 +- contrib/gdb-7/gdb/std-regs.c | 5 +- contrib/gdb-7/gdb/stub-termcap.c | 101 + contrib/gdb-7/gdb/stubs/ChangeLog | 21 - contrib/gdb-7/gdb/stubs/buildvms.com | 2 +- contrib/gdb-7/gdb/stubs/ia64vms-stub.c | 2 +- contrib/gdb-7/gdb/symfile-debug.c | 674 + contrib/gdb-7/gdb/symfile.c | 1033 +- contrib/gdb-7/gdb/symfile.h | 199 +- contrib/gdb-7/gdb/symmisc.c | 351 +- contrib/gdb-7/gdb/symtab.c | 3556 +- contrib/gdb-7/gdb/symtab.h | 665 +- contrib/gdb-7/gdb/syscalls/aarch64-linux.xml | 271 + contrib/gdb-7/gdb/syscalls/arm-linux.py | 60 + contrib/gdb-7/gdb/syscalls/arm-linux.xml | 398 + contrib/gdb-7/gdb/syscalls/gdb-syscalls.dtd | 2 +- contrib/gdb-7/gdb/syscalls/s390-linux.xml | 342 + contrib/gdb-7/gdb/syscalls/s390x-linux.xml | 309 + contrib/gdb-7/gdb/system-gdbinit/elinos.py | 91 + .../wrs-linux.py} | 13 +- contrib/gdb-7/gdb/target-dcache.c | 199 + .../gdb/{gdb_usleep.h => target-dcache.h} | 23 +- contrib/gdb-7/gdb/target-debug.h | 196 + contrib/gdb-7/gdb/target-delegates.c | 4488 + contrib/gdb-7/gdb/target-descriptions.c | 110 +- contrib/gdb-7/gdb/target-descriptions.h | 2 +- contrib/gdb-7/gdb/target-memory.c | 5 +- contrib/gdb-7/gdb/target.c | 3682 +- contrib/gdb-7/gdb/target.h | 1473 +- .../gdb/{tui/tui-stack.h => target/resume.h} | 28 +- contrib/gdb-7/gdb/target/target.h | 73 + .../gdb/{mi/mi-cmd-break.h => target/wait.h} | 20 +- contrib/gdb-7/gdb/target/waitstatus.c | 69 + contrib/gdb-7/gdb/target/waitstatus.h | 146 + contrib/gdb-7/gdb/terminal.h | 6 +- contrib/gdb-7/gdb/thread.c | 466 +- contrib/gdb-7/gdb/top.c | 690 +- contrib/gdb-7/gdb/top.h | 15 +- contrib/gdb-7/gdb/tracefile-tfile.c | 1055 + contrib/gdb-7/gdb/tracefile.c | 523 + contrib/gdb-7/gdb/tracefile.h | 117 + contrib/gdb-7/gdb/tracepoint.c | 1941 +- contrib/gdb-7/gdb/tracepoint.h | 97 +- contrib/gdb-7/gdb/trad-frame.c | 2 +- contrib/gdb-7/gdb/trad-frame.h | 4 +- contrib/gdb-7/gdb/tramp-frame.c | 7 +- contrib/gdb-7/gdb/tramp-frame.h | 9 +- contrib/gdb-7/gdb/transform.m4 | 23 + contrib/gdb-7/gdb/tui/tui-command.c | 125 +- contrib/gdb-7/gdb/tui/tui-command.h | 5 +- contrib/gdb-7/gdb/tui/tui-data.c | 51 +- contrib/gdb-7/gdb/tui/tui-data.h | 45 +- contrib/gdb-7/gdb/tui/tui-disasm.c | 32 +- contrib/gdb-7/gdb/tui/tui-disasm.h | 2 +- contrib/gdb-7/gdb/tui/tui-file.c | 16 +- contrib/gdb-7/gdb/tui/tui-file.h | 2 +- contrib/gdb-7/gdb/tui/tui-hooks.c | 150 +- contrib/gdb-7/gdb/tui/tui-hooks.h | 2 +- contrib/gdb-7/gdb/tui/tui-interp.c | 116 +- contrib/gdb-7/gdb/tui/tui-io.c | 425 +- contrib/gdb-7/gdb/tui/tui-io.h | 5 +- contrib/gdb-7/gdb/tui/tui-layout.c | 357 +- contrib/gdb-7/gdb/tui/tui-layout.h | 5 +- contrib/gdb-7/gdb/tui/tui-out.c | 7 +- contrib/gdb-7/gdb/tui/tui-regs.c | 274 +- contrib/gdb-7/gdb/tui/tui-regs.h | 2 +- contrib/gdb-7/gdb/tui/tui-source.c | 46 +- contrib/gdb-7/gdb/tui/tui-source.h | 2 +- contrib/gdb-7/gdb/tui/tui-stack.c | 96 +- contrib/gdb-7/gdb/tui/tui-stack.h | 4 +- contrib/gdb-7/gdb/tui/tui-win.c | 266 +- contrib/gdb-7/gdb/tui/tui-win.h | 6 +- contrib/gdb-7/gdb/tui/tui-windata.c | 6 +- contrib/gdb-7/gdb/tui/tui-windata.h | 2 +- contrib/gdb-7/gdb/tui/tui-wingeneral.c | 4 +- contrib/gdb-7/gdb/tui/tui-wingeneral.h | 2 +- contrib/gdb-7/gdb/tui/tui-winsource.c | 73 +- contrib/gdb-7/gdb/tui/tui-winsource.h | 2 +- contrib/gdb-7/gdb/tui/tui.c | 153 +- contrib/gdb-7/gdb/tui/tui.h | 8 +- contrib/gdb-7/gdb/typeprint.c | 56 +- contrib/gdb-7/gdb/typeprint.h | 5 +- contrib/gdb-7/gdb/ui-file.c | 72 +- contrib/gdb-7/gdb/ui-file.h | 16 +- contrib/gdb-7/gdb/ui-out.c | 65 +- contrib/gdb-7/gdb/ui-out.h | 4 +- contrib/gdb-7/gdb/unwind_stop_reasons.def | 17 +- contrib/gdb-7/gdb/user-regs.c | 30 +- contrib/gdb-7/gdb/user-regs.h | 2 +- contrib/gdb-7/gdb/utils.c | 1398 +- contrib/gdb-7/gdb/utils.h | 129 +- contrib/gdb-7/gdb/valarith.c | 55 +- contrib/gdb-7/gdb/valops.c | 1031 +- contrib/gdb-7/gdb/valprint.c | 413 +- contrib/gdb-7/gdb/valprint.h | 53 +- contrib/gdb-7/gdb/value.c | 1237 +- contrib/gdb-7/gdb/value.h | 243 +- contrib/gdb-7/gdb/varobj-iter.h | 72 + contrib/gdb-7/gdb/varobj.c | 2495 +- contrib/gdb-7/gdb/varobj.h | 223 +- contrib/gdb-7/gdb/version.in | 2 +- contrib/gdb-7/gdb/x86-linux-nat.c | 405 + ...warf2-frame-tailcall.h => x86-linux-nat.h} | 34 +- contrib/gdb-7/gdb/x86-nat.c | 314 + contrib/gdb-7/gdb/x86-nat.h | 52 + contrib/gdb-7/gdb/xcoffsolib.h | 65 - contrib/gdb-7/gdb/xml-support.c | 71 +- contrib/gdb-7/gdb/xml-support.h | 9 +- contrib/gdb-7/gdb/xml-syscall.c | 175 +- contrib/gdb-7/gdb/xml-syscall.h | 13 +- contrib/gdb-7/gdb/xml-tdesc.c | 4 +- contrib/gdb-7/gdb/xml-tdesc.h | 2 +- contrib/gdb-7/include/ansidecl.h | 152 +- contrib/gdb-7/include/aout/aout64.h | 2 +- contrib/gdb-7/include/aout/ar.h | 2 +- contrib/gdb-7/include/aout/ranlib.h | 2 +- contrib/gdb-7/include/aout/stab.def | 3 +- contrib/gdb-7/include/aout/stab_gnu.h | 2 +- contrib/gdb-7/include/bfdlink.h | 54 +- contrib/gdb-7/include/cgen/basic-modes.h | 2 +- contrib/gdb-7/include/cgen/basic-ops.h | 12 +- contrib/gdb-7/include/cgen/bitset.h | 22 +- contrib/gdb-7/include/coff/ecoff.h | 2 +- contrib/gdb-7/include/coff/internal.h | 129 +- contrib/gdb-7/include/demangle.h | 28 +- contrib/gdb-7/include/dis-asm.h | 22 +- contrib/gdb-7/include/dwarf2.def | 27 +- contrib/gdb-7/include/dwarf2.h | 10 +- contrib/gdb-7/include/dyn-string.h | 3 +- contrib/gdb-7/include/elf/common.h | 42 +- contrib/gdb-7/include/elf/dwarf.h | 2 +- contrib/gdb-7/include/elf/external.h | 17 +- contrib/gdb-7/include/elf/ft32.h | 37 + contrib/gdb-7/include/elf/i386.h | 3 +- contrib/gdb-7/include/elf/internal.h | 18 +- contrib/gdb-7/include/elf/mips.h | 213 +- contrib/gdb-7/include/elf/nds32.h | 299 + contrib/gdb-7/include/elf/or1k.h | 65 + contrib/gdb-7/include/elf/reloc-macros.h | 2 +- contrib/gdb-7/include/elf/visium.h | 51 + contrib/gdb-7/include/elf/vxworks.h | 3 +- contrib/gdb-7/include/elf/x86-64.h | 10 +- contrib/gdb-7/include/filenames.h | 4 +- contrib/gdb-7/include/floatformat.h | 14 +- contrib/gdb-7/include/fnmatch.h | 2 +- contrib/gdb-7/include/fopen-bin.h | 2 +- contrib/gdb-7/include/fopen-same.h | 2 +- contrib/gdb-7/include/gcc-c-fe.def | 197 + contrib/gdb-7/include/gcc-c-interface.h | 220 + contrib/gdb-7/include/gcc-interface.h | 127 + contrib/gdb-7/include/gdb/fileio.h | 2 +- contrib/gdb-7/include/gdb/gdb-index.h | 4 +- contrib/gdb-7/include/gdb/section-scripts.h | 62 + contrib/gdb-7/include/gdb/signals.def | 16 +- contrib/gdb-7/include/gdb/signals.h | 2 +- contrib/gdb-7/include/gdb/sim-bfin.h | 2 +- .../gdb/sim-ft32.h} | 25 +- contrib/gdb-7/include/getopt.h | 3 +- contrib/gdb-7/include/hashtab.h | 3 +- contrib/gdb-7/include/leb128.h | 2 +- contrib/gdb-7/include/libiberty.h | 99 +- contrib/gdb-7/include/longlong.h | 1741 + contrib/gdb-7/include/lto-symtab.h | 2 +- contrib/gdb-7/include/mach-o/ChangeLog | 81 - contrib/gdb-7/include/mach-o/external.h | 21 +- contrib/gdb-7/include/mach-o/loader.h | 77 +- contrib/gdb-7/include/mach-o/reloc.h | 3 +- contrib/gdb-7/include/mach-o/unwind.h | 199 + contrib/gdb-7/include/mach-o/x86-64.h | 3 +- contrib/gdb-7/include/objalloc.h | 2 +- contrib/gdb-7/include/obstack.h | 4 +- contrib/gdb-7/include/opcode/ft32.h | 100 + contrib/gdb-7/include/opcode/i386.h | 5 +- contrib/gdb-7/include/opcode/msp430-decode.h | 138 + contrib/gdb-7/include/opcode/nds32.h | 831 + contrib/gdb-7/include/opcode/nios2r1.h | 474 + contrib/gdb-7/include/opcode/nios2r2.h | 1081 + contrib/gdb-7/include/opcode/visium.h | 337 + contrib/gdb-7/include/safe-ctype.h | 2 +- contrib/gdb-7/include/simple-object.h | 2 +- contrib/gdb-7/include/splay-tree.h | 3 +- contrib/gdb-7/include/symcat.h | 2 +- contrib/gdb-7/include/timeval-utils.h | 2 +- contrib/gdb-7/include/vtv-change-permission.h | 54 + contrib/gdb-7/include/xregex2.h | 3 +- contrib/gdb-7/libdecnumber/decNumberLocal.h | 7 +- contrib/gdb-7/libiberty/README | 72 - contrib/gdb-7/libiberty/concat.c | 61 +- contrib/gdb-7/libiberty/cp-demangle.c | 749 +- contrib/gdb-7/libiberty/cp-demangle.h | 5 + contrib/gdb-7/libiberty/cplus-dem.c | 25 +- contrib/gdb-7/libiberty/crc32.c | 181 + contrib/gdb-7/libiberty/d-demangle.c | 1601 + contrib/gdb-7/libiberty/filename_cmp.c | 29 + contrib/gdb-7/libiberty/floatformat.c | 17 +- contrib/gdb-7/libiberty/hashtab.c | 24 +- contrib/gdb-7/libiberty/make-temp-file.c | 4 +- contrib/gdb-7/libiberty/pex-common.c | 8 +- contrib/gdb-7/libiberty/pex-common.h | 2 +- contrib/gdb-7/libiberty/pex-unix.c | 7 +- contrib/gdb-7/libiberty/regex.c | 8 +- contrib/gdb-7/libiberty/simple-object-elf.c | 38 +- .../gdb-7/libiberty/simple-object-mach-o.c | 2 +- contrib/gdb-7/libiberty/simple-object.c | 50 +- contrib/gdb-7/libiberty/strtoll.c | 175 + contrib/gdb-7/libiberty/strtoull.c | 122 + contrib/gdb-7/libiberty/vprintf-support.c | 119 + .../vprintf-support.h} | 32 +- contrib/gdb-7/libiberty/xasprintf.c | 50 + contrib/gdb-7/libiberty/xstrndup.c | 60 + contrib/gdb-7/libiberty/xvasprintf.c | 61 + contrib/gdb-7/opcodes/dis-buf.c | 7 +- contrib/gdb-7/opcodes/dis-init.c | 2 +- contrib/gdb-7/opcodes/disassemble.c | 42 +- contrib/gdb-7/opcodes/ft32-dis.c | 177 + contrib/gdb-7/opcodes/ft32-opc.c | 88 + contrib/gdb-7/opcodes/i386-dis-evex.h | 3875 + contrib/gdb-7/opcodes/i386-dis.c | 5443 +- contrib/gdb-7/opcodes/i386-opc.c | 3 +- contrib/gdb-7/opcodes/i386-opc.h | 160 +- contrib/gdb-7/opcodes/i386-tbl.h | 127109 ++++++++++----- contrib/gdb-7/opcodes/mips-formats.h | 144 + contrib/gdb-7/opcodes/msp430-decode.c | 4345 + contrib/gdb-7/opcodes/msp430-decode.opc | 590 + contrib/gdb-7/opcodes/nds32-asm.c | 2283 + contrib/gdb-7/opcodes/nds32-asm.h | 297 + contrib/gdb-7/opcodes/nds32-dis.c | 1051 + contrib/gdb-7/opcodes/nds32-opc.h | 209 + contrib/gdb-7/opcodes/opintl.h | 2 +- contrib/gdb-7/opcodes/or1k-asm.c | 910 + contrib/gdb-7/opcodes/or1k-desc.c | 2110 + contrib/gdb-7/opcodes/or1k-desc.h | 682 + contrib/gdb-7/opcodes/or1k-dis.c | 561 + contrib/gdb-7/opcodes/or1k-ibld.c | 1050 + contrib/gdb-7/opcodes/or1k-opc.c | 1081 + contrib/gdb-7/opcodes/or1k-opc.h | 135 + contrib/gdb-7/opcodes/or1k-opinst.c | 590 + contrib/gdb-7/opcodes/sysdep.h | 16 +- contrib/gdb-7/opcodes/visium-dis.c | 834 + .../opcodes/{i386-opc.c => visium-opc.c} | 20 +- contrib/gdb-7/readline/complete.c | 13 + contrib/gdb-7/readline/doc/hsuser.texi | 473 - contrib/gdb-7/readline/doc/rluser.texi | 2037 - contrib/gdb-7/readline/readline.c | 4 + contrib/gdb-7/readline/search.c | 2 +- contrib/gdb-7/readline/util.c | 2 +- 1166 files changed, 323123 insertions(+), 173470 deletions(-) delete mode 100644 contrib/gdb-7/README delete mode 100644 contrib/gdb-7/bfd/README create mode 100644 contrib/gdb-7/bfd/coff-bfd.c create mode 100644 contrib/gdb-7/bfd/coff-bfd.h create mode 100644 contrib/gdb-7/bfd/cpu-ft32.c copy contrib/gdb-7/bfd/{cpu-l1om.c => cpu-iamcu.c} (69%) create mode 100644 contrib/gdb-7/bfd/cpu-nds32.c create mode 100644 contrib/gdb-7/bfd/cpu-or1k.c copy contrib/gdb-7/bfd/{init.c => cpu-visium.c} (51%) copy contrib/gdb-7/{gdb/python/lib/gdb/command/__init__.py => bfd/development.sh} (78%) create mode 100644 contrib/gdb-7/bfd/elf32-ft32.c create mode 100644 contrib/gdb-7/bfd/elf32-nds32.c create mode 100644 contrib/gdb-7/bfd/elf32-nds32.h copy contrib/gdb-7/{include/mach-o/reloc.h => bfd/elf32-nios2.h} (57%) create mode 100644 contrib/gdb-7/bfd/elf32-or1k.c copy contrib/gdb-7/bfd/{elf32.c => elf32-rx.h} (71%) create mode 100644 contrib/gdb-7/bfd/elf32-visium.c create mode 100644 contrib/gdb-7/bfd/elfnn-aarch64.c create mode 100644 contrib/gdb-7/bfd/elfxx-aarch64.c create mode 100644 contrib/gdb-7/bfd/elfxx-aarch64.h create mode 100644 contrib/gdb-7/bfd/version.m4 delete mode 100644 contrib/gdb-7/gdb/README delete mode 100644 contrib/gdb-7/gdb/ada-varobj.h create mode 100644 contrib/gdb-7/gdb/break-catch-syscall.c create mode 100644 contrib/gdb-7/gdb/break-catch-throw.c create mode 100644 contrib/gdb-7/gdb/build-id.c create mode 100644 contrib/gdb-7/gdb/build-id.h create mode 100644 contrib/gdb-7/gdb/build-with-cxx.m4 create mode 100644 contrib/gdb-7/gdb/c-varobj.c copy contrib/gdb-7/gdb/{gdb_vfork.h => common/break-common.h} (62%) create mode 100644 contrib/gdb-7/gdb/common/btrace-common.c rename contrib/gdb-7/gdb/{ => common}/cleanups.c (94%) rename contrib/gdb-7/gdb/{ => common}/cleanups.h (97%) copy contrib/gdb-7/gdb/{ppc-ravenscar-thread.h => common/common-debug.c} (66%) create mode 100644 contrib/gdb-7/gdb/common/common-debug.h create mode 100644 contrib/gdb-7/gdb/common/common-defs.h create mode 100644 contrib/gdb-7/gdb/common/common-exceptions.c create mode 100644 contrib/gdb-7/gdb/common/common-exceptions.h copy contrib/gdb-7/gdb/common/{gdb_vecs.h => common-regcache.h} (52%) create mode 100644 contrib/gdb-7/gdb/common/common-types.h copy contrib/gdb-7/gdb/{python/lib/gdb/command/__init__.py => common/common.host} (54%) create mode 100644 contrib/gdb-7/gdb/common/common.m4 create mode 100755 contrib/gdb-7/gdb/common/create-version.sh create mode 100644 contrib/gdb-7/gdb/common/errors.c create mode 100644 contrib/gdb-7/gdb/common/errors.h create mode 100644 contrib/gdb-7/gdb/common/fileio.c create mode 100644 contrib/gdb-7/gdb/common/fileio.h create mode 100644 contrib/gdb-7/gdb/common/filestuff.c create mode 100644 contrib/gdb-7/gdb/common/filestuff.h delete mode 100644 contrib/gdb-7/gdb/common/gdb_dirent.h copy contrib/gdb-7/gdb/{gdb_regex.h => common/gdb_setjmp.h} (60%) delete mode 100644 contrib/gdb-7/gdb/common/gdb_stat.h delete mode 100644 contrib/gdb-7/gdb/common/gdb_string.h delete mode 100644 contrib/gdb-7/gdb/common/i386-xstate.h delete mode 100644 contrib/gdb-7/gdb/common/linux-btrace.c delete mode 100644 contrib/gdb-7/gdb/common/linux-btrace.h delete mode 100644 contrib/gdb-7/gdb/common/linux-procfs.c delete mode 100644 contrib/gdb-7/gdb/common/linux-procfs.h delete mode 100644 contrib/gdb-7/gdb/common/linux-ptrace.c delete mode 100644 contrib/gdb-7/gdb/common/linux-ptrace.h create mode 100644 contrib/gdb-7/gdb/common/mingw-strerror.c copy contrib/gdb-7/gdb/{mi/mi-cmd-info.c => common/posix-strerror.c} (60%) create mode 100644 contrib/gdb-7/gdb/common/print-utils.c create mode 100644 contrib/gdb-7/gdb/common/print-utils.h create mode 100644 contrib/gdb-7/gdb/common/rsp-low.c create mode 100644 contrib/gdb-7/gdb/common/rsp-low.h create mode 100644 contrib/gdb-7/gdb/common/symbol.h rename contrib/gdb-7/gdb/{ => common}/version.h (94%) create mode 100644 contrib/gdb-7/gdb/common/x86-xstate.h create mode 100644 contrib/gdb-7/gdb/compile/compile-c-support.c create mode 100644 contrib/gdb-7/gdb/compile/compile-c-symbols.c create mode 100644 contrib/gdb-7/gdb/compile/compile-c-types.c create mode 100644 contrib/gdb-7/gdb/compile/compile-internal.h create mode 100644 contrib/gdb-7/gdb/compile/compile-loc2c.c create mode 100644 contrib/gdb-7/gdb/compile/compile-object-load.c create mode 100644 contrib/gdb-7/gdb/compile/compile-object-load.h create mode 100644 contrib/gdb-7/gdb/compile/compile-object-run.c copy contrib/gdb-7/gdb/{sparc-ravenscar-thread.h => compile/compile-object-run.h} (67%) create mode 100644 contrib/gdb-7/gdb/compile/compile.c create mode 100644 contrib/gdb-7/gdb/compile/compile.h delete mode 100644 contrib/gdb-7/gdb/configure.ac delete mode 100644 contrib/gdb-7/gdb/configure.host delete mode 100644 contrib/gdb-7/gdb/configure.tgt create mode 100644 contrib/gdb-7/gdb/cris-linux-tdep.c copy contrib/gdb-7/gdb/{ravenscar-thread.h => cris-tdep.h} (61%) create mode 100644 contrib/gdb-7/gdb/ctf.c copy contrib/gdb-7/gdb/{gdb_vfork.h => ctf.h} (77%) create mode 100644 contrib/gdb-7/gdb/d-exp.c create mode 100644 contrib/gdb-7/gdb/d-exp.y copy contrib/gdb-7/gdb/{gdb_vfork.h => debug.c} (74%) create mode 100644 contrib/gdb-7/gdb/doc/Doxyfile-base.in create mode 100644 contrib/gdb-7/gdb/doc/Doxyfile-gdb-api.in rename contrib/gdb-7/gdb/{python/lib/gdb/command/__init__.py => doc/Doxyfile-gdb-xref.in} (53%) create mode 100644 contrib/gdb-7/gdb/doc/Doxyfile-gdbserver.in delete mode 100644 contrib/gdb-7/gdb/doc/LRS delete mode 100644 contrib/gdb-7/gdb/doc/a4rc.sed delete mode 100644 contrib/gdb-7/gdb/doc/agentexpr.texi delete mode 100644 contrib/gdb-7/gdb/doc/all-cfg.texi delete mode 100644 contrib/gdb-7/gdb/doc/annotate.texinfo create mode 100644 contrib/gdb-7/gdb/doc/doxy-index.in create mode 100755 contrib/gdb-7/gdb/doc/filter-for-doxygen create mode 100644 contrib/gdb-7/gdb/doc/filter-params.pl create mode 100644 contrib/gdb-7/gdb/doc/gcore.1 create mode 100644 contrib/gdb-7/gdb/doc/gdb.1 delete mode 100644 contrib/gdb-7/gdb/doc/gdb.texinfo create mode 100644 contrib/gdb-7/gdb/doc/gdbinit.5 delete mode 100644 contrib/gdb-7/gdb/doc/gdbint.texinfo create mode 100644 contrib/gdb-7/gdb/doc/gdbserver.1 delete mode 100644 contrib/gdb-7/gdb/doc/gpl.texi delete mode 100644 contrib/gdb-7/gdb/doc/stabs.texinfo delete mode 100644 contrib/gdb-7/gdb/doc/stack_frame.txt create mode 100644 contrib/gdb-7/gdb/dtrace-probe.c create mode 100644 contrib/gdb-7/gdb/extension-priv.h create mode 100644 contrib/gdb-7/gdb/extension.c create mode 100644 contrib/gdb-7/gdb/extension.h create mode 100644 contrib/gdb-7/gdb/fbsd-tdep.c copy contrib/gdb-7/gdb/{solib-target.h => fbsd-tdep.h} (71%) create mode 100644 contrib/gdb-7/gdb/features/btrace-conf.dtd mode change 100644 => 100755 contrib/gdb-7/gdb/features/feature_to_c.sh create mode 100644 contrib/gdb-7/gdb/features/i386/32bit-avx512.xml create mode 100644 contrib/gdb-7/gdb/features/i386/32bit-mpx.xml create mode 100644 contrib/gdb-7/gdb/features/i386/64bit-avx512.xml create mode 100644 contrib/gdb-7/gdb/features/i386/64bit-mpx.xml create mode 100644 contrib/gdb-7/gdb/features/i386/amd64-avx512-linux.c copy contrib/gdb-7/gdb/features/i386/{amd64-avx-linux.xml => amd64-avx512-linux.xml} (70%) create mode 100644 contrib/gdb-7/gdb/features/i386/amd64-avx512.c copy contrib/gdb-7/gdb/features/i386/{amd64-avx.xml => amd64-avx512.xml} (72%) create mode 100644 contrib/gdb-7/gdb/features/i386/amd64-mpx-linux.c copy contrib/gdb-7/gdb/features/i386/{amd64-avx-linux.xml => amd64-mpx-linux.xml} (75%) create mode 100644 contrib/gdb-7/gdb/features/i386/amd64-mpx.c copy contrib/gdb-7/gdb/features/i386/{amd64-avx.xml => amd64-mpx.xml} (78%) create mode 100644 contrib/gdb-7/gdb/features/i386/i386-avx512-linux.c copy contrib/gdb-7/gdb/features/i386/{i386-avx-linux.xml => i386-avx512-linux.xml} (70%) create mode 100644 contrib/gdb-7/gdb/features/i386/i386-avx512.c copy contrib/gdb-7/gdb/features/i386/{i386-avx.xml => i386-avx512.xml} (72%) create mode 100644 contrib/gdb-7/gdb/features/i386/i386-mpx-linux.c copy contrib/gdb-7/gdb/features/i386/{i386-avx-linux.xml => i386-mpx-linux.xml} (75%) create mode 100644 contrib/gdb-7/gdb/features/i386/i386-mpx.c copy contrib/gdb-7/gdb/features/i386/{i386-avx.xml => i386-mpx.xml} (78%) create mode 100644 contrib/gdb-7/gdb/features/i386/x32-avx512-linux.c copy contrib/gdb-7/gdb/features/i386/{x32-avx-linux.xml => x32-avx512-linux.xml} (70%) create mode 100644 contrib/gdb-7/gdb/features/i386/x32-avx512.c copy contrib/gdb-7/gdb/features/i386/{x32-avx.xml => x32-avx512.xml} (72%) create mode 100644 contrib/gdb-7/gdb/features/library-list-aix.dtd create mode 100644 contrib/gdb-7/gdb/features/microblaze-core.xml copy contrib/gdb-7/gdb/features/{i386/32bit-linux.xml => microblaze-stack-protect.xml} (59%) create mode 100644 contrib/gdb-7/gdb/features/microblaze-with-stack-protect.c copy contrib/gdb-7/gdb/features/{i386/i386-mmx.xml => microblaze-with-stack-protect.xml} (63%) create mode 100644 contrib/gdb-7/gdb/features/microblaze.c copy contrib/gdb-7/gdb/features/{i386/i386-mmx.xml => microblaze.xml} (63%) create mode 100644 contrib/gdb-7/gdb/features/nios2-cpu.xml create mode 100644 contrib/gdb-7/gdb/features/nios2-linux.c copy contrib/gdb-7/gdb/features/{i386/i386-mmx.xml => nios2-linux.xml} (63%) create mode 100644 contrib/gdb-7/gdb/features/nios2.c copy contrib/gdb-7/gdb/features/{i386/i386-mmx.xml => nios2.xml} (63%) create mode 100644 contrib/gdb-7/gdb/features/s390-tdb.xml create mode 100644 contrib/gdb-7/gdb/features/s390-te-linux64.c create mode 100644 contrib/gdb-7/gdb/features/s390-te-linux64.xml create mode 100644 contrib/gdb-7/gdb/features/s390-tevx-linux64.c create mode 100644 contrib/gdb-7/gdb/features/s390-tevx-linux64.xml create mode 100644 contrib/gdb-7/gdb/features/s390-vx-linux64.c create mode 100644 contrib/gdb-7/gdb/features/s390-vx-linux64.xml create mode 100644 contrib/gdb-7/gdb/features/s390-vx.xml create mode 100644 contrib/gdb-7/gdb/features/s390x-te-linux64.c create mode 100644 contrib/gdb-7/gdb/features/s390x-te-linux64.xml create mode 100644 contrib/gdb-7/gdb/features/s390x-tevx-linux64.c create mode 100644 contrib/gdb-7/gdb/features/s390x-tevx-linux64.xml create mode 100644 contrib/gdb-7/gdb/features/s390x-vx-linux64.c create mode 100644 contrib/gdb-7/gdb/features/s390x-vx-linux64.xml create mode 100644 contrib/gdb-7/gdb/ft32-tdep.c copy contrib/gdb-7/gdb/{solib-target.h => ft32-tdep.h} (72%) create mode 100755 contrib/gdb-7/gdb/gcore create mode 100644 contrib/gdb-7/gdb/gcore.in delete mode 100644 contrib/gdb-7/gdb/gdb.1 create mode 100644 contrib/gdb-7/gdb/gnulib/import/basename-lgpl.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/canonicalize-lgpl.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/dirent.in.h copy contrib/gdb-7/gdb/{solib-target.h => gnulib/import/dirfd.c} (59%) create mode 100644 contrib/gdb-7/gdb/gnulib/import/dirname-lgpl.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/dirname.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/dosname.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/errno.in.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/extra/snippet/_Noreturn.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/float+.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/float.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/float.in.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/fpucw.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/frexp.c copy contrib/gdb-7/gdb/{ppc-ravenscar-thread.h => gnulib/import/frexpl.c} (59%) create mode 100644 contrib/gdb-7/gdb/gnulib/import/isnan.c copy contrib/gdb-7/gdb/{gdb_regex.h => gnulib/import/isnand-nolibm.h} (51%) copy contrib/gdb-7/gdb/{gdb_vfork.h => gnulib/import/isnand.c} (65%) create mode 100644 contrib/gdb-7/gdb/gnulib/import/isnanl-nolibm.h copy contrib/gdb-7/gdb/{gdb_vfork.h => gnulib/import/isnanl.c} (65%) copy contrib/gdb-7/gdb/{gcore.h => gnulib/import/itold.c} (56%) create mode 100644 contrib/gdb-7/gdb/gnulib/import/lstat.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/canonicalize.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/dirent_h.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/dirfd.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/dirname.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/double-slash-root.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/eealloc.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/errno_h.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/exponentd.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/exponentl.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/float_h.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/fpieee.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/frexp.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/frexpl.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/isnand.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/isnanl.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/largefile.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/lstat.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/malloc.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/malloca.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/math_h.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/nocrash.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/off_t.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/pathmax.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/readlink.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/rename.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/rmdir.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/ssize_t.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/stat.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/stdio_h.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/stdlib_h.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/strstr.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/strtok_r.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/sys_stat_h.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/sys_types_h.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/time_h.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/m4/unistd_h.m4 create mode 100644 contrib/gdb-7/gdb/gnulib/import/malloc.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/malloca.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/malloca.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/malloca.valgrind create mode 100644 contrib/gdb-7/gdb/gnulib/import/math.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/math.in.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/pathmax.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/readlink.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/rename.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/rmdir.c copy contrib/gdb-7/gdb/{bfd-target.h => gnulib/import/same-inode.h} (51%) create mode 100644 contrib/gdb-7/gdb/gnulib/import/stat.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/stdio.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/stdio.in.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/stdlib.in.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/stripslash.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/strstr.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/strtok_r.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/sys_stat.in.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/sys_types.in.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/time.in.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/unistd.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/unistd.in.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/verify.h create mode 100644 contrib/gdb-7/gdb/guile/guile-internal.h create mode 100644 contrib/gdb-7/gdb/guile/guile.c copy contrib/gdb-7/gdb/{tui/tui-command.h => guile/guile.h} (70%) create mode 100644 contrib/gdb-7/gdb/guile/lib/gdb.scm create mode 100644 contrib/gdb-7/gdb/guile/lib/gdb/boot.scm create mode 100644 contrib/gdb-7/gdb/guile/lib/gdb/experimental.scm create mode 100644 contrib/gdb-7/gdb/guile/lib/gdb/init.scm create mode 100644 contrib/gdb-7/gdb/guile/lib/gdb/iterator.scm create mode 100644 contrib/gdb-7/gdb/guile/lib/gdb/printing.scm create mode 100644 contrib/gdb-7/gdb/guile/lib/gdb/support.scm create mode 100644 contrib/gdb-7/gdb/guile/lib/gdb/types.scm create mode 100644 contrib/gdb-7/gdb/guile/scm-arch.c create mode 100644 contrib/gdb-7/gdb/guile/scm-auto-load.c create mode 100644 contrib/gdb-7/gdb/guile/scm-block.c create mode 100644 contrib/gdb-7/gdb/guile/scm-breakpoint.c create mode 100644 contrib/gdb-7/gdb/guile/scm-cmd.c create mode 100644 contrib/gdb-7/gdb/guile/scm-disasm.c create mode 100644 contrib/gdb-7/gdb/guile/scm-exception.c create mode 100644 contrib/gdb-7/gdb/guile/scm-frame.c create mode 100644 contrib/gdb-7/gdb/guile/scm-gsmob.c create mode 100644 contrib/gdb-7/gdb/guile/scm-iterator.c create mode 100644 contrib/gdb-7/gdb/guile/scm-lazy-string.c create mode 100644 contrib/gdb-7/gdb/guile/scm-math.c create mode 100644 contrib/gdb-7/gdb/guile/scm-objfile.c create mode 100644 contrib/gdb-7/gdb/guile/scm-param.c create mode 100644 contrib/gdb-7/gdb/guile/scm-ports.c create mode 100644 contrib/gdb-7/gdb/guile/scm-pretty-print.c create mode 100644 contrib/gdb-7/gdb/guile/scm-progspace.c create mode 100644 contrib/gdb-7/gdb/guile/scm-safe-call.c create mode 100644 contrib/gdb-7/gdb/guile/scm-string.c create mode 100644 contrib/gdb-7/gdb/guile/scm-symbol.c create mode 100644 contrib/gdb-7/gdb/guile/scm-symtab.c create mode 100644 contrib/gdb-7/gdb/guile/scm-type.c create mode 100644 contrib/gdb-7/gdb/guile/scm-utils.c create mode 100644 contrib/gdb-7/gdb/guile/scm-value.c create mode 100644 contrib/gdb-7/gdb/hppaobsd-nat.c copy contrib/gdb-7/gdb/{sparc-ravenscar-thread.h => i386-linux-nat.h} (73%) delete mode 100644 contrib/gdb-7/gdb/i386-nat.c delete mode 100644 contrib/gdb-7/gdb/i386-nat.h copy contrib/gdb-7/gdb/{gcore.h => i386fbsd-tdep.h} (59%) create mode 100644 contrib/gdb-7/gdb/infrun.h create mode 100644 contrib/gdb-7/gdb/jv-varobj.c create mode 100644 contrib/gdb-7/gdb/libiberty.m4 create mode 100644 contrib/gdb-7/gdb/libmcheck.m4 copy contrib/gdb-7/gdb/{gdb_usleep.h => maint.h} (62%) create mode 100755 contrib/gdb-7/gdb/make-target-delegates create mode 100644 contrib/gdb-7/gdb/mips-sde-tdep.c create mode 100644 contrib/gdb-7/gdb/msp430-tdep.c create mode 100644 contrib/gdb-7/gdb/nat/gdb_thread_db.h rename contrib/gdb-7/gdb/{common/gdb_thread_db.h => nat/glibc_thread_db.h} (87%) create mode 100644 contrib/gdb-7/gdb/nat/linux-btrace.c create mode 100644 contrib/gdb-7/gdb/nat/linux-btrace.h create mode 100644 contrib/gdb-7/gdb/nat/linux-namespaces.c create mode 100644 contrib/gdb-7/gdb/nat/linux-namespaces.h create mode 100644 contrib/gdb-7/gdb/nat/linux-nat.h rename contrib/gdb-7/gdb/{common => nat}/linux-osdata.c (89%) rename contrib/gdb-7/gdb/{common => nat}/linux-osdata.h (89%) create mode 100644 contrib/gdb-7/gdb/nat/linux-personality.c rename contrib/gdb-7/gdb/{cli/cli-dump.h => nat/linux-personality.h} (54%) create mode 100644 contrib/gdb-7/gdb/nat/linux-procfs.c create mode 100644 contrib/gdb-7/gdb/nat/linux-procfs.h create mode 100644 contrib/gdb-7/gdb/nat/linux-ptrace.c create mode 100644 contrib/gdb-7/gdb/nat/linux-ptrace.h create mode 100644 contrib/gdb-7/gdb/nat/linux-waitpid.c copy contrib/gdb-7/gdb/{bfd-target.h => nat/linux-waitpid.h} (57%) create mode 100644 contrib/gdb-7/gdb/nat/mips-linux-watch.c create mode 100644 contrib/gdb-7/gdb/nat/mips-linux-watch.h create mode 100644 contrib/gdb-7/gdb/nat/ppc-linux.c create mode 100644 contrib/gdb-7/gdb/nat/ppc-linux.h create mode 100644 contrib/gdb-7/gdb/nat/x86-cpuid.h create mode 100644 contrib/gdb-7/gdb/nat/x86-dregs.c create mode 100644 contrib/gdb-7/gdb/nat/x86-dregs.h create mode 100644 contrib/gdb-7/gdb/nat/x86-gcc-cpuid.h create mode 100644 contrib/gdb-7/gdb/nat/x86-linux-dregs.c create mode 100644 contrib/gdb-7/gdb/nat/x86-linux-dregs.h create mode 100644 contrib/gdb-7/gdb/nat/x86-linux.c create mode 100644 contrib/gdb-7/gdb/nat/x86-linux.h create mode 100644 contrib/gdb-7/gdb/nios2-linux-tdep.c create mode 100644 contrib/gdb-7/gdb/nios2-tdep.c create mode 100644 contrib/gdb-7/gdb/nios2-tdep.h create mode 100644 contrib/gdb-7/gdb/obsd-nat.c copy contrib/gdb-7/gdb/{gdb_vfork.h => obsd-nat.h} (76%) delete mode 100644 contrib/gdb-7/gdb/python/lib/gdb/__init__.py delete mode 100644 contrib/gdb-7/gdb/python/lib/gdb/command/explore.py delete mode 100644 contrib/gdb-7/gdb/python/lib/gdb/command/pretty_printers.py delete mode 100644 contrib/gdb-7/gdb/python/lib/gdb/command/prompt.py delete mode 100644 contrib/gdb-7/gdb/python/lib/gdb/command/type_printers.py delete mode 100644 contrib/gdb-7/gdb/python/lib/gdb/function/strfns.py delete mode 100644 contrib/gdb-7/gdb/python/lib/gdb/printing.py delete mode 100644 contrib/gdb-7/gdb/python/lib/gdb/prompt.py delete mode 100644 contrib/gdb-7/gdb/python/lib/gdb/types.py delete mode 100644 contrib/gdb-7/gdb/python/py-arch.c delete mode 100644 contrib/gdb-7/gdb/python/py-auto-load.c delete mode 100644 contrib/gdb-7/gdb/python/py-block.c delete mode 100644 contrib/gdb-7/gdb/python/py-bpevent.c delete mode 100644 contrib/gdb-7/gdb/python/py-breakpoint.c delete mode 100644 contrib/gdb-7/gdb/python/py-cmd.c delete mode 100644 contrib/gdb-7/gdb/python/py-continueevent.c delete mode 100644 contrib/gdb-7/gdb/python/py-event.c delete mode 100644 contrib/gdb-7/gdb/python/py-event.h delete mode 100644 contrib/gdb-7/gdb/python/py-events.h delete mode 100644 contrib/gdb-7/gdb/python/py-evtregistry.c delete mode 100644 contrib/gdb-7/gdb/python/py-evts.c delete mode 100644 contrib/gdb-7/gdb/python/py-exitedevent.c delete mode 100644 contrib/gdb-7/gdb/python/py-finishbreakpoint.c delete mode 100644 contrib/gdb-7/gdb/python/py-frame.c delete mode 100644 contrib/gdb-7/gdb/python/py-function.c delete mode 100644 contrib/gdb-7/gdb/python/py-gdb-readline.c delete mode 100644 contrib/gdb-7/gdb/python/py-inferior.c delete mode 100644 contrib/gdb-7/gdb/python/py-infthread.c delete mode 100644 contrib/gdb-7/gdb/python/py-lazy-string.c delete mode 100644 contrib/gdb-7/gdb/python/py-newobjfileevent.c delete mode 100644 contrib/gdb-7/gdb/python/py-objfile.c delete mode 100644 contrib/gdb-7/gdb/python/py-param.c delete mode 100644 contrib/gdb-7/gdb/python/py-prettyprint.c delete mode 100644 contrib/gdb-7/gdb/python/py-progspace.c delete mode 100644 contrib/gdb-7/gdb/python/py-signalevent.c delete mode 100644 contrib/gdb-7/gdb/python/py-stopevent.c delete mode 100644 contrib/gdb-7/gdb/python/py-stopevent.h delete mode 100644 contrib/gdb-7/gdb/python/py-symbol.c delete mode 100644 contrib/gdb-7/gdb/python/py-symtab.c delete mode 100644 contrib/gdb-7/gdb/python/py-threadevent.c delete mode 100644 contrib/gdb-7/gdb/python/py-type.c delete mode 100644 contrib/gdb-7/gdb/python/py-utils.c delete mode 100644 contrib/gdb-7/gdb/python/py-value.c delete mode 100644 contrib/gdb-7/gdb/python/python-config.py delete mode 100644 contrib/gdb-7/gdb/python/python-internal.h delete mode 100644 contrib/gdb-7/gdb/python/python.c delete mode 100644 contrib/gdb-7/gdb/python/python.h create mode 100644 contrib/gdb-7/gdb/regformats/i386/amd64-avx512-linux.dat create mode 100644 contrib/gdb-7/gdb/regformats/i386/amd64-avx512.dat copy contrib/gdb-7/gdb/regformats/i386/{x32-avx-linux.dat => amd64-mpx-linux.dat} (73%) copy contrib/gdb-7/gdb/regformats/i386/{x32-avx-linux.dat => amd64-mpx.dat} (74%) copy contrib/gdb-7/gdb/regformats/i386/{i386-avx-linux.dat => i386-avx512-linux.dat} (53%) copy contrib/gdb-7/gdb/regformats/i386/{i386-avx-linux.dat => i386-avx512.dat} (54%) copy contrib/gdb-7/gdb/regformats/i386/{i386-avx-linux.dat => i386-mpx-linux.dat} (65%) copy contrib/gdb-7/gdb/regformats/i386/{i386-avx-linux.dat => i386-mpx.dat} (66%) create mode 100644 contrib/gdb-7/gdb/regformats/i386/x32-avx512-linux.dat create mode 100644 contrib/gdb-7/gdb/regformats/i386/x32-avx512.dat create mode 100644 contrib/gdb-7/gdb/regformats/microblaze-with-stack-protect.dat create mode 100644 contrib/gdb-7/gdb/regformats/nios2-linux.dat create mode 100644 contrib/gdb-7/gdb/regformats/s390-te-linux64.dat create mode 100644 contrib/gdb-7/gdb/regformats/s390-tevx-linux64.dat create mode 100644 contrib/gdb-7/gdb/regformats/s390-vx-linux64.dat create mode 100644 contrib/gdb-7/gdb/regformats/s390x-te-linux64.dat create mode 100644 contrib/gdb-7/gdb/regformats/s390x-tevx-linux64.dat create mode 100644 contrib/gdb-7/gdb/regformats/s390x-vx-linux64.dat delete mode 100644 contrib/gdb-7/gdb/regset.c copy contrib/gdb-7/gdb/{gcore.h => rs6000-aix-tdep.h} (66%) create mode 100644 contrib/gdb-7/gdb/s390-linux-nat.c create mode 100644 contrib/gdb-7/gdb/s390-linux-tdep.c create mode 100644 contrib/gdb-7/gdb/s390-linux-tdep.h create mode 100644 contrib/gdb-7/gdb/solib-aix.c copy contrib/gdb-7/gdb/{gdb_vfork.h => solib-aix.h} (75%) delete mode 100644 contrib/gdb-7/gdb/somread.c create mode 100644 contrib/gdb-7/gdb/sparc64obsd-nat.c create mode 100644 contrib/gdb-7/gdb/stub-termcap.c delete mode 100644 contrib/gdb-7/gdb/stubs/ChangeLog create mode 100644 contrib/gdb-7/gdb/symfile-debug.c create mode 100644 contrib/gdb-7/gdb/syscalls/aarch64-linux.xml create mode 100644 contrib/gdb-7/gdb/syscalls/arm-linux.py create mode 100644 contrib/gdb-7/gdb/syscalls/arm-linux.xml create mode 100644 contrib/gdb-7/gdb/syscalls/s390-linux.xml create mode 100644 contrib/gdb-7/gdb/syscalls/s390x-linux.xml create mode 100644 contrib/gdb-7/gdb/system-gdbinit/elinos.py rename contrib/gdb-7/gdb/{python/lib/gdb/function/__init__.py => system-gdbinit/wrs-linux.py} (63%) create mode 100644 contrib/gdb-7/gdb/target-dcache.c copy contrib/gdb-7/gdb/{gdb_usleep.h => target-dcache.h} (62%) create mode 100644 contrib/gdb-7/gdb/target-debug.h create mode 100644 contrib/gdb-7/gdb/target-delegates.c copy contrib/gdb-7/gdb/{tui/tui-stack.h => target/resume.h} (64%) create mode 100644 contrib/gdb-7/gdb/target/target.h copy contrib/gdb-7/gdb/{mi/mi-cmd-break.h => target/wait.h} (64%) create mode 100644 contrib/gdb-7/gdb/target/waitstatus.c create mode 100644 contrib/gdb-7/gdb/target/waitstatus.h create mode 100644 contrib/gdb-7/gdb/tracefile-tfile.c create mode 100644 contrib/gdb-7/gdb/tracefile.c create mode 100644 contrib/gdb-7/gdb/tracefile.h create mode 100644 contrib/gdb-7/gdb/transform.m4 create mode 100644 contrib/gdb-7/gdb/varobj-iter.h create mode 100644 contrib/gdb-7/gdb/x86-linux-nat.c copy contrib/gdb-7/gdb/{dwarf2-frame-tailcall.h => x86-linux-nat.h} (51%) create mode 100644 contrib/gdb-7/gdb/x86-nat.c create mode 100644 contrib/gdb-7/gdb/x86-nat.h delete mode 100644 contrib/gdb-7/gdb/xcoffsolib.h create mode 100644 contrib/gdb-7/include/elf/ft32.h create mode 100644 contrib/gdb-7/include/elf/nds32.h create mode 100644 contrib/gdb-7/include/elf/or1k.h create mode 100644 contrib/gdb-7/include/elf/visium.h create mode 100644 contrib/gdb-7/include/gcc-c-fe.def create mode 100644 contrib/gdb-7/include/gcc-c-interface.h create mode 100644 contrib/gdb-7/include/gcc-interface.h create mode 100644 contrib/gdb-7/include/gdb/section-scripts.h copy contrib/gdb-7/{gdb/ravenscar-thread.h => include/gdb/sim-ft32.h} (54%) create mode 100644 contrib/gdb-7/include/longlong.h delete mode 100644 contrib/gdb-7/include/mach-o/ChangeLog create mode 100644 contrib/gdb-7/include/mach-o/unwind.h create mode 100644 contrib/gdb-7/include/opcode/ft32.h create mode 100644 contrib/gdb-7/include/opcode/msp430-decode.h create mode 100644 contrib/gdb-7/include/opcode/nds32.h create mode 100644 contrib/gdb-7/include/opcode/nios2r1.h create mode 100644 contrib/gdb-7/include/opcode/nios2r2.h create mode 100644 contrib/gdb-7/include/opcode/visium.h create mode 100644 contrib/gdb-7/include/vtv-change-permission.h delete mode 100644 contrib/gdb-7/libiberty/README create mode 100644 contrib/gdb-7/libiberty/crc32.c create mode 100644 contrib/gdb-7/libiberty/d-demangle.c create mode 100644 contrib/gdb-7/libiberty/strtoll.c create mode 100644 contrib/gdb-7/libiberty/strtoull.c create mode 100644 contrib/gdb-7/libiberty/vprintf-support.c copy contrib/gdb-7/{include/timeval-utils.h => libiberty/vprintf-support.h} (51%) create mode 100644 contrib/gdb-7/libiberty/xasprintf.c create mode 100644 contrib/gdb-7/libiberty/xstrndup.c create mode 100644 contrib/gdb-7/libiberty/xvasprintf.c create mode 100644 contrib/gdb-7/opcodes/ft32-dis.c create mode 100644 contrib/gdb-7/opcodes/ft32-opc.c create mode 100644 contrib/gdb-7/opcodes/i386-dis-evex.h create mode 100644 contrib/gdb-7/opcodes/mips-formats.h create mode 100644 contrib/gdb-7/opcodes/msp430-decode.c create mode 100644 contrib/gdb-7/opcodes/msp430-decode.opc create mode 100644 contrib/gdb-7/opcodes/nds32-asm.c create mode 100644 contrib/gdb-7/opcodes/nds32-asm.h create mode 100644 contrib/gdb-7/opcodes/nds32-dis.c create mode 100644 contrib/gdb-7/opcodes/nds32-opc.h create mode 100644 contrib/gdb-7/opcodes/or1k-asm.c create mode 100644 contrib/gdb-7/opcodes/or1k-desc.c create mode 100644 contrib/gdb-7/opcodes/or1k-desc.h create mode 100644 contrib/gdb-7/opcodes/or1k-dis.c create mode 100644 contrib/gdb-7/opcodes/or1k-ibld.c create mode 100644 contrib/gdb-7/opcodes/or1k-opc.c create mode 100644 contrib/gdb-7/opcodes/or1k-opc.h create mode 100644 contrib/gdb-7/opcodes/or1k-opinst.c create mode 100644 contrib/gdb-7/opcodes/visium-dis.c copy contrib/gdb-7/opcodes/{i386-opc.c => visium-opc.c} (64%) delete mode 100644 contrib/gdb-7/readline/doc/hsuser.texi delete mode 100644 contrib/gdb-7/readline/doc/rluser.texi diff --git a/contrib/gdb-7/README b/contrib/gdb-7/README deleted file mode 100644 index eb0e436d86..0000000000 --- a/contrib/gdb-7/README +++ /dev/null @@ -1,47 +0,0 @@ - README for GNU development tools - -This directory contains various GNU compilers, assemblers, linkers, -debuggers, etc., plus their support routines, definitions, and documentation. - -If you are receiving this as part of a GDB release, see the file gdb/README. -If with a binutils release, see binutils/README; if with a libg++ release, -see libg++/README, etc. That'll give you info about this -package -- supported targets, how to use it, how to report bugs, etc. - -It is now possible to automatically configure and build a variety of -tools with one command. To build all of the tools contained herein, -run the ``configure'' script here, e.g.: - - ./configure - make - -To install them (by default in /usr/local/bin, /usr/local/lib, etc), -then do: - make install - -(If the configure script can't determine your type of computer, give it -the name as an argument, for instance ``./configure sun4''. You can -use the script ``config.sub'' to test whether a name is recognized; if -it is, config.sub translates it to a triplet specifying CPU, vendor, -and OS.) - -If you have more than one compiler on your system, it is often best to -explicitly set CC in the environment before running configure, and to -also set CC when running make. For example (assuming sh/bash/ksh): - - CC=gcc ./configure - make - -A similar example using csh: - - setenv CC gcc - ./configure - make - -Much of the code and documentation enclosed is copyright by -the Free Software Foundation, Inc. See the file COPYING or -COPYING.LIB in the various directories, for a description of the -GNU General Public License terms under which you can copy the files. - -REPORTING BUGS: Again, see gdb/README, binutils/README, etc., for info -on where and how to report problems. diff --git a/contrib/gdb-7/bfd/README b/contrib/gdb-7/bfd/README deleted file mode 100644 index 5ecfd298be..0000000000 --- a/contrib/gdb-7/bfd/README +++ /dev/null @@ -1,55 +0,0 @@ -BFD is an object file library. It permits applications to use the -same routines to process object files regardless of their format. - -BFD is used by the GNU debugger, assembler, linker, and the binary -utilities. - -The documentation on using BFD is scanty and may be occasionally -incorrect. Pointers to documentation problems, or an entirely -rewritten manual, would be appreciated. - -There is some BFD internals documentation in doc/bfdint.texi which may -help programmers who want to modify BFD. - -BFD is normally built as part of another package. See the build -instructions for that package, probably in a README file in the -appropriate directory. - -BFD supports the following configure options: - - --target=TARGET - The default target for which to build the library. TARGET is - a configuration target triplet, such as sparc-sun-solaris. - --enable-targets=TARGET,TARGET,TARGET... - Additional targets the library should support. To include - support for all known targets, use --enable-targets=all. - --enable-64-bit-bfd - Include support for 64 bit targets. This is automatically - turned on if you explicitly request a 64 bit target, but not - for --enable-targets=all. This requires a compiler with a 64 - bit integer type, such as gcc. - --enable-shared - Build BFD as a shared library. - --with-mmap - Use mmap when accessing files. This is faster on some hosts, - but slower on others. It may not work on all hosts. - -Report bugs with BFD to bug-binutils@gnu.org. - -Patches are encouraged. When sending patches, always send the output -of diff -u or diff -c from the original file to the new file. Do not -send default diff output. Do not make the diff from the new file to -the original file. Remember that any patch must not break other -systems. Remember that BFD must support cross compilation from any -host to any target, so patches which use ``#ifdef HOST'' are not -acceptable. Please also read the ``Reporting Bugs'' section of the -gcc manual. - -Bug reports without patches will be remembered, but they may never get -fixed until somebody volunteers to fix them. - -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/contrib/gdb-7/bfd/archive.c b/contrib/gdb-7/bfd/archive.c index 8cc6bf2a27..1715474ea6 100644 --- a/contrib/gdb-7/bfd/archive.c +++ b/contrib/gdb-7/bfd/archive.c @@ -1,5 +1,5 @@ /* BFD back-end for archive files (libraries). - Copyright 1990-2013 Free Software Foundation, Inc. + Copyright (C) 1990-2015 Free Software Foundation, Inc. Written by Cygnus Support. Mostly Gumby Henkel-Wallace's fault. This file is part of BFD, the Binary File Descriptor library. @@ -140,6 +140,7 @@ SUBSECTION #include "safe-ctype.h" #include "hashtab.h" #include "filenames.h" +#include "bfdlink.h" #ifndef errno extern int errno; @@ -310,8 +311,12 @@ _bfd_look_for_bfd_in_cache (bfd *arch_bfd, file_ptr filepos) struct ar_cache *entry = (struct ar_cache *) htab_find (hash_table, &m); if (!entry) return NULL; - else - return entry->arbfd; + + /* Unfortunately this flag is set after checking that we have + an archive, and checking for an archive means one element has + sneaked into the cache. */ + entry->arbfd->no_export = arch_bfd->no_export; + return entry->arbfd; } else return NULL; @@ -374,10 +379,27 @@ _bfd_add_bfd_to_archive_cache (bfd *arch_bfd, file_ptr filepos, bfd *new_elt) } static bfd * -_bfd_find_nested_archive (bfd *arch_bfd, const char *filename) +open_nested_file (const char *filename, bfd *archive) { - bfd *abfd; const char *target; + bfd *n_bfd; + + target = NULL; + if (!archive->target_defaulted) + target = archive->xvec->name; + n_bfd = bfd_openr (filename, target); + if (n_bfd != NULL) + { + n_bfd->lto_output = archive->lto_output; + n_bfd->no_export = archive->no_export; + } + return n_bfd; +} + +static bfd * +find_nested_archive (const char *filename, bfd *arch_bfd) +{ + bfd *abfd; /* PR 15140: Don't allow a nested archive pointing to itself. */ if (filename_cmp (filename, arch_bfd->filename) == 0) @@ -393,10 +415,7 @@ _bfd_find_nested_archive (bfd *arch_bfd, const char *filename) if (filename_cmp (filename, abfd->filename) == 0) return abfd; } - target = NULL; - if (!arch_bfd->target_defaulted) - target = arch_bfd->xvec->name; - abfd = bfd_openr (filename, target); + abfd = open_nested_file (filename, arch_bfd); if (abfd) { abfd->archive_next = arch_bfd->nested_archives; @@ -625,12 +644,12 @@ bfd * _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) { struct areltdata *new_areldata; - bfd *n_nfd; + bfd *n_bfd; char *filename; - n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos); - if (n_nfd) - return n_nfd; + n_bfd = _bfd_look_for_bfd_in_cache (archive, filepos); + if (n_bfd) + return n_bfd; if (0 > bfd_seek (archive, filepos, SEEK_SET)) return NULL; @@ -642,8 +661,6 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) if (bfd_is_thin_archive (archive)) { - const char *target; - /* This is a proxy entry for an external file. */ if (! IS_ABSOLUTE_PATH (filename)) { @@ -659,7 +676,7 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) { /* This proxy entry refers to an element of a nested archive. Locate the member of that archive and return a bfd for it. */ - bfd *ext_arch = _bfd_find_nested_archive (archive, filename); + bfd *ext_arch = find_nested_archive (filename, archive); if (ext_arch == NULL || ! bfd_check_format (ext_arch, bfd_archive)) @@ -667,57 +684,60 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) free (new_areldata); return NULL; } - n_nfd = _bfd_get_elt_at_filepos (ext_arch, new_areldata->origin); - if (n_nfd == NULL) + n_bfd = _bfd_get_elt_at_filepos (ext_arch, new_areldata->origin); + if (n_bfd == NULL) { free (new_areldata); return NULL; } - n_nfd->proxy_origin = bfd_tell (archive); - return n_nfd; + n_bfd->proxy_origin = bfd_tell (archive); + return n_bfd; } + /* It's not an element of a nested archive; open the external file as a bfd. */ - target = NULL; - if (!archive->target_defaulted) - target = archive->xvec->name; - n_nfd = bfd_openr (filename, target); - if (n_nfd == NULL) + n_bfd = open_nested_file (filename, archive); + if (n_bfd == NULL) bfd_set_error (bfd_error_malformed_archive); } else { - n_nfd = _bfd_create_empty_archive_element_shell (archive); + n_bfd = _bfd_create_empty_archive_element_shell (archive); } - if (n_nfd == NULL) + if (n_bfd == NULL) { free (new_areldata); return NULL; } - n_nfd->proxy_origin = bfd_tell (archive); + n_bfd->proxy_origin = bfd_tell (archive); if (bfd_is_thin_archive (archive)) { - n_nfd->origin = 0; + n_bfd->origin = 0; } else { - n_nfd->origin = n_nfd->proxy_origin; - n_nfd->filename = filename; + n_bfd->origin = n_bfd->proxy_origin; + n_bfd->filename = xstrdup (filename); } - n_nfd->arelt_data = new_areldata; + n_bfd->arelt_data = new_areldata; + + /* Copy BFD_COMPRESS, BFD_DECOMPRESS and BFD_COMPRESS_GABI flags. */ + n_bfd->flags |= archive->flags & (BFD_COMPRESS + | BFD_DECOMPRESS + | BFD_COMPRESS_GABI); - /* Copy BFD_COMPRESS and BFD_DECOMPRESS flags. */ - n_nfd->flags |= archive->flags & (BFD_COMPRESS | BFD_DECOMPRESS); + /* Copy is_linker_input. */ + n_bfd->is_linker_input = archive->is_linker_input; - if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd)) - return n_nfd; + if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_bfd)) + return n_bfd; free (new_areldata); - n_nfd->arelt_data = NULL; + n_bfd->arelt_data = NULL; return NULL; } @@ -901,6 +921,10 @@ do_slurp_bsd_armap (bfd *abfd) return FALSE; parsed_size = mapdata->parsed_size; free (mapdata); + /* PR 17512: file: 883ff754. */ + /* PR 17512: file: 0458885f. */ + if (parsed_size < 4) + return FALSE; raw_armap = (bfd_byte *) bfd_zalloc (abfd, parsed_size); if (raw_armap == NULL) @@ -916,7 +940,6 @@ do_slurp_bsd_armap (bfd *abfd) } ardata->symdef_count = H_GET_32 (abfd, raw_armap) / BSD_SYMDEF_SIZE; - if (ardata->symdef_count * BSD_SYMDEF_SIZE > parsed_size - BSD_SYMDEF_COUNT_SIZE) { @@ -1037,12 +1060,19 @@ do_slurp_coff_armap (bfd *abfd) } /* OK, build the carsyms. */ - for (i = 0; i < nsymz; i++) + for (i = 0; i < nsymz && stringsize > 0; i++) { + bfd_size_type len; + rawptr = raw_armap + i; carsyms->file_offset = swap ((bfd_byte *) rawptr); carsyms->name = stringbase; - stringbase += strlen (stringbase) + 1; + /* PR 17512: file: 4a1d50c1. */ + len = strnlen (stringbase, stringsize); + if (len < stringsize) + len ++; + stringbase += len; + stringsize -= len; carsyms++; } *stringbase = 0; @@ -1130,6 +1160,7 @@ bfd_slurp_armap (bfd *abfd) return FALSE; if (bfd_seek (abfd, -(file_ptr) (sizeof (hdr) + 20), SEEK_CUR) != 0) return FALSE; + extname[20] = 0; if (CONST_STRNEQ (extname, "__.SYMDEF SORTED") || CONST_STRNEQ (extname, "__.SYMDEF")) return do_slurp_bsd_armap (abfd); @@ -1299,6 +1330,8 @@ _bfd_slurp_extended_name_table (bfd *abfd) { byebye: free (namedata); + bfd_ardata (abfd)->extended_names = NULL; + bfd_ardata (abfd)->extended_names_size = 0; return FALSE; } @@ -1315,11 +1348,12 @@ _bfd_slurp_extended_name_table (bfd *abfd) text, the entries in the list are newline-padded, not null padded. In SVR4-style archives, the names also have a trailing '/'. DOS/NT created archive often have \ in them - We'll fix all problems here.. */ + We'll fix all problems here. */ { char *ext_names = bfd_ardata (abfd)->extended_names; char *temp = ext_names; char *limit = temp + namedata->parsed_size; + for (; temp < limit; ++temp) { if (*temp == ARFMAG[1]) @@ -1960,7 +1994,9 @@ bfd_generic_stat_arch_elt (bfd *abfd, struct stat *buf) } hdr = arch_hdr (abfd); - + /* PR 17512: file: 3d9e9fe9. */ + if (hdr == NULL) + return -1; #define foo(arelt, stelt, size) \ buf->stelt = strtol (hdr->arelt, &aloser, size); \ if (aloser == hdr->arelt) \ @@ -2356,6 +2392,10 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) map = new_map; } + if (strcmp (syms[src_count]->name, "__gnu_lto_slim") == 0) + (*_bfd_error_handler) + (_("%s: plugin needed to handle lto object"), + bfd_get_filename (current)); namelen = strlen (syms[src_count]->name); amt = sizeof (char *); map[orl_count].name = (char **) bfd_alloc (arch, amt); @@ -2732,7 +2772,7 @@ _bfd_archive_close_and_cleanup (bfd *abfd) bfd_ardata (abfd)->cache = NULL; } } - else if (arch_eltdata (abfd) != NULL) + if (arch_eltdata (abfd) != NULL) { struct areltdata *ared = arch_eltdata (abfd); htab_t htab = (htab_t) ared->parent_cache; @@ -2751,5 +2791,8 @@ _bfd_archive_close_and_cleanup (bfd *abfd) } } } + if (abfd->is_linker_output) + (*abfd->link.hash->hash_table_free) (abfd); + return TRUE; } diff --git a/contrib/gdb-7/bfd/archive64.c b/contrib/gdb-7/bfd/archive64.c index be64e0d373..8dbdc75077 100644 --- a/contrib/gdb-7/bfd/archive64.c +++ b/contrib/gdb-7/bfd/archive64.c @@ -1,5 +1,5 @@ /* Support for 64-bit ELF archives. - Copyright 1996-2013 Free Software Foundation, Inc. + Copyright (C) 1996-2015 Free Software Foundation, Inc. Ian Lance Taylor, Cygnus Support Linker support added by Mark Mitchell, CodeSourcery, LLC. @@ -46,6 +46,7 @@ bfd_elf64_archive_slurp_armap (bfd *abfd) struct areltdata *mapdata; bfd_byte int_buf[8]; char *stringbase; + char *stringend; bfd_byte *raw_armap = NULL; carsym *carsyms; bfd_size_type amt; @@ -92,11 +93,18 @@ bfd_elf64_archive_slurp_armap (bfd *abfd) ptrsize = 8 * nsymz; amt = carsym_size + stringsize + 1; + if (carsym_size < nsymz || ptrsize < nsymz || amt < nsymz) + { + bfd_set_error (bfd_error_malformed_archive); + return FALSE; + } ardata->symdefs = (struct carsym *) bfd_zalloc (abfd, amt); if (ardata->symdefs == NULL) return FALSE; carsyms = ardata->symdefs; stringbase = ((char *) ardata->symdefs) + carsym_size; + stringbase[stringsize] = 0; + stringend = stringbase + stringsize; raw_armap = (bfd_byte *) bfd_alloc (abfd, ptrsize); if (raw_armap == NULL) @@ -114,7 +122,8 @@ bfd_elf64_archive_slurp_armap (bfd *abfd) { carsyms->file_offset = bfd_getb64 (raw_armap + i * 8); carsyms->name = stringbase; - stringbase += strlen (stringbase) + 1; + if (stringbase < stringend) + stringbase += strlen (stringbase) + 1; ++carsyms; } *stringbase = '\0'; diff --git a/contrib/gdb-7/bfd/archures.c b/contrib/gdb-7/bfd/archures.c index 0be72da528..95433f85ad 100644 --- a/contrib/gdb-7/bfd/archures.c +++ b/contrib/gdb-7/bfd/archures.c @@ -1,7 +1,5 @@ /* BFD library support routines for architectures. - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, - 2012, 2013 Free Software Foundation, Inc. + Copyright (C) 1990-2015 Free Software Foundation, Inc. Hacked by John Gilmore and Steve Chamberlain of Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -123,7 +121,9 @@ DESCRIPTION .#define bfd_mach_i960_jx 7 .#define bfd_mach_i960_hx 8 . -. bfd_arch_or32, {* OpenRISC 32 *} +. bfd_arch_or1k, {* OpenRISC 1000 *} +.#define bfd_mach_or1k 1 +.#define bfd_mach_or1knd 2 . . bfd_arch_sparc, {* SPARC *} .#define bfd_mach_sparc 1 @@ -179,11 +179,18 @@ DESCRIPTION .#define bfd_mach_mips_octeon 6501 .#define bfd_mach_mips_octeonp 6601 .#define bfd_mach_mips_octeon2 6502 +.#define bfd_mach_mips_octeon3 6503 .#define bfd_mach_mips_xlr 887682 {* decimal 'XLR' *} .#define bfd_mach_mipsisa32 32 .#define bfd_mach_mipsisa32r2 33 +.#define bfd_mach_mipsisa32r3 34 +.#define bfd_mach_mipsisa32r5 36 +.#define bfd_mach_mipsisa32r6 37 .#define bfd_mach_mipsisa64 64 .#define bfd_mach_mipsisa64r2 65 +.#define bfd_mach_mipsisa64r3 66 +.#define bfd_mach_mipsisa64r5 68 +.#define bfd_mach_mipsisa64r6 69 .#define bfd_mach_mips_micromips 96 . bfd_arch_i386, {* Intel 386 *} .#define bfd_mach_i386_intel_syntax (1 << 0) @@ -200,6 +207,14 @@ DESCRIPTION . bfd_arch_k1om, {* Intel K1OM *} .#define bfd_mach_k1om (1 << 6) .#define bfd_mach_k1om_intel_syntax (bfd_mach_k1om | bfd_mach_i386_intel_syntax) +.#define bfd_mach_i386_nacl (1 << 7) +.#define bfd_mach_i386_i386_nacl (bfd_mach_i386_i386 | bfd_mach_i386_nacl) +.#define bfd_mach_x86_64_nacl (bfd_mach_x86_64 | bfd_mach_i386_nacl) +.#define bfd_mach_x64_32_nacl (bfd_mach_x64_32 | bfd_mach_i386_nacl) +. bfd_arch_iamcu, {* Intel MCU *} +.#define bfd_mach_iamcu (1 << 8) +.#define bfd_mach_i386_iamcu (bfd_mach_i386_i386 | bfd_mach_iamcu) +.#define bfd_mach_i386_iamcu_intel_syntax (bfd_mach_i386_iamcu | bfd_mach_i386_intel_syntax) . bfd_arch_we32k, {* AT&T WE32xxx *} . bfd_arch_tahoe, {* CCI/Harris Tahoe *} . bfd_arch_i860, {* Intel 860 *} @@ -314,6 +329,12 @@ DESCRIPTION .#define bfd_mach_arm_ep9312 11 .#define bfd_mach_arm_iWMMXt 12 .#define bfd_mach_arm_iWMMXt2 13 +. bfd_arch_nds32, {* Andes NDS32 *} +.#define bfd_mach_n1 1 +.#define bfd_mach_n1h 2 +.#define bfd_mach_n1h_v2 3 +.#define bfd_mach_n1h_v3 4 +.#define bfd_mach_n1h_v3m 5 . bfd_arch_ns32k, {* National Semiconductors ns32000 *} . bfd_arch_w65, {* WDC 65816 *} . bfd_arch_tic30, {* Texas Instruments TMS320C30 *} @@ -361,6 +382,8 @@ DESCRIPTION .#define bfd_mach_fr550 550 . bfd_arch_moxie, {* The moxie processor *} .#define bfd_mach_moxie 1 +. bfd_arch_ft32, {* The ft32 processor *} +.#define bfd_mach_ft32 1 . bfd_arch_mcore, . bfd_arch_mep, .#define bfd_mach_mep 1 @@ -396,6 +419,7 @@ DESCRIPTION .#define bfd_mach_avr5 5 .#define bfd_mach_avr51 51 .#define bfd_mach_avr6 6 +.#define bfd_mach_avrtiny 100 .#define bfd_mach_avrxmega1 101 .#define bfd_mach_avrxmega2 102 .#define bfd_mach_avrxmega3 103 @@ -425,7 +449,6 @@ DESCRIPTION . bfd_arch_score, {* Sunplus score *} .#define bfd_mach_score3 3 .#define bfd_mach_score7 7 -. bfd_arch_openrisc, {* OpenRISC *} . bfd_arch_mmix, {* Donald Knuth's educational processor. *} . bfd_arch_xstormy16, .#define bfd_mach_xstormy16 1 @@ -437,7 +460,12 @@ DESCRIPTION .#define bfd_mach_msp14 14 .#define bfd_mach_msp15 15 .#define bfd_mach_msp16 16 +.#define bfd_mach_msp20 20 .#define bfd_mach_msp21 21 +.#define bfd_mach_msp22 22 +.#define bfd_mach_msp23 23 +.#define bfd_mach_msp24 24 +.#define bfd_mach_msp26 26 .#define bfd_mach_msp31 31 .#define bfd_mach_msp32 32 .#define bfd_mach_msp33 33 @@ -445,6 +473,10 @@ DESCRIPTION .#define bfd_mach_msp42 42 .#define bfd_mach_msp43 43 .#define bfd_mach_msp44 44 +.#define bfd_mach_msp430x 45 +.#define bfd_mach_msp46 46 +.#define bfd_mach_msp47 47 +.#define bfd_mach_msp54 54 . bfd_arch_xc16x, {* Infineon's XC16X Series. *} .#define bfd_mach_xc16x 1 .#define bfd_mach_xc16xl 2 @@ -468,8 +500,13 @@ DESCRIPTION .#define bfd_mach_tilegx32 2 . bfd_arch_aarch64, {* AArch64 *} .#define bfd_mach_aarch64 0 -. bfd_arch_nios2, -.#define bfd_mach_nios2 0 +.#define bfd_mach_aarch64_ilp32 32 +. bfd_arch_nios2, {* Nios II *} +.#define bfd_mach_nios2 0 +.#define bfd_mach_nios2r1 1 +.#define bfd_mach_nios2r2 2 +. bfd_arch_visium, {* Visium *} +.#define bfd_mach_visium 1 . bfd_arch_last . }; */ @@ -535,6 +572,7 @@ extern const bfd_arch_info_type bfd_h8500_arch; extern const bfd_arch_info_type bfd_hppa_arch; extern const bfd_arch_info_type bfd_i370_arch; extern const bfd_arch_info_type bfd_i386_arch; +extern const bfd_arch_info_type bfd_iamcu_arch; extern const bfd_arch_info_type bfd_i860_arch; extern const bfd_arch_info_type bfd_i960_arch; extern const bfd_arch_info_type bfd_ia64_arch; @@ -560,12 +598,13 @@ extern const bfd_arch_info_type bfd_mmix_arch; extern const bfd_arch_info_type bfd_mn10200_arch; extern const bfd_arch_info_type bfd_mn10300_arch; extern const bfd_arch_info_type bfd_moxie_arch; +extern const bfd_arch_info_type bfd_ft32_arch; extern const bfd_arch_info_type bfd_msp430_arch; extern const bfd_arch_info_type bfd_mt_arch; +extern const bfd_arch_info_type bfd_nds32_arch; extern const bfd_arch_info_type bfd_nios2_arch; extern const bfd_arch_info_type bfd_ns32k_arch; -extern const bfd_arch_info_type bfd_openrisc_arch; -extern const bfd_arch_info_type bfd_or32_arch; +extern const bfd_arch_info_type bfd_or1k_arch; extern const bfd_arch_info_type bfd_pdp11_arch; extern const bfd_arch_info_type bfd_pj_arch; extern const bfd_arch_info_type bfd_plugin_arch; @@ -589,6 +628,7 @@ extern const bfd_arch_info_type bfd_tilepro_arch; extern const bfd_arch_info_type bfd_v850_arch; extern const bfd_arch_info_type bfd_v850_rh850_arch; extern const bfd_arch_info_type bfd_vax_arch; +extern const bfd_arch_info_type bfd_visium_arch; extern const bfd_arch_info_type bfd_w65_arch; extern const bfd_arch_info_type bfd_we32k_arch; extern const bfd_arch_info_type bfd_xstormy16_arch; @@ -624,6 +664,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] = &bfd_hppa_arch, &bfd_i370_arch, &bfd_i386_arch, + &bfd_iamcu_arch, &bfd_i860_arch, &bfd_i960_arch, &bfd_ia64_arch, @@ -649,12 +690,13 @@ static const bfd_arch_info_type * const bfd_archures_list[] = &bfd_mn10200_arch, &bfd_mn10300_arch, &bfd_moxie_arch, + &bfd_ft32_arch, &bfd_msp430_arch, &bfd_mt_arch, + &bfd_nds32_arch, &bfd_nios2_arch, &bfd_ns32k_arch, - &bfd_openrisc_arch, - &bfd_or32_arch, + &bfd_or1k_arch, &bfd_pdp11_arch, &bfd_powerpc_arch, &bfd_rs6000_arch, @@ -675,6 +717,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] = &bfd_v850_arch, &bfd_v850_rh850_arch, &bfd_vax_arch, + &bfd_visium_arch, &bfd_w65_arch, &bfd_we32k_arch, &bfd_xstormy16_arch, diff --git a/contrib/gdb-7/bfd/bfd-in.h b/contrib/gdb-7/bfd/bfd-in.h index 1d51932568..ae99d1e356 100644 --- a/contrib/gdb-7/bfd/bfd-in.h +++ b/contrib/gdb-7/bfd/bfd-in.h @@ -1,8 +1,6 @@ /* Main header file for the bfd library -- portable access to object files. - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, - 2012 Free Software Foundation, Inc. + Copyright (C) 1990-2015 Free Software Foundation, Inc. Contributed by Cygnus Support. @@ -294,13 +292,13 @@ typedef struct bfd_section *sec_ptr; #define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) -#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma = (val)), ((ptr)->user_set_vma = TRUE), TRUE) -#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),TRUE) -#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),TRUE) +#define bfd_get_section_limit_octets(bfd, sec) \ + ((bfd)->direction != write_direction && (sec)->rawsize != 0 \ + ? (sec)->rawsize : (sec)->size) + /* Find the address one past the end of SEC. */ #define bfd_get_section_limit(bfd, sec) \ - (((bfd)->direction != write_direction && (sec)->rawsize != 0 \ - ? (sec)->rawsize : (sec)->size) / bfd_octets_per_byte (bfd)) + (bfd_get_section_limit_octets(bfd, sec) / bfd_octets_per_byte (bfd)) /* Return TRUE if input section SEC has been discarded. */ #define discarded_section(sec) \ @@ -439,6 +437,16 @@ extern void bfd_hash_traverse this size. */ extern unsigned long bfd_hash_set_default_size (unsigned long); +/* Types of compressed DWARF debug sections. We currently support + zlib. */ +enum compressed_debug_section_type +{ + COMPRESS_DEBUG_NONE = 0, + COMPRESS_DEBUG = 1 << 0, + COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1, + COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2 +}; + /* This structure is used to keep track of stabs in sections information while linking. */ @@ -519,8 +527,6 @@ extern void warn_deprecated (const char *, const char *, int, const char *); #define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) -#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = bool), TRUE) - extern bfd_boolean bfd_cache_close (bfd *abfd); /* NB: This declaration should match the autogenerated one in libbfd.h. */ @@ -665,7 +671,7 @@ extern int bfd_elf_get_dyn_lib_class (bfd *); extern struct bfd_link_needed_list *bfd_elf_get_runpath_list (bfd *, struct bfd_link_info *); -extern bfd_boolean bfd_elf_discard_info +extern int bfd_elf_discard_info (bfd *, struct bfd_link_info *); extern unsigned int _bfd_elf_default_action_discarded (struct bfd_section *); @@ -687,19 +693,21 @@ extern int bfd_get_elf_phdrs (bfd *abfd, void *phdrs); /* Create a new BFD as if by bfd_openr. Rather than opening a file, - reconstruct an ELF file by reading the segments out of remote memory - based on the ELF file header at EHDR_VMA and the ELF program headers it - points to. If not null, *LOADBASEP is filled in with the difference - between the VMAs from which the segments were read, and the VMAs the - file headers (and hence BFD's idea of each section's VMA) put them at. - - The function TARGET_READ_MEMORY is called to copy LEN bytes from the - remote memory at target address VMA into the local buffer at MYADDR; it - should return zero on success or an `errno' code on failure. TEMPL must - be a BFD for an ELF target with the word size and byte order found in - the remote memory. */ + reconstruct an ELF file by reading the segments out of remote + memory based on the ELF file header at EHDR_VMA and the ELF program + headers it points to. If non-zero, SIZE is the known extent of the + object. If not null, *LOADBASEP is filled in with the difference + between the VMAs from which the segments were read, and the VMAs + the file headers (and hence BFD's idea of each section's VMA) put + them at. + + The function TARGET_READ_MEMORY is called to copy LEN bytes from + the remote memory at target address VMA into the local buffer at + MYADDR; it should return zero on success or an `errno' code on + failure. TEMPL must be a BFD for a target with the word size and + byte order found in the remote memory. */ extern bfd *bfd_elf_bfd_from_remote_memory - (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, + (bfd *templ, bfd_vma ehdr_vma, bfd_size_type size, bfd_vma *loadbasep, int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, bfd_size_type len)); @@ -811,12 +819,6 @@ struct internal_syment; union internal_auxent; #endif -extern bfd_boolean bfd_coff_get_syment - (bfd *, struct bfd_symbol *, struct internal_syment *); - -extern bfd_boolean bfd_coff_get_auxent - (bfd *, struct bfd_symbol *, int, union internal_auxent *); - extern bfd_boolean bfd_coff_set_symbol_class (bfd *, struct bfd_symbol *, unsigned int); @@ -884,15 +886,19 @@ extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking extern bfd_boolean bfd_elf32_arm_add_glue_sections_to_bfd (bfd *, struct bfd_link_info *); -/* ELF ARM mapping symbol support */ +/* ELF ARM mapping symbol support. */ #define BFD_ARM_SPECIAL_SYM_TYPE_MAP (1 << 0) #define BFD_ARM_SPECIAL_SYM_TYPE_TAG (1 << 1) #define BFD_ARM_SPECIAL_SYM_TYPE_OTHER (1 << 2) #define BFD_ARM_SPECIAL_SYM_TYPE_ANY (~0) + extern bfd_boolean bfd_is_arm_special_symbol_name - (const char * name, int type); + (const char *, int); -extern void bfd_elf32_arm_set_byteswap_code (struct bfd_link_info *, int); +extern void bfd_elf32_arm_set_byteswap_code + (struct bfd_link_info *, int); + +extern void bfd_elf32_arm_use_long_plt (void); /* ARM Note section processing. */ extern bfd_boolean bfd_arm_merge_machines @@ -911,7 +917,8 @@ extern void elf32_arm_next_input_section (struct bfd_link_info *, struct bfd_section *); extern bfd_boolean elf32_arm_size_stubs (bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, - struct bfd_section * (*) (const char *, struct bfd_section *), void (*) (void)); + struct bfd_section * (*) (const char *, struct bfd_section *, unsigned int), + void (*) (void)); extern bfd_boolean elf32_arm_build_stubs (struct bfd_link_info *); @@ -933,8 +940,14 @@ extern unsigned int _bfd_elf_ppc_at_tprel_transform extern void bfd_elf64_aarch64_init_maps (bfd *); -void bfd_elf64_aarch64_set_options - (bfd *, struct bfd_link_info *, int, int, int); +extern void bfd_elf32_aarch64_init_maps + (bfd *); + +extern void bfd_elf64_aarch64_set_options + (bfd *, struct bfd_link_info *, int, int, int, int, int); + +extern void bfd_elf32_aarch64_set_options + (bfd *, struct bfd_link_info *, int, int, int, int, int); /* ELF AArch64 mapping symbol support. */ #define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0) @@ -944,7 +957,7 @@ void bfd_elf64_aarch64_set_options extern bfd_boolean bfd_is_aarch64_special_symbol_name (const char * name, int type); -/* AArch64 stub generation support. Called from the linker. */ +/* AArch64 stub generation support for ELF64. Called from the linker. */ extern int elf64_aarch64_setup_section_lists (bfd *, struct bfd_link_info *); extern void elf64_aarch64_next_input_section @@ -955,6 +968,18 @@ extern bfd_boolean elf64_aarch64_size_stubs void (*) (void)); extern bfd_boolean elf64_aarch64_build_stubs (struct bfd_link_info *); +/* AArch64 stub generation support for ELF32. Called from the linker. */ +extern int elf32_aarch64_setup_section_lists + (bfd *, struct bfd_link_info *); +extern void elf32_aarch64_next_input_section + (struct bfd_link_info *, struct bfd_section *); +extern bfd_boolean elf32_aarch64_size_stubs + (bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, + struct bfd_section * (*) (const char *, struct bfd_section *), + void (*) (void)); +extern bfd_boolean elf32_aarch64_build_stubs + (struct bfd_link_info *); + /* TI COFF load page support. */ extern void bfd_ticoff_set_section_load_page @@ -974,23 +999,9 @@ extern void bfd_elf32_ia64_after_parse extern void bfd_elf64_ia64_after_parse (int); -/* This structure is used for a comdat section, as in PE. A comdat - section is associated with a particular symbol. When the linker - sees a comdat section, it keeps only one of the sections with a - given name and associated with a given symbol. */ - -struct coff_comdat_info -{ - /* The name of the symbol associated with a comdat section. */ - const char *name; - - /* The local symbol table index of the symbol associated with a - comdat section. This is only meaningful to the object file format - specific code; it is not an index into the list returned by - bfd_canonicalize_symtab. */ - long symbol; -}; - -extern struct coff_comdat_info *bfd_coff_get_comdat_section - (bfd *, struct bfd_section *); +/* V850 Note manipulation routines. */ +extern bfd_boolean v850_elf_create_sections + (struct bfd_link_info *); +extern bfd_boolean v850_elf_set_note + (bfd *, unsigned int, unsigned int); diff --git a/contrib/gdb-7/bfd/bfd-in2.h b/contrib/gdb-7/bfd/bfd-in2.h index 524e97e78b..85f2054ba5 100644 --- a/contrib/gdb-7/bfd/bfd-in2.h +++ b/contrib/gdb-7/bfd/bfd-in2.h @@ -7,9 +7,7 @@ /* Main header file for the bfd library -- portable access to object files. - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, - 2012 Free Software Foundation, Inc. + Copyright (C) 1990-2015 Free Software Foundation, Inc. Contributed by Cygnus Support. @@ -301,13 +299,13 @@ typedef struct bfd_section *sec_ptr; #define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) -#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma = (val)), ((ptr)->user_set_vma = TRUE), TRUE) -#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),TRUE) -#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),TRUE) +#define bfd_get_section_limit_octets(bfd, sec) \ + ((bfd)->direction != write_direction && (sec)->rawsize != 0 \ + ? (sec)->rawsize : (sec)->size) + /* Find the address one past the end of SEC. */ #define bfd_get_section_limit(bfd, sec) \ - (((bfd)->direction != write_direction && (sec)->rawsize != 0 \ - ? (sec)->rawsize : (sec)->size) / bfd_octets_per_byte (bfd)) + (bfd_get_section_limit_octets(bfd, sec) / bfd_octets_per_byte (bfd)) /* Return TRUE if input section SEC has been discarded. */ #define discarded_section(sec) \ @@ -446,6 +444,16 @@ extern void bfd_hash_traverse this size. */ extern unsigned long bfd_hash_set_default_size (unsigned long); +/* Types of compressed DWARF debug sections. We currently support + zlib. */ +enum compressed_debug_section_type +{ + COMPRESS_DEBUG_NONE = 0, + COMPRESS_DEBUG = 1 << 0, + COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1, + COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2 +}; + /* This structure is used to keep track of stabs in sections information while linking. */ @@ -526,8 +534,6 @@ extern void warn_deprecated (const char *, const char *, int, const char *); #define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) -#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = bool), TRUE) - extern bfd_boolean bfd_cache_close (bfd *abfd); /* NB: This declaration should match the autogenerated one in libbfd.h. */ @@ -672,7 +678,7 @@ extern int bfd_elf_get_dyn_lib_class (bfd *); extern struct bfd_link_needed_list *bfd_elf_get_runpath_list (bfd *, struct bfd_link_info *); -extern bfd_boolean bfd_elf_discard_info +extern int bfd_elf_discard_info (bfd *, struct bfd_link_info *); extern unsigned int _bfd_elf_default_action_discarded (struct bfd_section *); @@ -694,19 +700,21 @@ extern int bfd_get_elf_phdrs (bfd *abfd, void *phdrs); /* Create a new BFD as if by bfd_openr. Rather than opening a file, - reconstruct an ELF file by reading the segments out of remote memory - based on the ELF file header at EHDR_VMA and the ELF program headers it - points to. If not null, *LOADBASEP is filled in with the difference - between the VMAs from which the segments were read, and the VMAs the - file headers (and hence BFD's idea of each section's VMA) put them at. - - The function TARGET_READ_MEMORY is called to copy LEN bytes from the - remote memory at target address VMA into the local buffer at MYADDR; it - should return zero on success or an `errno' code on failure. TEMPL must - be a BFD for an ELF target with the word size and byte order found in - the remote memory. */ + reconstruct an ELF file by reading the segments out of remote + memory based on the ELF file header at EHDR_VMA and the ELF program + headers it points to. If non-zero, SIZE is the known extent of the + object. If not null, *LOADBASEP is filled in with the difference + between the VMAs from which the segments were read, and the VMAs + the file headers (and hence BFD's idea of each section's VMA) put + them at. + + The function TARGET_READ_MEMORY is called to copy LEN bytes from + the remote memory at target address VMA into the local buffer at + MYADDR; it should return zero on success or an `errno' code on + failure. TEMPL must be a BFD for a target with the word size and + byte order found in the remote memory. */ extern bfd *bfd_elf_bfd_from_remote_memory - (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, + (bfd *templ, bfd_vma ehdr_vma, bfd_size_type size, bfd_vma *loadbasep, int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, bfd_size_type len)); @@ -818,12 +826,6 @@ struct internal_syment; union internal_auxent; #endif -extern bfd_boolean bfd_coff_get_syment - (bfd *, struct bfd_symbol *, struct internal_syment *); - -extern bfd_boolean bfd_coff_get_auxent - (bfd *, struct bfd_symbol *, int, union internal_auxent *); - extern bfd_boolean bfd_coff_set_symbol_class (bfd *, struct bfd_symbol *, unsigned int); @@ -891,15 +893,19 @@ extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking extern bfd_boolean bfd_elf32_arm_add_glue_sections_to_bfd (bfd *, struct bfd_link_info *); -/* ELF ARM mapping symbol support */ +/* ELF ARM mapping symbol support. */ #define BFD_ARM_SPECIAL_SYM_TYPE_MAP (1 << 0) #define BFD_ARM_SPECIAL_SYM_TYPE_TAG (1 << 1) #define BFD_ARM_SPECIAL_SYM_TYPE_OTHER (1 << 2) #define BFD_ARM_SPECIAL_SYM_TYPE_ANY (~0) + extern bfd_boolean bfd_is_arm_special_symbol_name - (const char * name, int type); + (const char *, int); + +extern void bfd_elf32_arm_set_byteswap_code + (struct bfd_link_info *, int); -extern void bfd_elf32_arm_set_byteswap_code (struct bfd_link_info *, int); +extern void bfd_elf32_arm_use_long_plt (void); /* ARM Note section processing. */ extern bfd_boolean bfd_arm_merge_machines @@ -918,7 +924,8 @@ extern void elf32_arm_next_input_section (struct bfd_link_info *, struct bfd_section *); extern bfd_boolean elf32_arm_size_stubs (bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, - struct bfd_section * (*) (const char *, struct bfd_section *), void (*) (void)); + struct bfd_section * (*) (const char *, struct bfd_section *, unsigned int), + void (*) (void)); extern bfd_boolean elf32_arm_build_stubs (struct bfd_link_info *); @@ -940,8 +947,14 @@ extern unsigned int _bfd_elf_ppc_at_tprel_transform extern void bfd_elf64_aarch64_init_maps (bfd *); -void bfd_elf64_aarch64_set_options - (bfd *, struct bfd_link_info *, int, int, int); +extern void bfd_elf32_aarch64_init_maps + (bfd *); + +extern void bfd_elf64_aarch64_set_options + (bfd *, struct bfd_link_info *, int, int, int, int, int); + +extern void bfd_elf32_aarch64_set_options + (bfd *, struct bfd_link_info *, int, int, int, int, int); /* ELF AArch64 mapping symbol support. */ #define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0) @@ -951,7 +964,7 @@ void bfd_elf64_aarch64_set_options extern bfd_boolean bfd_is_aarch64_special_symbol_name (const char * name, int type); -/* AArch64 stub generation support. Called from the linker. */ +/* AArch64 stub generation support for ELF64. Called from the linker. */ extern int elf64_aarch64_setup_section_lists (bfd *, struct bfd_link_info *); extern void elf64_aarch64_next_input_section @@ -962,6 +975,18 @@ extern bfd_boolean elf64_aarch64_size_stubs void (*) (void)); extern bfd_boolean elf64_aarch64_build_stubs (struct bfd_link_info *); +/* AArch64 stub generation support for ELF32. Called from the linker. */ +extern int elf32_aarch64_setup_section_lists + (bfd *, struct bfd_link_info *); +extern void elf32_aarch64_next_input_section + (struct bfd_link_info *, struct bfd_section *); +extern bfd_boolean elf32_aarch64_size_stubs + (bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, + struct bfd_section * (*) (const char *, struct bfd_section *), + void (*) (void)); +extern bfd_boolean elf32_aarch64_build_stubs + (struct bfd_link_info *); + /* TI COFF load page support. */ extern void bfd_ticoff_set_section_load_page @@ -981,30 +1006,17 @@ extern void bfd_elf32_ia64_after_parse extern void bfd_elf64_ia64_after_parse (int); -/* This structure is used for a comdat section, as in PE. A comdat - section is associated with a particular symbol. When the linker - sees a comdat section, it keeps only one of the sections with a - given name and associated with a given symbol. */ - -struct coff_comdat_info -{ - /* The name of the symbol associated with a comdat section. */ - const char *name; - - /* The local symbol table index of the symbol associated with a - comdat section. This is only meaningful to the object file format - specific code; it is not an index into the list returned by - bfd_canonicalize_symtab. */ - long symbol; -}; - -extern struct coff_comdat_info *bfd_coff_get_comdat_section - (bfd *, struct bfd_section *); +/* V850 Note manipulation routines. */ +extern bfd_boolean v850_elf_create_sections + (struct bfd_link_info *); +extern bfd_boolean v850_elf_set_note + (bfd *, unsigned int, unsigned int); /* Extracted from init.c. */ void bfd_init (void); /* Extracted from opncls.c. */ +/* Set to N to open the next N BFDs using an alternate id space. */ extern unsigned int bfd_use_reserved_id; bfd *bfd_fopen (const char *filename, const char *target, const char *mode, int fd); @@ -1013,7 +1025,7 @@ bfd *bfd_openr (const char *filename, const char *target); bfd *bfd_fdopenr (const char *filename, const char *target, int fd); -bfd *bfd_openstreamr (const char *, const char *, void *); +bfd *bfd_openstreamr (const char * filename, const char * target, void * stream); bfd *bfd_openr_iovec (const char *filename, const char *target, void *(*open_func) (struct bfd *nbfd, @@ -1049,8 +1061,16 @@ void *bfd_zalloc (bfd *abfd, bfd_size_type wanted); unsigned long bfd_calc_gnu_debuglink_crc32 (unsigned long crc, const unsigned char *buf, bfd_size_type len); +char *bfd_get_debug_link_info (bfd *abfd, unsigned long *crc32_out); + +char *bfd_get_alt_debug_link_info (bfd * abfd, + bfd_size_type *buildid_len, + bfd_byte **buildid_out); + char *bfd_follow_gnu_debuglink (bfd *abfd, const char *dir); +char *bfd_follow_gnu_debugaltlink (bfd *abfd, const char *dir); + struct bfd_section *bfd_create_gnu_debuglink_section (bfd *abfd, const char *filename); @@ -1181,6 +1201,7 @@ void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len, /* Extracted from bfdwin.c. */ /* Extracted from section.c. */ + typedef struct bfd_section { /* The name of the section; the name isn't a copy, the pointer is @@ -1367,6 +1388,10 @@ typedef struct bfd_section executables or shared objects. This is for COFF only. */ #define SEC_COFF_SHARED 0x8000000 + /* This section should be compressed. This is for ELF linker + internal use only. */ +#define SEC_ELF_COMPRESS 0x8000000 + /* When a section with this flag is being linked, then if the size of the input section is less than a page, it should not cross a page boundary. If the size of the input section is one page or more, @@ -1374,11 +1399,18 @@ typedef struct bfd_section TMS320C54X only. */ #define SEC_TIC54X_BLOCK 0x10000000 + /* This section should be renamed. This is for ELF linker + internal use only. */ +#define SEC_ELF_RENAME 0x10000000 + /* Conditionally link this section; do not link if there are no references found to any symbol in the section. This is for TI TMS320C54X only. */ #define SEC_TIC54X_CLINK 0x20000000 + /* This section contains vliw code. This is for Toshiba MeP only. */ +#define SEC_MEP_VLIW 0x20000000 + /* Indicate that section has the no read flag set. This happens when memory read flag isn't set. */ #define SEC_COFF_NOREAD 0x40000000 @@ -1418,6 +1450,8 @@ typedef struct bfd_section #define SEC_INFO_TYPE_MERGE 2 #define SEC_INFO_TYPE_EH_FRAME 3 #define SEC_INFO_TYPE_JUST_SYMS 4 +#define SEC_INFO_TYPE_TARGET 5 +#define SEC_INFO_TYPE_EH_FRAME_ENTRY 6 /* Nonzero if this section uses RELA relocations, rather than REL. */ unsigned int use_rela_p:1; @@ -1572,6 +1606,32 @@ struct relax_table { int size; }; +/* Note: the following are provided as inline functions rather than macros + because not all callers use the return value. A macro implementation + would use a comma expression, eg: "((ptr)->foo = val, TRUE)" and some + compilers will complain about comma expressions that have no effect. */ +static inline bfd_boolean +bfd_set_section_userdata (bfd * abfd ATTRIBUTE_UNUSED, asection * ptr, void * val) +{ + ptr->userdata = val; + return TRUE; +} + +static inline bfd_boolean +bfd_set_section_vma (bfd * abfd ATTRIBUTE_UNUSED, asection * ptr, bfd_vma val) +{ + ptr->vma = ptr->lma = val; + ptr->user_set_vma = TRUE; + return TRUE; +} + +static inline bfd_boolean +bfd_set_section_alignment (bfd * abfd ATTRIBUTE_UNUSED, asection * ptr, unsigned int val) +{ + ptr->alignment_power = val; + return TRUE; +} + /* These sections are global, and are managed by BFD. The application and target back end are not permitted to change the values in these sections. */ @@ -1854,7 +1914,9 @@ enum bfd_architecture #define bfd_mach_i960_jx 7 #define bfd_mach_i960_hx 8 - bfd_arch_or32, /* OpenRISC 32 */ + bfd_arch_or1k, /* OpenRISC 1000 */ +#define bfd_mach_or1k 1 +#define bfd_mach_or1knd 2 bfd_arch_sparc, /* SPARC */ #define bfd_mach_sparc 1 @@ -1910,11 +1972,18 @@ enum bfd_architecture #define bfd_mach_mips_octeon 6501 #define bfd_mach_mips_octeonp 6601 #define bfd_mach_mips_octeon2 6502 +#define bfd_mach_mips_octeon3 6503 #define bfd_mach_mips_xlr 887682 /* decimal 'XLR' */ #define bfd_mach_mipsisa32 32 #define bfd_mach_mipsisa32r2 33 +#define bfd_mach_mipsisa32r3 34 +#define bfd_mach_mipsisa32r5 36 +#define bfd_mach_mipsisa32r6 37 #define bfd_mach_mipsisa64 64 #define bfd_mach_mipsisa64r2 65 +#define bfd_mach_mipsisa64r3 66 +#define bfd_mach_mipsisa64r5 68 +#define bfd_mach_mipsisa64r6 69 #define bfd_mach_mips_micromips 96 bfd_arch_i386, /* Intel 386 */ #define bfd_mach_i386_intel_syntax (1 << 0) @@ -1931,6 +2000,14 @@ enum bfd_architecture bfd_arch_k1om, /* Intel K1OM */ #define bfd_mach_k1om (1 << 6) #define bfd_mach_k1om_intel_syntax (bfd_mach_k1om | bfd_mach_i386_intel_syntax) +#define bfd_mach_i386_nacl (1 << 7) +#define bfd_mach_i386_i386_nacl (bfd_mach_i386_i386 | bfd_mach_i386_nacl) +#define bfd_mach_x86_64_nacl (bfd_mach_x86_64 | bfd_mach_i386_nacl) +#define bfd_mach_x64_32_nacl (bfd_mach_x64_32 | bfd_mach_i386_nacl) + bfd_arch_iamcu, /* Intel MCU */ +#define bfd_mach_iamcu (1 << 8) +#define bfd_mach_i386_iamcu (bfd_mach_i386_i386 | bfd_mach_iamcu) +#define bfd_mach_i386_iamcu_intel_syntax (bfd_mach_i386_iamcu | bfd_mach_i386_intel_syntax) bfd_arch_we32k, /* AT&T WE32xxx */ bfd_arch_tahoe, /* CCI/Harris Tahoe */ bfd_arch_i860, /* Intel 860 */ @@ -2045,6 +2122,12 @@ enum bfd_architecture #define bfd_mach_arm_ep9312 11 #define bfd_mach_arm_iWMMXt 12 #define bfd_mach_arm_iWMMXt2 13 + bfd_arch_nds32, /* Andes NDS32 */ +#define bfd_mach_n1 1 +#define bfd_mach_n1h 2 +#define bfd_mach_n1h_v2 3 +#define bfd_mach_n1h_v3 4 +#define bfd_mach_n1h_v3m 5 bfd_arch_ns32k, /* National Semiconductors ns32000 */ bfd_arch_w65, /* WDC 65816 */ bfd_arch_tic30, /* Texas Instruments TMS320C30 */ @@ -2092,6 +2175,8 @@ enum bfd_architecture #define bfd_mach_fr550 550 bfd_arch_moxie, /* The moxie processor */ #define bfd_mach_moxie 1 + bfd_arch_ft32, /* The ft32 processor */ +#define bfd_mach_ft32 1 bfd_arch_mcore, bfd_arch_mep, #define bfd_mach_mep 1 @@ -2127,6 +2212,7 @@ enum bfd_architecture #define bfd_mach_avr5 5 #define bfd_mach_avr51 51 #define bfd_mach_avr6 6 +#define bfd_mach_avrtiny 100 #define bfd_mach_avrxmega1 101 #define bfd_mach_avrxmega2 102 #define bfd_mach_avrxmega3 103 @@ -2156,7 +2242,6 @@ enum bfd_architecture bfd_arch_score, /* Sunplus score */ #define bfd_mach_score3 3 #define bfd_mach_score7 7 - bfd_arch_openrisc, /* OpenRISC */ bfd_arch_mmix, /* Donald Knuth's educational processor. */ bfd_arch_xstormy16, #define bfd_mach_xstormy16 1 @@ -2168,7 +2253,12 @@ enum bfd_architecture #define bfd_mach_msp14 14 #define bfd_mach_msp15 15 #define bfd_mach_msp16 16 +#define bfd_mach_msp20 20 #define bfd_mach_msp21 21 +#define bfd_mach_msp22 22 +#define bfd_mach_msp23 23 +#define bfd_mach_msp24 24 +#define bfd_mach_msp26 26 #define bfd_mach_msp31 31 #define bfd_mach_msp32 32 #define bfd_mach_msp33 33 @@ -2176,6 +2266,10 @@ enum bfd_architecture #define bfd_mach_msp42 42 #define bfd_mach_msp43 43 #define bfd_mach_msp44 44 +#define bfd_mach_msp430x 45 +#define bfd_mach_msp46 46 +#define bfd_mach_msp47 47 +#define bfd_mach_msp54 54 bfd_arch_xc16x, /* Infineon's XC16X Series. */ #define bfd_mach_xc16x 1 #define bfd_mach_xc16xl 2 @@ -2199,8 +2293,13 @@ enum bfd_architecture #define bfd_mach_tilegx32 2 bfd_arch_aarch64, /* AArch64 */ #define bfd_mach_aarch64 0 - bfd_arch_nios2, -#define bfd_mach_nios2 0 +#define bfd_mach_aarch64_ilp32 32 + bfd_arch_nios2, /* Nios II */ +#define bfd_mach_nios2 0 +#define bfd_mach_nios2r1 1 +#define bfd_mach_nios2r2 2 + bfd_arch_visium, /* Visium */ +#define bfd_mach_visium 1 bfd_arch_last }; @@ -2266,6 +2365,7 @@ unsigned int bfd_arch_mach_octets_per_byte (enum bfd_architecture arch, unsigned long machine); /* Extracted from reloc.c. */ + typedef enum bfd_reloc_status { /* No errors detected. */ @@ -2315,6 +2415,7 @@ typedef struct reloc_cache_entry } arelent; + enum complain_overflow { /* Do not complain on overflow. */ @@ -2333,6 +2434,7 @@ enum complain_overflow unsigned number. */ complain_overflow_unsigned }; +struct bfd_symbol; /* Forward declaration. */ struct reloc_howto_struct { @@ -2860,6 +2962,12 @@ to compensate for the borrow when the low bits are added. */ BFD_RELOC_MICROMIPS_10_PCREL_S1, BFD_RELOC_MICROMIPS_16_PCREL_S1, +/* MIPS PC-relative relocations. */ + BFD_RELOC_MIPS_21_PCREL_S2, + BFD_RELOC_MIPS_26_PCREL_S2, + BFD_RELOC_MIPS_18_PCREL_S3, + BFD_RELOC_MIPS_19_PCREL_S2, + /* microMIPS versions of generic BFD relocs. */ BFD_RELOC_MICROMIPS_GPREL16, BFD_RELOC_MICROMIPS_HI16, @@ -2922,6 +3030,7 @@ to compensate for the borrow when the low bits are added. */ BFD_RELOC_MICROMIPS_TLS_TPREL_HI16, BFD_RELOC_MIPS_TLS_TPREL_LO16, BFD_RELOC_MICROMIPS_TLS_TPREL_LO16, + BFD_RELOC_MIPS_EH, /* MIPS ELF relocations (VxWorks and PLT extensions). */ @@ -2933,6 +3042,13 @@ to compensate for the borrow when the low bits are added. */ BFD_RELOC_MOXIE_10_PCREL, +/* FT32 ELF relocations. */ + BFD_RELOC_FT32_10, + BFD_RELOC_FT32_20, + BFD_RELOC_FT32_17, + BFD_RELOC_FT32_18, + + /* Fujitsu Frv Relocations. */ BFD_RELOC_FRV_LABEL16, BFD_RELOC_FRV_LABEL24, @@ -3086,6 +3202,8 @@ instruction. */ BFD_RELOC_X86_64_TLSDESC_CALL, BFD_RELOC_X86_64_TLSDESC, BFD_RELOC_X86_64_IRELATIVE, + BFD_RELOC_X86_64_PC32_BND, + BFD_RELOC_X86_64_PLT32_BND, /* ns32k relocations */ BFD_RELOC_NS32K_IMM_8, @@ -3184,6 +3302,9 @@ instruction. */ BFD_RELOC_PPC64_TOC16_LO_DS, BFD_RELOC_PPC64_PLTGOT16_DS, BFD_RELOC_PPC64_PLTGOT16_LO_DS, + BFD_RELOC_PPC64_ADDR16_HIGH, + BFD_RELOC_PPC64_ADDR16_HIGHA, + BFD_RELOC_PPC64_ADDR64_LOCAL, /* PowerPC and PowerPC64 thread-local storage relocations. */ BFD_RELOC_PPC_TLS, @@ -3228,6 +3349,10 @@ instruction. */ BFD_RELOC_PPC64_DTPREL16_HIGHERA, BFD_RELOC_PPC64_DTPREL16_HIGHEST, BFD_RELOC_PPC64_DTPREL16_HIGHESTA, + BFD_RELOC_PPC64_TPREL16_HIGH, + BFD_RELOC_PPC64_TPREL16_HIGHA, + BFD_RELOC_PPC64_DTPREL16_HIGH, + BFD_RELOC_PPC64_DTPREL16_HIGHA, /* IBM 370/390 relocations */ BFD_RELOC_I370_D12, @@ -3749,6 +3874,205 @@ add3, load, and store instructions. */ BFD_RELOC_M32R_GOTPC_HI_SLO, BFD_RELOC_M32R_GOTPC_LO, +/* NDS32 relocs. +This is a 20 bit absolute address. */ + BFD_RELOC_NDS32_20, + +/* This is a 9-bit pc-relative reloc with the right 1 bit assumed to be 0. */ + BFD_RELOC_NDS32_9_PCREL, + +/* This is a 9-bit pc-relative reloc with the right 1 bit assumed to be 0. */ + BFD_RELOC_NDS32_WORD_9_PCREL, + +/* This is an 15-bit reloc with the right 1 bit assumed to be 0. */ + BFD_RELOC_NDS32_15_PCREL, + +/* This is an 17-bit reloc with the right 1 bit assumed to be 0. */ + BFD_RELOC_NDS32_17_PCREL, + +/* This is a 25-bit reloc with the right 1 bit assumed to be 0. */ + BFD_RELOC_NDS32_25_PCREL, + +/* This is a 20-bit reloc containing the high 20 bits of an address +used with the lower 12 bits */ + BFD_RELOC_NDS32_HI20, + +/* This is a 12-bit reloc containing the lower 12 bits of an address +then shift right by 3. This is used with ldi,sdi... */ + BFD_RELOC_NDS32_LO12S3, + +/* This is a 12-bit reloc containing the lower 12 bits of an address +then shift left by 2. This is used with lwi,swi... */ + BFD_RELOC_NDS32_LO12S2, + +/* This is a 12-bit reloc containing the lower 12 bits of an address +then shift left by 1. This is used with lhi,shi... */ + BFD_RELOC_NDS32_LO12S1, + +/* This is a 12-bit reloc containing the lower 12 bits of an address +then shift left by 0. This is used with lbisbi... */ + BFD_RELOC_NDS32_LO12S0, + +/* This is a 12-bit reloc containing the lower 12 bits of an address +then shift left by 0. This is only used with branch relaxations */ + BFD_RELOC_NDS32_LO12S0_ORI, + +/* This is a 15-bit reloc containing the small data area 18-bit signed offset +and shift left by 3 for use in ldi, sdi... */ + BFD_RELOC_NDS32_SDA15S3, + +/* This is a 15-bit reloc containing the small data area 17-bit signed offset +and shift left by 2 for use in lwi, swi... */ + BFD_RELOC_NDS32_SDA15S2, + +/* This is a 15-bit reloc containing the small data area 16-bit signed offset +and shift left by 1 for use in lhi, shi... */ + BFD_RELOC_NDS32_SDA15S1, + +/* This is a 15-bit reloc containing the small data area 15-bit signed offset +and shift left by 0 for use in lbi, sbi... */ + BFD_RELOC_NDS32_SDA15S0, + +/* This is a 16-bit reloc containing the small data area 16-bit signed offset +and shift left by 3 */ + BFD_RELOC_NDS32_SDA16S3, + +/* This is a 17-bit reloc containing the small data area 17-bit signed offset +and shift left by 2 for use in lwi.gp, swi.gp... */ + BFD_RELOC_NDS32_SDA17S2, + +/* This is a 18-bit reloc containing the small data area 18-bit signed offset +and shift left by 1 for use in lhi.gp, shi.gp... */ + BFD_RELOC_NDS32_SDA18S1, + +/* This is a 19-bit reloc containing the small data area 19-bit signed offset +and shift left by 0 for use in lbi.gp, sbi.gp... */ + BFD_RELOC_NDS32_SDA19S0, + +/* for PIC */ + BFD_RELOC_NDS32_GOT20, + BFD_RELOC_NDS32_9_PLTREL, + BFD_RELOC_NDS32_25_PLTREL, + BFD_RELOC_NDS32_COPY, + BFD_RELOC_NDS32_GLOB_DAT, + BFD_RELOC_NDS32_JMP_SLOT, + BFD_RELOC_NDS32_RELATIVE, + BFD_RELOC_NDS32_GOTOFF, + BFD_RELOC_NDS32_GOTOFF_HI20, + BFD_RELOC_NDS32_GOTOFF_LO12, + BFD_RELOC_NDS32_GOTPC20, + BFD_RELOC_NDS32_GOT_HI20, + BFD_RELOC_NDS32_GOT_LO12, + BFD_RELOC_NDS32_GOTPC_HI20, + BFD_RELOC_NDS32_GOTPC_LO12, + +/* for relax */ + BFD_RELOC_NDS32_INSN16, + BFD_RELOC_NDS32_LABEL, + BFD_RELOC_NDS32_LONGCALL1, + BFD_RELOC_NDS32_LONGCALL2, + BFD_RELOC_NDS32_LONGCALL3, + BFD_RELOC_NDS32_LONGJUMP1, + BFD_RELOC_NDS32_LONGJUMP2, + BFD_RELOC_NDS32_LONGJUMP3, + BFD_RELOC_NDS32_LOADSTORE, + BFD_RELOC_NDS32_9_FIXED, + BFD_RELOC_NDS32_15_FIXED, + BFD_RELOC_NDS32_17_FIXED, + BFD_RELOC_NDS32_25_FIXED, + BFD_RELOC_NDS32_LONGCALL4, + BFD_RELOC_NDS32_LONGCALL5, + BFD_RELOC_NDS32_LONGCALL6, + BFD_RELOC_NDS32_LONGJUMP4, + BFD_RELOC_NDS32_LONGJUMP5, + BFD_RELOC_NDS32_LONGJUMP6, + BFD_RELOC_NDS32_LONGJUMP7, + +/* for PIC */ + BFD_RELOC_NDS32_PLTREL_HI20, + BFD_RELOC_NDS32_PLTREL_LO12, + BFD_RELOC_NDS32_PLT_GOTREL_HI20, + BFD_RELOC_NDS32_PLT_GOTREL_LO12, + +/* for floating point */ + BFD_RELOC_NDS32_SDA12S2_DP, + BFD_RELOC_NDS32_SDA12S2_SP, + BFD_RELOC_NDS32_LO12S2_DP, + BFD_RELOC_NDS32_LO12S2_SP, + +/* for dwarf2 debug_line. */ + BFD_RELOC_NDS32_DWARF2_OP1, + BFD_RELOC_NDS32_DWARF2_OP2, + BFD_RELOC_NDS32_DWARF2_LEB, + +/* for eliminate 16-bit instructions */ + BFD_RELOC_NDS32_UPDATE_TA, + +/* for PIC object relaxation */ + BFD_RELOC_NDS32_PLT_GOTREL_LO20, + BFD_RELOC_NDS32_PLT_GOTREL_LO15, + BFD_RELOC_NDS32_PLT_GOTREL_LO19, + BFD_RELOC_NDS32_GOT_LO15, + BFD_RELOC_NDS32_GOT_LO19, + BFD_RELOC_NDS32_GOTOFF_LO15, + BFD_RELOC_NDS32_GOTOFF_LO19, + BFD_RELOC_NDS32_GOT15S2, + BFD_RELOC_NDS32_GOT17S2, + +/* NDS32 relocs. +This is a 5 bit absolute address. */ + BFD_RELOC_NDS32_5, + +/* This is a 10-bit unsigned pc-relative reloc with the right 1 bit assumed to be 0. */ + BFD_RELOC_NDS32_10_UPCREL, + +/* If fp were omitted, fp can used as another gp. */ + BFD_RELOC_NDS32_SDA_FP7U2_RELA, + +/* relaxation relative relocation types */ + BFD_RELOC_NDS32_RELAX_ENTRY, + BFD_RELOC_NDS32_GOT_SUFF, + BFD_RELOC_NDS32_GOTOFF_SUFF, + BFD_RELOC_NDS32_PLT_GOT_SUFF, + BFD_RELOC_NDS32_MULCALL_SUFF, + BFD_RELOC_NDS32_PTR, + BFD_RELOC_NDS32_PTR_COUNT, + BFD_RELOC_NDS32_PTR_RESOLVED, + BFD_RELOC_NDS32_PLTBLOCK, + BFD_RELOC_NDS32_RELAX_REGION_BEGIN, + BFD_RELOC_NDS32_RELAX_REGION_END, + BFD_RELOC_NDS32_MINUEND, + BFD_RELOC_NDS32_SUBTRAHEND, + BFD_RELOC_NDS32_DIFF8, + BFD_RELOC_NDS32_DIFF16, + BFD_RELOC_NDS32_DIFF32, + BFD_RELOC_NDS32_DIFF_ULEB128, + BFD_RELOC_NDS32_EMPTY, + +/* This is a 25 bit absolute address. */ + BFD_RELOC_NDS32_25_ABS, + +/* For ex9 and ifc using. */ + BFD_RELOC_NDS32_DATA, + BFD_RELOC_NDS32_TRAN, + BFD_RELOC_NDS32_17IFC_PCREL, + BFD_RELOC_NDS32_10IFCU_PCREL, + +/* For TLS. */ + BFD_RELOC_NDS32_TPOFF, + BFD_RELOC_NDS32_TLS_LE_HI20, + BFD_RELOC_NDS32_TLS_LE_LO12, + BFD_RELOC_NDS32_TLS_LE_ADD, + BFD_RELOC_NDS32_TLS_LE_LS, + BFD_RELOC_NDS32_GOTTPOFF, + BFD_RELOC_NDS32_TLS_IE_HI20, + BFD_RELOC_NDS32_TLS_IE_LO12S2, + BFD_RELOC_NDS32_TLS_TPOFF, + BFD_RELOC_NDS32_TLS_LE_20, + BFD_RELOC_NDS32_TLS_LE_15S0, + BFD_RELOC_NDS32_TLS_LE_15S1, + BFD_RELOC_NDS32_TLS_LE_15S2, + /* This is a 9-bit reloc */ BFD_RELOC_V850_9_PCREL, @@ -4206,6 +4530,28 @@ in .byte hi8(symbol) */ in .byte hlo8(symbol) */ BFD_RELOC_AVR_8_HLO, +/* AVR relocations to mark the difference of two local symbols. +These are only needed to support linker relaxation and can be ignored +when not relaxing. The field is set to the value of the difference +assuming no relaxation. The relocation encodes the position of the +second symbol so the linker can determine whether to adjust the field +value. */ + BFD_RELOC_AVR_DIFF8, + BFD_RELOC_AVR_DIFF16, + BFD_RELOC_AVR_DIFF32, + +/* This is a 7 bit reloc for the AVR that stores SRAM address for 16bit +lds and sts instructions supported only tiny core. */ + BFD_RELOC_AVR_LDS_STS_16, + +/* This is a 6 bit reloc for the AVR that stores an I/O register +number for the IN and OUT instructions */ + BFD_RELOC_AVR_PORT6, + +/* This is a 5 bit reloc for the AVR that stores an I/O register +number for the SBIC, SBIS, SBI and CBI instructions */ + BFD_RELOC_AVR_PORT5, + /* Renesas RL78 Relocations. */ BFD_RELOC_RL78_NEG8, BFD_RELOC_RL78_NEG16, @@ -4240,6 +4586,7 @@ in .byte hlo8(symbol) */ BFD_RELOC_RL78_HI8, BFD_RELOC_RL78_LO16, BFD_RELOC_RL78_CODE, + BFD_RELOC_RL78_SADDR, /* Renesas RX Relocations. */ BFD_RELOC_RX_NEG8, @@ -4297,12 +4644,24 @@ in .byte hlo8(symbol) */ /* 16 bit GOT offset. */ BFD_RELOC_390_GOT16, +/* PC relative 12 bit shifted by 1. */ + BFD_RELOC_390_PC12DBL, + +/* 12 bit PC rel. PLT shifted by 1. */ + BFD_RELOC_390_PLT12DBL, + /* PC relative 16 bit shifted by 1. */ BFD_RELOC_390_PC16DBL, /* 16 bit PC rel. PLT shifted by 1. */ BFD_RELOC_390_PLT16DBL, +/* PC relative 24 bit shifted by 1. */ + BFD_RELOC_390_PC24DBL, + +/* 24 bit PC rel. PLT shifted by 1. */ + BFD_RELOC_390_PLT24DBL, + /* PC relative 32 bit shifted by 1. */ BFD_RELOC_390_PC32DBL, @@ -4857,9 +5216,31 @@ a matching LO8XG part. */ BFD_RELOC_860_HIGOT, BFD_RELOC_860_HIGOTOFF, -/* OpenRISC Relocations. */ - BFD_RELOC_OPENRISC_ABS_26, - BFD_RELOC_OPENRISC_REL_26, +/* OpenRISC 1000 Relocations. */ + BFD_RELOC_OR1K_REL_26, + BFD_RELOC_OR1K_GOTPC_HI16, + BFD_RELOC_OR1K_GOTPC_LO16, + BFD_RELOC_OR1K_GOT16, + BFD_RELOC_OR1K_PLT26, + BFD_RELOC_OR1K_GOTOFF_HI16, + BFD_RELOC_OR1K_GOTOFF_LO16, + BFD_RELOC_OR1K_COPY, + BFD_RELOC_OR1K_GLOB_DAT, + BFD_RELOC_OR1K_JMP_SLOT, + BFD_RELOC_OR1K_RELATIVE, + BFD_RELOC_OR1K_TLS_GD_HI16, + BFD_RELOC_OR1K_TLS_GD_LO16, + BFD_RELOC_OR1K_TLS_LDM_HI16, + BFD_RELOC_OR1K_TLS_LDM_LO16, + BFD_RELOC_OR1K_TLS_LDO_HI16, + BFD_RELOC_OR1K_TLS_LDO_LO16, + BFD_RELOC_OR1K_TLS_IE_HI16, + BFD_RELOC_OR1K_TLS_IE_LO16, + BFD_RELOC_OR1K_TLS_LE_HI16, + BFD_RELOC_OR1K_TLS_LE_LO16, + BFD_RELOC_OR1K_TLS_TPOFF, + BFD_RELOC_OR1K_TLS_DTPOFF, + BFD_RELOC_OR1K_TLS_DTPMOD, /* H8 elf Relocations. */ BFD_RELOC_H8_DIR16A8, @@ -4867,6 +5248,7 @@ a matching LO8XG part. */ BFD_RELOC_H8_DIR24A8, BFD_RELOC_H8_DIR24R8, BFD_RELOC_H8_DIR32A16, + BFD_RELOC_H8_DISP32A16, /* Sony Xstormy16 Relocations. */ BFD_RELOC_XSTORMY16_REL_12, @@ -4915,6 +5297,21 @@ a matching LO8XG part. */ BFD_RELOC_MSP430_16_BYTE, BFD_RELOC_MSP430_2X_PCREL, BFD_RELOC_MSP430_RL_PCREL, + BFD_RELOC_MSP430_ABS8, + BFD_RELOC_MSP430X_PCR20_EXT_SRC, + BFD_RELOC_MSP430X_PCR20_EXT_DST, + BFD_RELOC_MSP430X_PCR20_EXT_ODST, + BFD_RELOC_MSP430X_ABS20_EXT_SRC, + BFD_RELOC_MSP430X_ABS20_EXT_DST, + BFD_RELOC_MSP430X_ABS20_EXT_ODST, + BFD_RELOC_MSP430X_ABS20_ADR_SRC, + BFD_RELOC_MSP430X_ABS20_ADR_DST, + BFD_RELOC_MSP430X_PCR16, + BFD_RELOC_MSP430X_PCR20_CALL, + BFD_RELOC_MSP430X_ABS16, + BFD_RELOC_MSP430_ABS_HI16, + BFD_RELOC_MSP430_PREL31, + BFD_RELOC_MSP430_SYM_DIFF, /* Relocations used by the Altera Nios II core. */ BFD_RELOC_NIOS2_S16, @@ -4951,6 +5348,24 @@ a matching LO8XG part. */ BFD_RELOC_NIOS2_JUMP_SLOT, BFD_RELOC_NIOS2_RELATIVE, BFD_RELOC_NIOS2_GOTOFF, + BFD_RELOC_NIOS2_CALL26_NOAT, + BFD_RELOC_NIOS2_GOT_LO, + BFD_RELOC_NIOS2_GOT_HA, + BFD_RELOC_NIOS2_CALL_LO, + BFD_RELOC_NIOS2_CALL_HA, + BFD_RELOC_NIOS2_R2_S12, + BFD_RELOC_NIOS2_R2_I10_1_PCREL, + BFD_RELOC_NIOS2_R2_T1I7_1_PCREL, + BFD_RELOC_NIOS2_R2_T1I7_2, + BFD_RELOC_NIOS2_R2_T2I4, + BFD_RELOC_NIOS2_R2_T2I4_1, + BFD_RELOC_NIOS2_R2_T2I4_2, + BFD_RELOC_NIOS2_R2_X1I7_2, + BFD_RELOC_NIOS2_R2_X2L5, + BFD_RELOC_NIOS2_R2_F1I5_2, + BFD_RELOC_NIOS2_R2_L5I4X1, + BFD_RELOC_NIOS2_R2_T1X1I6, + BFD_RELOC_NIOS2_R2_T1X1I6_2, /* IQ2000 Relocations. */ BFD_RELOC_IQ2000_OFFSET_16, @@ -5189,21 +5604,78 @@ to two words (uses imm instruction). */ to two words (uses imm instruction). */ BFD_RELOC_MICROBLAZE_64_TLSTPREL, -/* AArch64 ADD immediate instruction, holding bits 0 to 11 of the address. -Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ - BFD_RELOC_AARCH64_ADD_LO12, +/* AArch64 pseudo relocation code to mark the start of the AArch64 +relocation enumerators. N.B. the order of the enumerators is +important as several tables in the AArch64 bfd backend are indexed +by these enumerators; make sure they are all synced. */ + BFD_RELOC_AARCH64_RELOC_START, -/* AArch64 Load Literal instruction, holding a 19 bit PC relative word -offset of the global offset table entry for a symbol. The lowest two -bits must be zero and are not stored in the instruction, giving a 21 -bit signed byte offset. This relocation type requires signed overflow -checking. */ - BFD_RELOC_AARCH64_GOT_LD_PREL19, +/* AArch64 null relocation code. */ + BFD_RELOC_AARCH64_NONE, -/* Get to the page base of the global offset table entry for a symbol as -part of an ADRP instruction using a 21 bit PC relative value.Used in -conjunction with BFD_RELOC_AARCH64_LD64_GOT_LO12_NC. */ - BFD_RELOC_AARCH64_ADR_GOT_PAGE, +/* Basic absolute relocations of N bits. These are equivalent to +BFD_RELOC_N and they were added to assist the indexing of the howto +table. */ + BFD_RELOC_AARCH64_64, + BFD_RELOC_AARCH64_32, + BFD_RELOC_AARCH64_16, + +/* PC-relative relocations. These are equivalent to BFD_RELOC_N_PCREL +and they were added to assist the indexing of the howto table. */ + BFD_RELOC_AARCH64_64_PCREL, + BFD_RELOC_AARCH64_32_PCREL, + BFD_RELOC_AARCH64_16_PCREL, + +/* AArch64 MOV[NZK] instruction with most significant bits 0 to 15 +of an unsigned address/value. */ + BFD_RELOC_AARCH64_MOVW_G0, + +/* AArch64 MOV[NZK] instruction with less significant bits 0 to 15 of +an address/value. No overflow checking. */ + BFD_RELOC_AARCH64_MOVW_G0_NC, + +/* AArch64 MOV[NZK] instruction with most significant bits 16 to 31 +of an unsigned address/value. */ + BFD_RELOC_AARCH64_MOVW_G1, + +/* AArch64 MOV[NZK] instruction with less significant bits 16 to 31 +of an address/value. No overflow checking. */ + BFD_RELOC_AARCH64_MOVW_G1_NC, + +/* AArch64 MOV[NZK] instruction with most significant bits 32 to 47 +of an unsigned address/value. */ + BFD_RELOC_AARCH64_MOVW_G2, + +/* AArch64 MOV[NZK] instruction with less significant bits 32 to 47 +of an address/value. No overflow checking. */ + BFD_RELOC_AARCH64_MOVW_G2_NC, + +/* AArch64 MOV[NZK] instruction with most signficant bits 48 to 64 +of a signed or unsigned address/value. */ + BFD_RELOC_AARCH64_MOVW_G3, + +/* AArch64 MOV[NZ] instruction with most significant bits 0 to 15 +of a signed value. Changes instruction to MOVZ or MOVN depending on the +value's sign. */ + BFD_RELOC_AARCH64_MOVW_G0_S, + +/* AArch64 MOV[NZ] instruction with most significant bits 16 to 31 +of a signed value. Changes instruction to MOVZ or MOVN depending on the +value's sign. */ + BFD_RELOC_AARCH64_MOVW_G1_S, + +/* AArch64 MOV[NZ] instruction with most significant bits 32 to 47 +of a signed value. Changes instruction to MOVZ or MOVN depending on the +value's sign. */ + BFD_RELOC_AARCH64_MOVW_G2_S, + +/* AArch64 Load Literal instruction, holding a 19 bit pc-relative word +offset. The lowest two bits must be zero and are not stored in the +instruction, giving a 21 bit signed byte offset. */ + BFD_RELOC_AARCH64_LD_LO19_PCREL, + +/* AArch64 ADR instruction, holding a simple 21 bit pc-relative byte offset. */ + BFD_RELOC_AARCH64_ADR_LO21_PCREL, /* AArch64 ADRP instruction, with bits 12 to 32 of a pc-relative page offset, giving a 4KB aligned page base address. */ @@ -5214,45 +5686,33 @@ offset, giving a 4KB aligned page base address, but with no overflow checking. */ BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL, -/* AArch64 ADR instruction, holding a simple 21 bit pc-relative byte offset. */ - BFD_RELOC_AARCH64_ADR_LO21_PCREL, +/* AArch64 ADD immediate instruction, holding bits 0 to 11 of the address. +Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ + BFD_RELOC_AARCH64_ADD_LO12, + +/* AArch64 8-bit load/store instruction, holding bits 0 to 11 of the +address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ + BFD_RELOC_AARCH64_LDST8_LO12, + +/* AArch64 14 bit pc-relative test bit and branch. +The lowest two bits must be zero and are not stored in the instruction, +giving a 16 bit signed byte offset. */ + BFD_RELOC_AARCH64_TSTBR14, /* AArch64 19 bit pc-relative conditional branch and compare & branch. The lowest two bits must be zero and are not stored in the instruction, giving a 21 bit signed byte offset. */ BFD_RELOC_AARCH64_BRANCH19, -/* AArch64 26 bit pc-relative unconditional branch and link. -The lowest two bits must be zero and are not stored in the instruction, -giving a 28 bit signed byte offset. */ - BFD_RELOC_AARCH64_CALL26, - -/* AArch64 pseudo relocation code to be used internally by the AArch64 -assembler and not (currently) written to any object files. */ - BFD_RELOC_AARCH64_GAS_INTERNAL_FIXUP, - /* AArch64 26 bit pc-relative unconditional branch. The lowest two bits must be zero and are not stored in the instruction, giving a 28 bit signed byte offset. */ BFD_RELOC_AARCH64_JUMP26, -/* AArch64 Load Literal instruction, holding a 19 bit pc-relative word -offset. The lowest two bits must be zero and are not stored in the -instruction, giving a 21 bit signed byte offset. */ - BFD_RELOC_AARCH64_LD_LO19_PCREL, - -/* Unsigned 12 bit byte offset for 64 bit load/store from the page of -the GOT entry for this symbol. Used in conjunction with -BFD_RELOC_AARCH64_ADR_GOTPAGE. */ - BFD_RELOC_AARCH64_LD64_GOT_LO12_NC, - -/* AArch64 unspecified load/store instruction, holding bits 0 to 11 of the -address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ - BFD_RELOC_AARCH64_LDST_LO12, - -/* AArch64 8-bit load/store instruction, holding bits 0 to 11 of the -address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ - BFD_RELOC_AARCH64_LDST8_LO12, +/* AArch64 26 bit pc-relative unconditional branch and link. +The lowest two bits must be zero and are not stored in the instruction, +giving a 28 bit signed byte offset. */ + BFD_RELOC_AARCH64_CALL26, /* AArch64 16-bit load/store instruction, holding bits 0 to 11 of the address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ @@ -5270,116 +5730,78 @@ address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ BFD_RELOC_AARCH64_LDST128_LO12, -/* AArch64 MOV[NZK] instruction with most significant bits 0 to 15 -of an unsigned address/value. */ - BFD_RELOC_AARCH64_MOVW_G0, - -/* AArch64 MOV[NZ] instruction with most significant bits 0 to 15 -of a signed value. Changes instruction to MOVZ or MOVN depending on the -value's sign. */ - BFD_RELOC_AARCH64_MOVW_G0_S, - -/* AArch64 MOV[NZK] instruction with less significant bits 0 to 15 of -an address/value. No overflow checking. */ - BFD_RELOC_AARCH64_MOVW_G0_NC, - -/* AArch64 MOV[NZK] instruction with most significant bits 16 to 31 -of an unsigned address/value. */ - BFD_RELOC_AARCH64_MOVW_G1, - -/* AArch64 MOV[NZK] instruction with less significant bits 16 to 31 -of an address/value. No overflow checking. */ - BFD_RELOC_AARCH64_MOVW_G1_NC, - -/* AArch64 MOV[NZ] instruction with most significant bits 16 to 31 -of a signed value. Changes instruction to MOVZ or MOVN depending on the -value's sign. */ - BFD_RELOC_AARCH64_MOVW_G1_S, - -/* AArch64 MOV[NZK] instruction with most significant bits 32 to 47 -of an unsigned address/value. */ - BFD_RELOC_AARCH64_MOVW_G2, - -/* AArch64 MOV[NZK] instruction with less significant bits 32 to 47 -of an address/value. No overflow checking. */ - BFD_RELOC_AARCH64_MOVW_G2_NC, - -/* AArch64 MOV[NZ] instruction with most significant bits 32 to 47 -of a signed value. Changes instruction to MOVZ or MOVN depending on the -value's sign. */ - BFD_RELOC_AARCH64_MOVW_G2_S, - -/* AArch64 MOV[NZK] instruction with most signficant bits 48 to 64 -of a signed or unsigned address/value. */ - BFD_RELOC_AARCH64_MOVW_G3, - -/* AArch64 TLS relocation. */ - BFD_RELOC_AARCH64_TLSDESC, - -/* AArch64 TLS DESC relocation. */ - BFD_RELOC_AARCH64_TLSDESC_ADD, - -/* AArch64 TLS DESC relocation. */ - BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC, +/* AArch64 Load Literal instruction, holding a 19 bit PC relative word +offset of the global offset table entry for a symbol. The lowest two +bits must be zero and are not stored in the instruction, giving a 21 +bit signed byte offset. This relocation type requires signed overflow +checking. */ + BFD_RELOC_AARCH64_GOT_LD_PREL19, -/* AArch64 TLS DESC relocation. */ - BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE, +/* Get to the page base of the global offset table entry for a symbol as +part of an ADRP instruction using a 21 bit PC relative value.Used in +conjunction with BFD_RELOC_AARCH64_LD64_GOT_LO12_NC. */ + BFD_RELOC_AARCH64_ADR_GOT_PAGE, -/* AArch64 TLS DESC relocation. */ - BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21, +/* Unsigned 12 bit byte offset for 64 bit load/store from the page of +the GOT entry for this symbol. Used in conjunction with +BFD_RELOC_AARCH64_ADR_GOTPAGE. Valid in LP64 ABI only. */ + BFD_RELOC_AARCH64_LD64_GOT_LO12_NC, -/* AArch64 TLS DESC relocation. */ - BFD_RELOC_AARCH64_TLSDESC_CALL, +/* Unsigned 12 bit byte offset for 32 bit load/store from the page of +the GOT entry for this symbol. Used in conjunction with +BFD_RELOC_AARCH64_ADR_GOTPAGE. Valid in ILP32 ABI only. */ + BFD_RELOC_AARCH64_LD32_GOT_LO12_NC, -/* AArch64 TLS DESC relocation. */ - BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC, +/* Unsigned 15 bit byte offset for 64 bit load/store from the page of +the GOT entry for this symbol. Valid in ILP64 ABI only. */ + BFD_RELOC_AARCH64_LD64_GOTOFF_LO15, -/* AArch64 TLS DESC relocation. */ - BFD_RELOC_AARCH64_TLSDESC_LD64_PREL19, +/* Scaled 14 bit byte offset to the page base of the global offset table. */ + BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14, -/* AArch64 TLS DESC relocation. */ - BFD_RELOC_AARCH64_TLSDESC_LDR, +/* Scaled 15 bit byte offset to the page base of the global offset table. */ + BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15, -/* AArch64 TLS DESC relocation. */ - BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC, +/* Get to the page base of the global offset table entry for a symbols +tls_index structure as part of an adrp instruction using a 21 bit PC +relative value. Used in conjunction with +BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC. */ + BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21, -/* AArch64 TLS DESC relocation. */ - BFD_RELOC_AARCH64_TLSDESC_OFF_G1, +/* AArch64 TLS General Dynamic */ + BFD_RELOC_AARCH64_TLSGD_ADR_PREL21, /* Unsigned 12 bit byte offset to global offset table entry for a symbols tls_index structure. Used in conjunction with BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21. */ BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC, -/* Get to the page base of the global offset table entry for a symbols -tls_index structure as part of an adrp instruction using a 21 bit PC -relative value. Used in conjunction with -BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC. */ - BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21, +/* AArch64 TLS INITIAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1, /* AArch64 TLS INITIAL EXEC relocation. */ - BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, + BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC, /* AArch64 TLS INITIAL EXEC relocation. */ - BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19, + BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, /* AArch64 TLS INITIAL EXEC relocation. */ BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, /* AArch64 TLS INITIAL EXEC relocation. */ - BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC, + BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC, /* AArch64 TLS INITIAL EXEC relocation. */ - BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1, + BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19, /* AArch64 TLS LOCAL EXEC relocation. */ - BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12, + BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2, /* AArch64 TLS LOCAL EXEC relocation. */ - BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12, + BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1, /* AArch64 TLS LOCAL EXEC relocation. */ - BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC, + BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC, /* AArch64 TLS LOCAL EXEC relocation. */ BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0, @@ -5388,27 +5810,100 @@ BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC. */ BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC, /* AArch64 TLS LOCAL EXEC relocation. */ - BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1, + BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12, /* AArch64 TLS LOCAL EXEC relocation. */ - BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC, + BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12, /* AArch64 TLS LOCAL EXEC relocation. */ - BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2, + BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_LD_PREL19, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_OFF_G1, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_LDR, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_ADD, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_CALL, /* AArch64 TLS relocation. */ - BFD_RELOC_AARCH64_TLS_DTPMOD64, + BFD_RELOC_AARCH64_COPY, /* AArch64 TLS relocation. */ - BFD_RELOC_AARCH64_TLS_DTPREL64, + BFD_RELOC_AARCH64_GLOB_DAT, /* AArch64 TLS relocation. */ - BFD_RELOC_AARCH64_TLS_TPREL64, + BFD_RELOC_AARCH64_JUMP_SLOT, -/* AArch64 14 bit pc-relative test bit and branch. -The lowest two bits must be zero and are not stored in the instruction, -giving a 16 bit signed byte offset. */ - BFD_RELOC_AARCH64_TSTBR14, +/* AArch64 TLS relocation. */ + BFD_RELOC_AARCH64_RELATIVE, + +/* AArch64 TLS relocation. */ + BFD_RELOC_AARCH64_TLS_DTPMOD, + +/* AArch64 TLS relocation. */ + BFD_RELOC_AARCH64_TLS_DTPREL, + +/* AArch64 TLS relocation. */ + BFD_RELOC_AARCH64_TLS_TPREL, + +/* AArch64 TLS relocation. */ + BFD_RELOC_AARCH64_TLSDESC, + +/* AArch64 support for STT_GNU_IFUNC. */ + BFD_RELOC_AARCH64_IRELATIVE, + +/* AArch64 pseudo relocation code to mark the end of the AArch64 +relocation enumerators that have direct mapping to ELF reloc codes. +There are a few more enumerators after this one; those are mainly +used by the AArch64 assembler for the internal fixup or to select +one of the above enumerators. */ + BFD_RELOC_AARCH64_RELOC_END, + +/* AArch64 pseudo relocation code to be used internally by the AArch64 +assembler and not (currently) written to any object files. */ + BFD_RELOC_AARCH64_GAS_INTERNAL_FIXUP, + +/* AArch64 unspecified load/store instruction, holding bits 0 to 11 of the +address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ + BFD_RELOC_AARCH64_LDST_LO12, + +/* AArch64 pseudo relocation code to be used internally by the AArch64 +assembler and not (currently) written to any object files. */ + BFD_RELOC_AARCH64_LD_GOT_LO12_NC, + +/* AArch64 pseudo relocation code to be used internally by the AArch64 +assembler and not (currently) written to any object files. */ + BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_LO12_NC, + +/* AArch64 pseudo relocation code to be used internally by the AArch64 +assembler and not (currently) written to any object files. */ + BFD_RELOC_AARCH64_TLSDESC_LD_LO12_NC, /* Tilera TILEPro Relocations. */ BFD_RELOC_TILEPRO_COPY, @@ -5622,7 +6117,17 @@ giving a 16 bit signed byte offset. */ /* Adapteva EPIPHANY - 8 bit immediate for 16 bit mov instruction. */ BFD_RELOC_EPIPHANY_IMM8, + +/* Visium Relocations. */ + BFD_RELOC_VISIUM_HI16, + BFD_RELOC_VISIUM_LO16, + BFD_RELOC_VISIUM_IM16, + BFD_RELOC_VISIUM_REL16, + BFD_RELOC_VISIUM_HI16_PCREL, + BFD_RELOC_VISIUM_LO16_PCREL, + BFD_RELOC_VISIUM_IM16_PCREL, BFD_RELOC_UNUSED }; + typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; reloc_howto_type *bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code); @@ -5820,6 +6325,7 @@ bfd_boolean bfd_copy_private_symbol_data (ibfd, isymbol, obfd, osymbol)) /* Extracted from bfd.c. */ + enum bfd_direction { no_direction = 0, @@ -5828,11 +6334,21 @@ enum bfd_direction both_direction = 3 }; +enum bfd_plugin_format + { + bfd_plugin_uknown = 0, + bfd_plugin_yes = 1, + bfd_plugin_no = 2 + }; + +struct bfd_build_id + { + bfd_size_type size; + bfd_byte data[1]; + }; + struct bfd { - /* A unique identifier of the BFD */ - unsigned int id; - /* The filename the application opened the BFD with. */ const char *filename; @@ -5855,17 +6371,17 @@ struct bfd /* File modified time, if mtime_set is TRUE. */ long mtime; - /* Reserved for an unimplemented file locking extension. */ - int ifd; + /* A unique identifier of the BFD */ + unsigned int id; /* The format which belongs to the BFD. (object, core, etc.) */ - bfd_format format; + ENUM_BITFIELD (bfd_format) format : 3; /* The direction with which the BFD was opened. */ - enum bfd_direction direction; + ENUM_BITFIELD (bfd_direction) direction : 2; /* Format_specific flags. */ - flagword flags; + flagword flags : 18; /* Values that may appear in the flags field of a BFD. These also appear in the object_flags field of the bfd_target structure, where @@ -5924,35 +6440,86 @@ struct bfd struct. */ #define BFD_IN_MEMORY 0x800 - /* The sections in this BFD specify a memory page. */ -#define HAS_LOAD_PAGE 0x1000 - /* This BFD has been created by the linker and doesn't correspond to any input file. */ -#define BFD_LINKER_CREATED 0x2000 +#define BFD_LINKER_CREATED 0x1000 /* This may be set before writing out a BFD to request that it be written using values for UIDs, GIDs, timestamps, etc. that will be consistent from run to run. */ -#define BFD_DETERMINISTIC_OUTPUT 0x4000 +#define BFD_DETERMINISTIC_OUTPUT 0x2000 /* Compress sections in this BFD. */ -#define BFD_COMPRESS 0x8000 +#define BFD_COMPRESS 0x4000 /* Decompress sections in this BFD. */ -#define BFD_DECOMPRESS 0x10000 +#define BFD_DECOMPRESS 0x8000 /* BFD is a dummy, for plugins. */ -#define BFD_PLUGIN 0x20000 +#define BFD_PLUGIN 0x10000 + + /* Compress sections in this BFD with SHF_COMPRESSED from gABI. */ +#define BFD_COMPRESS_GABI 0x20000 /* Flags bits to be saved in bfd_preserve_save. */ #define BFD_FLAGS_SAVED \ - (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN) + (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN \ + | BFD_COMPRESS_GABI) /* Flags bits which are for BFD use only. */ #define BFD_FLAGS_FOR_BFD_USE_MASK \ (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \ - | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT) + | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT \ + | BFD_COMPRESS_GABI) + + /* Is the file descriptor being cached? That is, can it be closed as + needed, and re-opened when accessed later? */ + unsigned int cacheable : 1; + + /* Marks whether there was a default target specified when the + BFD was opened. This is used to select which matching algorithm + to use to choose the back end. */ + unsigned int target_defaulted : 1; + + /* ... and here: (``once'' means at least once). */ + unsigned int opened_once : 1; + + /* Set if we have a locally maintained mtime value, rather than + getting it from the file each time. */ + unsigned int mtime_set : 1; + + /* Flag set if symbols from this BFD should not be exported. */ + unsigned int no_export : 1; + + /* Remember when output has begun, to stop strange things + from happening. */ + unsigned int output_has_begun : 1; + + /* Have archive map. */ + unsigned int has_armap : 1; + + /* Set if this is a thin archive. */ + unsigned int is_thin_archive : 1; + + /* Set if only required symbols should be added in the link hash table for + this object. Used by VMS linkers. */ + unsigned int selective_search : 1; + + /* Set if this is the linker output BFD. */ + unsigned int is_linker_output : 1; + + /* Set if this is the linker input BFD. */ + unsigned int is_linker_input : 1; + + /* If this is an input for a compiler plug-in library. */ + ENUM_BITFIELD (bfd_plugin_format) plugin_format : 2; + + /* Set if this is a plugin output file. */ + unsigned int lto_output : 1; + + /* Set to dummy BFD created when claimed by a compiler plug-in + library. */ + bfd *plugin_dummy_bfd; /* Currently my_archive is tested before adding origin to anything. I believe that this can become always an add of @@ -5978,17 +6545,21 @@ struct bfd /* The number of sections. */ unsigned int section_count; + /* A field used by _bfd_generic_link_add_archive_symbols. This will + be used only for archive elements. */ + int archive_pass; + /* Stuff only useful for object files: The start address. */ bfd_vma start_address; - /* Used for input and output. */ - unsigned int symcount; - /* Symbol table for output BFD (with symcount entries). Also used by the linker to cache input BFD symbols. */ struct bfd_symbol **outsymbols; + /* Used for input and output. */ + unsigned int symcount; + /* Used for slurped dynamic symbol tables. */ unsigned int dynsymcount; @@ -6003,12 +6574,12 @@ struct bfd struct bfd *nested_archives; /* List of nested archive in a flattened thin archive. */ - /* A chain of BFD structures involved in a link. */ - struct bfd *link_next; - - /* A field used by _bfd_generic_link_add_archive_symbols. This will - be used only for archive elements. */ - int archive_pass; + union { + /* For input BFDs, a chain of BFDs involved in a link. */ + struct bfd *next; + /* For output BFD, the linker hash table. */ + struct bfd_link_hash_table *hash; + } link; /* Used by the back end to hold private data. */ union @@ -6061,39 +6632,18 @@ struct bfd of objalloc.h. */ void *memory; - /* Is the file descriptor being cached? That is, can it be closed as - needed, and re-opened when accessed later? */ - unsigned int cacheable : 1; - - /* Marks whether there was a default target specified when the - BFD was opened. This is used to select which matching algorithm - to use to choose the back end. */ - unsigned int target_defaulted : 1; - - /* ... and here: (``once'' means at least once). */ - unsigned int opened_once : 1; - - /* Set if we have a locally maintained mtime value, rather than - getting it from the file each time. */ - unsigned int mtime_set : 1; - - /* Flag set if symbols from this BFD should not be exported. */ - unsigned int no_export : 1; - - /* Remember when output has begun, to stop strange things - from happening. */ - unsigned int output_has_begun : 1; - - /* Have archive map. */ - unsigned int has_armap : 1; + /* For input BFDs, the build ID, if the object has one. */ + const struct bfd_build_id *build_id; +}; - /* Set if this is a thin archive. */ - unsigned int is_thin_archive : 1; +/* See note beside bfd_set_section_userdata. */ +static inline bfd_boolean +bfd_set_cacheable (bfd * abfd, bfd_boolean val) +{ + abfd->cacheable = val; + return TRUE; +} - /* Set if only required symbols should be added in the link hash table for - this object. Used by VMS linkers. */ - unsigned int selective_search : 1; -}; typedef enum bfd_error { @@ -6108,6 +6658,7 @@ typedef enum bfd_error bfd_error_no_armap, bfd_error_no_more_archived_files, bfd_error_malformed_archive, + bfd_error_missing_dso, bfd_error_file_not_recognized, bfd_error_file_ambiguously_recognized, bfd_error_no_contents, @@ -6129,6 +6680,7 @@ const char *bfd_errmsg (bfd_error_type error_tag); void bfd_perror (const char *message); + typedef void (*bfd_error_handler_type) (const char *, ...); bfd_error_handler_type bfd_set_error_handler (bfd_error_handler_type); @@ -6137,6 +6689,7 @@ void bfd_set_error_program_name (const char *); bfd_error_handler_type bfd_get_error_handler (void); + typedef void (*bfd_assert_handler_type) (const char *bfd_formatmsg, const char *bfd_version, const char *bfd_file, @@ -6192,12 +6745,12 @@ bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags); #define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ BFD_SEND (abfd, _bfd_find_nearest_line, \ - (abfd, sec, syms, off, file, func, line)) + (abfd, syms, sec, off, file, func, line, NULL)) #define bfd_find_nearest_line_discriminator(abfd, sec, syms, off, file, func, \ line, disc) \ - BFD_SEND (abfd, _bfd_find_nearest_line_discriminator, \ - (abfd, sec, syms, off, file, func, line, disc)) + BFD_SEND (abfd, _bfd_find_nearest_line, \ + (abfd, syms, sec, off, file, func, line, disc)) #define bfd_find_line(abfd, syms, sym, file, line) \ BFD_SEND (abfd, _bfd_find_line, \ @@ -6246,9 +6799,6 @@ bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags); #define bfd_link_hash_table_create(abfd) \ BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) -#define bfd_link_hash_table_free(abfd, hash) \ - BFD_SEND (abfd, _bfd_link_hash_table_free, (hash)) - #define bfd_link_add_symbols(abfd, info) \ BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info)) @@ -6296,6 +6846,15 @@ void bfd_emul_set_commonpagesize (const char *, bfd_vma); char *bfd_demangle (bfd *, const char *, int); +void bfd_update_compression_header + (bfd *abfd, bfd_byte *contents, asection *sec); + +bfd_boolean bfd_check_compression_header + (bfd *abfd, bfd_byte *contents, asection *sec, + bfd_size_type *uncompressed_size); + +int bfd_get_compression_header_size (bfd *abfd, asection *sec); + /* Extracted from archive.c. */ symindex bfd_get_next_mapent (bfd *abfd, symindex previous, carsym **sym); @@ -6558,12 +7117,12 @@ typedef struct bfd_target NAME##_make_empty_symbol, \ NAME##_print_symbol, \ NAME##_get_symbol_info, \ + NAME##_get_symbol_version_string, \ NAME##_bfd_is_local_label_name, \ NAME##_bfd_is_target_special_symbol, \ NAME##_get_lineno, \ NAME##_find_nearest_line, \ - _bfd_generic_find_nearest_line_discriminator, \ - _bfd_generic_find_line, \ + NAME##_find_line, \ NAME##_find_inliner_info, \ NAME##_bfd_make_debug_symbol, \ NAME##_read_minisymbols, \ @@ -6580,14 +7139,14 @@ typedef struct bfd_target void (*_bfd_get_symbol_info) (bfd *, struct bfd_symbol *, symbol_info *); #define bfd_get_symbol_info(b,p,e) BFD_SEND (b, _bfd_get_symbol_info, (b,p,e)) + const char *(*_bfd_get_symbol_version_string) + (bfd *, struct bfd_symbol *, bfd_boolean *); +#define bfd_get_symbol_version_string(b,s,h) BFD_SEND (b, _bfd_get_symbol_version_string, (b,s,h)) bfd_boolean (*_bfd_is_local_label_name) (bfd *, const char *); bfd_boolean (*_bfd_is_target_special_symbol) (bfd *, asymbol *); alent * (*_get_lineno) (bfd *, struct bfd_symbol *); bfd_boolean (*_bfd_find_nearest_line) - (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, - const char **, const char **, unsigned int *); - bfd_boolean (*_bfd_find_nearest_line_discriminator) - (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, + (bfd *, struct bfd_symbol **, struct bfd_section *, bfd_vma, const char **, const char **, unsigned int *, unsigned int *); bfd_boolean (*_bfd_find_line) (bfd *, struct bfd_symbol **, struct bfd_symbol *, @@ -6641,7 +7200,6 @@ typedef struct bfd_target NAME##_bfd_get_relocated_section_contents, \ NAME##_bfd_relax_section, \ NAME##_bfd_link_hash_table_create, \ - NAME##_bfd_link_hash_table_free, \ NAME##_bfd_link_add_symbols, \ NAME##_bfd_link_just_syms, \ NAME##_bfd_copy_link_hash_symbol_type, \ @@ -6668,16 +7226,14 @@ typedef struct bfd_target struct bfd_link_hash_table * (*_bfd_link_hash_table_create) (bfd *); - /* Release the memory associated with the linker hash table. */ - void (*_bfd_link_hash_table_free) (struct bfd_link_hash_table *); - /* Add symbols from this object file into the hash table. */ bfd_boolean (*_bfd_link_add_symbols) (bfd *, struct bfd_link_info *); /* Indicate that we are only retrieving symbol values from this section. */ void (*_bfd_link_just_syms) (asection *, struct bfd_link_info *); - /* Copy the symbol type of a linker hash table entry. */ + /* Copy the symbol type and other attributes for a linker script + assignment of one symbol to another. */ #define bfd_copy_link_hash_symbol_type(b, t, f) \ BFD_SEND (b, _bfd_copy_link_hash_symbol_type, (b, t, f)) void (*_bfd_copy_link_hash_symbol_type) @@ -6805,16 +7361,17 @@ bfd_byte *bfd_simple_get_relocated_section_contents (bfd *abfd, asection *sec, bfd_byte *outbuf, asymbol **symbol_table); /* Extracted from compress.c. */ -bfd_boolean bfd_compress_section_contents - (bfd *abfd, asection *section, bfd_byte *uncompressed_buffer, - bfd_size_type uncompressed_size); - bfd_boolean bfd_get_full_section_contents (bfd *abfd, asection *section, bfd_byte **ptr); void bfd_cache_section_contents (asection *sec, void *contents); +bfd_boolean bfd_is_section_compressed_with_header + (bfd *abfd, asection *section, + int *compression_header_size_p, + bfd_size_type *uncompressed_size_p); + bfd_boolean bfd_is_section_compressed (bfd *abfd, asection *section); @@ -6824,6 +7381,9 @@ bfd_boolean bfd_init_section_decompress_status bfd_boolean bfd_init_section_compress_status (bfd *abfd, asection *section); +bfd_boolean bfd_compress_section + (bfd *abfd, asection *section, bfd_byte *uncompressed_buffer); + #ifdef __cplusplus } #endif diff --git a/contrib/gdb-7/bfd/bfd.c b/contrib/gdb-7/bfd/bfd.c index d77b90f931..8d85de50b9 100644 --- a/contrib/gdb-7/bfd/bfd.c +++ b/contrib/gdb-7/bfd/bfd.c @@ -1,7 +1,5 @@ /* Generic BFD library interface and support routines. - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + Copyright (C) 1990-2015 Free Software Foundation, Inc. Written by Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -22,6 +20,9 @@ MA 02110-1301, USA. */ /* +INODE +typedef bfd, Error reporting, BFD front end, BFD front end + SECTION <> @@ -43,11 +44,21 @@ CODE_FRAGMENT . both_direction = 3 . }; . +.enum bfd_plugin_format +. { +. bfd_plugin_uknown = 0, +. bfd_plugin_yes = 1, +. bfd_plugin_no = 2 +. }; +. +.struct bfd_build_id +. { +. bfd_size_type size; +. bfd_byte data[1]; +. }; +. .struct bfd .{ -. {* A unique identifier of the BFD *} -. unsigned int id; -. . {* The filename the application opened the BFD with. *} . const char *filename; . @@ -70,17 +81,17 @@ CODE_FRAGMENT . {* File modified time, if mtime_set is TRUE. *} . long mtime; . -. {* Reserved for an unimplemented file locking extension. *} -. int ifd; +. {* A unique identifier of the BFD *} +. unsigned int id; . . {* The format which belongs to the BFD. (object, core, etc.) *} -. bfd_format format; +. ENUM_BITFIELD (bfd_format) format : 3; . . {* The direction with which the BFD was opened. *} -. enum bfd_direction direction; +. ENUM_BITFIELD (bfd_direction) direction : 2; . . {* Format_specific flags. *} -. flagword flags; +. flagword flags : 18; . . {* Values that may appear in the flags field of a BFD. These also . appear in the object_flags field of the bfd_target structure, where @@ -139,35 +150,86 @@ CODE_FRAGMENT . struct. *} .#define BFD_IN_MEMORY 0x800 . -. {* The sections in this BFD specify a memory page. *} -.#define HAS_LOAD_PAGE 0x1000 -. . {* This BFD has been created by the linker and doesn't correspond . to any input file. *} -.#define BFD_LINKER_CREATED 0x2000 +.#define BFD_LINKER_CREATED 0x1000 . . {* This may be set before writing out a BFD to request that it . be written using values for UIDs, GIDs, timestamps, etc. that . will be consistent from run to run. *} -.#define BFD_DETERMINISTIC_OUTPUT 0x4000 +.#define BFD_DETERMINISTIC_OUTPUT 0x2000 . . {* Compress sections in this BFD. *} -.#define BFD_COMPRESS 0x8000 +.#define BFD_COMPRESS 0x4000 . . {* Decompress sections in this BFD. *} -.#define BFD_DECOMPRESS 0x10000 +.#define BFD_DECOMPRESS 0x8000 . . {* BFD is a dummy, for plugins. *} -.#define BFD_PLUGIN 0x20000 +.#define BFD_PLUGIN 0x10000 +. +. {* Compress sections in this BFD with SHF_COMPRESSED from gABI. *} +.#define BFD_COMPRESS_GABI 0x20000 . . {* Flags bits to be saved in bfd_preserve_save. *} .#define BFD_FLAGS_SAVED \ -. (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN) +. (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN \ +. | BFD_COMPRESS_GABI) . . {* Flags bits which are for BFD use only. *} .#define BFD_FLAGS_FOR_BFD_USE_MASK \ . (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \ -. | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT) +. | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT \ +. | BFD_COMPRESS_GABI) +. +. {* Is the file descriptor being cached? That is, can it be closed as +. needed, and re-opened when accessed later? *} +. unsigned int cacheable : 1; +. +. {* Marks whether there was a default target specified when the +. BFD was opened. This is used to select which matching algorithm +. to use to choose the back end. *} +. unsigned int target_defaulted : 1; +. +. {* ... and here: (``once'' means at least once). *} +. unsigned int opened_once : 1; +. +. {* Set if we have a locally maintained mtime value, rather than +. getting it from the file each time. *} +. unsigned int mtime_set : 1; +. +. {* Flag set if symbols from this BFD should not be exported. *} +. unsigned int no_export : 1; +. +. {* Remember when output has begun, to stop strange things +. from happening. *} +. unsigned int output_has_begun : 1; +. +. {* Have archive map. *} +. unsigned int has_armap : 1; +. +. {* Set if this is a thin archive. *} +. unsigned int is_thin_archive : 1; +. +. {* Set if only required symbols should be added in the link hash table for +. this object. Used by VMS linkers. *} +. unsigned int selective_search : 1; +. +. {* Set if this is the linker output BFD. *} +. unsigned int is_linker_output : 1; +. +. {* Set if this is the linker input BFD. *} +. unsigned int is_linker_input : 1; +. +. {* If this is an input for a compiler plug-in library. *} +. ENUM_BITFIELD (bfd_plugin_format) plugin_format : 2; +. +. {* Set if this is a plugin output file. *} +. unsigned int lto_output : 1; +. +. {* Set to dummy BFD created when claimed by a compiler plug-in +. library. *} +. bfd *plugin_dummy_bfd; . . {* Currently my_archive is tested before adding origin to . anything. I believe that this can become always an add of @@ -193,17 +255,21 @@ CODE_FRAGMENT . {* The number of sections. *} . unsigned int section_count; . +. {* A field used by _bfd_generic_link_add_archive_symbols. This will +. be used only for archive elements. *} +. int archive_pass; +. . {* Stuff only useful for object files: . The start address. *} . bfd_vma start_address; . -. {* Used for input and output. *} -. unsigned int symcount; -. . {* Symbol table for output BFD (with symcount entries). . Also used by the linker to cache input BFD symbols. *} . struct bfd_symbol **outsymbols; . +. {* Used for input and output. *} +. unsigned int symcount; +. . {* Used for slurped dynamic symbol tables. *} . unsigned int dynsymcount; . @@ -218,12 +284,12 @@ CODE_FRAGMENT . struct bfd *nested_archives; {* List of nested archive in a flattened . thin archive. *} . -. {* A chain of BFD structures involved in a link. *} -. struct bfd *link_next; -. -. {* A field used by _bfd_generic_link_add_archive_symbols. This will -. be used only for archive elements. *} -. int archive_pass; +. union { +. {* For input BFDs, a chain of BFDs involved in a link. *} +. struct bfd *next; +. {* For output BFD, the linker hash table. *} +. struct bfd_link_hash_table *hash; +. } link; . . {* Used by the back end to hold private data. *} . union @@ -276,40 +342,18 @@ CODE_FRAGMENT . of objalloc.h. *} . void *memory; . -. {* Is the file descriptor being cached? That is, can it be closed as -. needed, and re-opened when accessed later? *} -. unsigned int cacheable : 1; -. -. {* Marks whether there was a default target specified when the -. BFD was opened. This is used to select which matching algorithm -. to use to choose the back end. *} -. unsigned int target_defaulted : 1; -. -. {* ... and here: (``once'' means at least once). *} -. unsigned int opened_once : 1; -. -. {* Set if we have a locally maintained mtime value, rather than -. getting it from the file each time. *} -. unsigned int mtime_set : 1; -. -. {* Flag set if symbols from this BFD should not be exported. *} -. unsigned int no_export : 1; -. -. {* Remember when output has begun, to stop strange things -. from happening. *} -. unsigned int output_has_begun : 1; -. -. {* Have archive map. *} -. unsigned int has_armap : 1; -. -. {* Set if this is a thin archive. *} -. unsigned int is_thin_archive : 1; -. -. {* Set if only required symbols should be added in the link hash table for -. this object. Used by VMS linkers. *} -. unsigned int selective_search : 1; +. {* For input BFDs, the build ID, if the object has one. *} +. const struct bfd_build_id *build_id; .}; . +.{* See note beside bfd_set_section_userdata. *} +.static inline bfd_boolean +.bfd_set_cacheable (bfd * abfd, bfd_boolean val) +.{ +. abfd->cacheable = val; +. return TRUE; +.} +. */ #include "sysdep.h" @@ -340,6 +384,9 @@ CODE_FRAGMENT where it is needed. The typedef's used are defined in bfd.h */ /* +INODE +Error reporting, Miscellaneous, typedef bfd, BFD front end + SECTION Error reporting @@ -374,6 +421,7 @@ CODE_FRAGMENT . bfd_error_no_armap, . bfd_error_no_more_archived_files, . bfd_error_malformed_archive, +. bfd_error_missing_dso, . bfd_error_file_not_recognized, . bfd_error_file_ambiguously_recognized, . bfd_error_no_contents, @@ -406,6 +454,7 @@ const char *const bfd_errmsgs[] = N_("Archive has no index; run ranlib to add one"), N_("No more archived files"), N_("Malformed archive"), + N_("DSO missing from command line"), N_("File format not recognized"), N_("File format is ambiguous"), N_("Section has no contents"), @@ -727,7 +776,9 @@ _bfd_default_error_handler (const char *fmt, ...) vfprintf (stderr, new_fmt, ap); va_end (ap); - putc ('\n', stderr); + /* On AIX, putc is implemented as a macro that triggers a -Wunused-value + warning, so use the fputc function to avoid it. */ + fputc ('\n', stderr); fflush (stderr); } @@ -881,6 +932,9 @@ bfd_get_assert_handler (void) } /* +INODE +Miscellaneous, Memory Usage, Error reporting, BFD front end + SECTION Miscellaneous @@ -1054,9 +1108,11 @@ SYNOPSIS int bfd_get_arch_size (bfd *abfd); DESCRIPTION - Returns the architecture address size, in bits, as determined - by the object file's format. For ELF, this information is - included in the header. + Returns the normalized architecture address size, in bits, as + determined by the object file's format. By normalized, we mean + either 32 or 64. For ELF, this information is included in the + header. Use bfd_arch_bits_per_address for number of bits in + the architecture address. RETURNS Returns the arch size in bits if known, <<-1>> otherwise. @@ -1068,7 +1124,7 @@ bfd_get_arch_size (bfd *abfd) if (abfd->xvec->flavour == bfd_target_elf_flavour) return get_elf_backend_data (abfd)->s->arch_size; - return -1; + return bfd_arch_bits_per_address (abfd) > 32 ? 64 : 32; } /* @@ -1422,12 +1478,12 @@ DESCRIPTION . .#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ . BFD_SEND (abfd, _bfd_find_nearest_line, \ -. (abfd, sec, syms, off, file, func, line)) +. (abfd, syms, sec, off, file, func, line, NULL)) . .#define bfd_find_nearest_line_discriminator(abfd, sec, syms, off, file, func, \ . line, disc) \ -. BFD_SEND (abfd, _bfd_find_nearest_line_discriminator, \ -. (abfd, sec, syms, off, file, func, line, disc)) +. BFD_SEND (abfd, _bfd_find_nearest_line, \ +. (abfd, syms, sec, off, file, func, line, disc)) . .#define bfd_find_line(abfd, syms, sym, file, line) \ . BFD_SEND (abfd, _bfd_find_line, \ @@ -1476,9 +1532,6 @@ DESCRIPTION .#define bfd_link_hash_table_create(abfd) \ . BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) . -.#define bfd_link_hash_table_free(abfd, hash) \ -. BFD_SEND (abfd, _bfd_link_hash_table_free, (hash)) -. .#define bfd_link_add_symbols(abfd, info) \ . BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info)) . @@ -1904,3 +1957,157 @@ bfd_demangle (bfd *abfd, const char *name, int options) return res; } + +/* +FUNCTION + bfd_update_compression_header + +SYNOPSIS + void bfd_update_compression_header + (bfd *abfd, bfd_byte *contents, asection *sec); + +DESCRIPTION + Set the compression header at CONTENTS of SEC in ABFD and update + elf_section_flags for compression. +*/ + +void +bfd_update_compression_header (bfd *abfd, bfd_byte *contents, + asection *sec) +{ + if ((abfd->flags & BFD_COMPRESS) != 0) + { + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + { + if ((abfd->flags & BFD_COMPRESS_GABI) != 0) + { + const struct elf_backend_data *bed + = get_elf_backend_data (abfd); + + /* Set the SHF_COMPRESSED bit. */ + elf_section_flags (sec) |= SHF_COMPRESSED; + + if (bed->s->elfclass == ELFCLASS32) + { + Elf32_External_Chdr *echdr + = (Elf32_External_Chdr *) contents; + bfd_put_32 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type); + bfd_put_32 (abfd, sec->size, &echdr->ch_size); + bfd_put_32 (abfd, 1 << sec->alignment_power, + &echdr->ch_addralign); + } + else + { + Elf64_External_Chdr *echdr + = (Elf64_External_Chdr *) contents; + bfd_put_64 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type); + bfd_put_64 (abfd, sec->size, &echdr->ch_size); + bfd_put_64 (abfd, 1 << sec->alignment_power, + &echdr->ch_addralign); + } + } + else + { + /* Clear the SHF_COMPRESSED bit. */ + elf_section_flags (sec) &= ~SHF_COMPRESSED; + + /* Write the zlib header. It should be "ZLIB" followed by + the uncompressed section size, 8 bytes in big-endian + order. */ + memcpy (contents, "ZLIB", 4); + bfd_putb64 (sec->size, contents + 4); + } + } + } + else + abort (); +} + +/* + FUNCTION + bfd_check_compression_header + + SYNOPSIS + bfd_boolean bfd_check_compression_header + (bfd *abfd, bfd_byte *contents, asection *sec, + bfd_size_type *uncompressed_size); + +DESCRIPTION + Check the compression header at CONTENTS of SEC in ABFD and + store the uncompressed size in UNCOMPRESSED_SIZE if the + compression header is valid. + +RETURNS + Return TRUE if the compression header is valid. +*/ + +bfd_boolean +bfd_check_compression_header (bfd *abfd, bfd_byte *contents, + asection *sec, + bfd_size_type *uncompressed_size) +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && (elf_section_flags (sec) & SHF_COMPRESSED) != 0) + { + Elf_Internal_Chdr chdr; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + if (bed->s->elfclass == ELFCLASS32) + { + Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) contents; + chdr.ch_type = bfd_get_32 (abfd, &echdr->ch_type); + chdr.ch_size = bfd_get_32 (abfd, &echdr->ch_size); + chdr.ch_addralign = bfd_get_32 (abfd, &echdr->ch_addralign); + } + else + { + Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) contents; + chdr.ch_type = bfd_get_64 (abfd, &echdr->ch_type); + chdr.ch_size = bfd_get_64 (abfd, &echdr->ch_size); + chdr.ch_addralign = bfd_get_64 (abfd, &echdr->ch_addralign); + } + if (chdr.ch_type == ELFCOMPRESS_ZLIB + && chdr.ch_addralign == 1U << sec->alignment_power) + { + *uncompressed_size = chdr.ch_size; + return TRUE; + } + } + + return FALSE; +} + +/* +FUNCTION + bfd_get_compression_header_size + +SYNOPSIS + int bfd_get_compression_header_size (bfd *abfd, asection *sec); + +DESCRIPTION + Return the size of the compression header of SEC in ABFD. + +RETURNS + Return the size of the compression header in bytes. +*/ + +int +bfd_get_compression_header_size (bfd *abfd, asection *sec) +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + { + if (sec == NULL) + { + if (!(abfd->flags & BFD_COMPRESS_GABI)) + return 0; + } + else if (!(elf_section_flags (sec) & SHF_COMPRESSED)) + return 0; + + if (get_elf_backend_data (abfd)->s->elfclass == ELFCLASS32) + return sizeof (Elf32_External_Chdr); + else + return sizeof (Elf64_External_Chdr); + } + + return 0; +} diff --git a/contrib/gdb-7/bfd/bfdio.c b/contrib/gdb-7/bfd/bfdio.c index be05581aeb..89406e3c73 100644 --- a/contrib/gdb-7/bfd/bfdio.c +++ b/contrib/gdb-7/bfd/bfdio.c @@ -1,8 +1,6 @@ /* Low-level I/O routines for BFDs. - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 - Free Software Foundation, Inc. + Copyright (C) 1990-2015 Free Software Foundation, Inc. Written by Cygnus Support. @@ -89,7 +87,7 @@ real_fopen (const char *filename, const char *modes) #ifdef VMS char *vms_attr; - /* On VMS, fopen allows file attributes as optionnal arguments. + /* On VMS, fopen allows file attributes as optional arguments. We need to use them but we'd better to use the common prototype. In fopen-vms.h, they are separated from the mode with a comma. Split here. */ diff --git a/contrib/gdb-7/bfd/bfdwin.c b/contrib/gdb-7/bfd/bfdwin.c index 4103e9c2f5..d133656ab4 100644 --- a/contrib/gdb-7/bfd/bfdwin.c +++ b/contrib/gdb-7/bfd/bfdwin.c @@ -1,6 +1,5 @@ /* Support for memory-mapped windows into a BFD. - Copyright 1995, 1996, 2001, 2002, 2003, 2005, 2007, 2008, 2009, 2011 - Free Software Foundation, Inc. + Copyright (C) 1995-2015 Free Software Foundation, Inc. Written by Cygnus Support. This file is part of BFD, the Binary File Descriptor library. diff --git a/contrib/gdb-7/bfd/binary.c b/contrib/gdb-7/bfd/binary.c index 700c862f93..9ed61aa9c5 100644 --- a/contrib/gdb-7/bfd/binary.c +++ b/contrib/gdb-7/bfd/binary.c @@ -1,6 +1,5 @@ /* BFD back-end for binary objects. - Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007, 2009, 2011 Free Software Foundation, Inc. + Copyright (C) 1994-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support, This file is part of BFD, the Binary File Descriptor library. @@ -191,6 +190,8 @@ binary_canonicalize_symtab (bfd *abfd, asymbol **alocation) #define binary_make_empty_symbol _bfd_generic_make_empty_symbol #define binary_print_symbol _bfd_nosymbols_print_symbol +#define binary_get_symbol_version_string \ + _bfd_nosymbols_get_symbol_version_string /* Get information about a symbol. */ @@ -205,6 +206,7 @@ binary_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED, #define binary_bfd_is_local_label_name bfd_generic_is_local_label_name #define binary_get_lineno _bfd_nosymbols_get_lineno #define binary_find_nearest_line _bfd_nosymbols_find_nearest_line +#define binary_find_line _bfd_nosymbols_find_line #define binary_find_inliner_info _bfd_nosymbols_find_inliner_info #define binary_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol #define binary_read_minisymbols _bfd_generic_read_minisymbols @@ -306,7 +308,6 @@ binary_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, #define binary_section_already_linked _bfd_generic_section_already_linked #define binary_bfd_define_common_symbol bfd_generic_define_common_symbol #define binary_bfd_link_hash_table_create _bfd_generic_link_hash_table_create -#define binary_bfd_link_hash_table_free _bfd_generic_link_hash_table_free #define binary_bfd_link_just_syms _bfd_generic_link_just_syms #define binary_bfd_copy_link_hash_symbol_type \ _bfd_generic_copy_link_hash_symbol_type diff --git a/contrib/gdb-7/bfd/cache.c b/contrib/gdb-7/bfd/cache.c index 52268162c2..94a82daff0 100644 --- a/contrib/gdb-7/bfd/cache.c +++ b/contrib/gdb-7/bfd/cache.c @@ -1,7 +1,6 @@ /* BFD library -- caching of file descriptors. - Copyright 1990, 1991, 1992, 1993, 1994, 1996, 2000, 2001, 2002, - 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 1990-2015 Free Software Foundation, Inc. Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com). @@ -31,7 +30,7 @@ SECTION regard to the underlying operating system's file descriptor limit (often as low as 20 open files). The module in <> maintains a least recently used list of - <> files, and exports the name + <> files, and exports the name <>, which runs around and makes sure that the required BFD is open. If not, then it chooses a file to close, closes it and opens the one wanted, returning its file @@ -67,9 +66,35 @@ enum cache_flag { }; /* The maximum number of files which the cache will keep open at - one time. */ + one time. When needed call bfd_cache_max_open to initialize. */ -#define BFD_CACHE_MAX_OPEN 10 +static int max_open_files = 0; + +/* Set max_open_files, if not already set, to 12.5% of the allowed open + file descriptors, but at least 10, and return the value. */ +static int +bfd_cache_max_open (void) +{ + if (max_open_files == 0) + { + int max; +#ifdef HAVE_GETRLIMIT + struct rlimit rlim; + if (getrlimit (RLIMIT_NOFILE, &rlim) == 0 + && rlim.rlim_cur != (rlim_t) RLIM_INFINITY) + max = rlim.rlim_cur / 8; + else +#endif /* HAVE_GETRLIMIT */ +#ifdef _SC_OPEN_MAX + max = sysconf (_SC_OPEN_MAX) / 8; +#else + max = 10; +#endif /* _SC_OPEN_MAX */ + max_open_files = max < 10 ? 10 : max; + } + + return max_open_files; +} /* The number of BFD files we have open. */ @@ -187,7 +212,7 @@ close_one (void) /* Called when the macro <> fails to find a quick answer. Find a file descriptor for @var{abfd}. If necessary, it open it. If there are already more than - <> files open, it tries to close one first, to + <> files open, it tries to close one first, to avoid running out of file descriptors. It will return NULL if it is unable to (re)open the @var{abfd}. */ @@ -285,7 +310,7 @@ cache_bread_1 (struct bfd *abfd, void *buf, file_ptr nbytes) if (nread == (file_ptr)-1) { bfd_set_error (bfd_error_system_call); - return -1; + return nread; } #else nread = fread (buf, 1, nbytes, f); @@ -295,7 +320,7 @@ cache_bread_1 (struct bfd *abfd, void *buf, file_ptr nbytes) if (nread < nbytes && ferror (f)) { bfd_set_error (bfd_error_system_call); - return -1; + return nread; } #endif if (nread < nbytes) @@ -466,7 +491,7 @@ bfd_boolean bfd_cache_init (bfd *abfd) { BFD_ASSERT (abfd->iostream != NULL); - if (open_files >= BFD_CACHE_MAX_OPEN) + if (open_files >= bfd_cache_max_open ()) { if (! close_one ()) return FALSE; @@ -553,7 +578,7 @@ bfd_open_file (bfd *abfd) { abfd->cacheable = TRUE; /* Allow it to be closed later. */ - if (open_files >= BFD_CACHE_MAX_OPEN) + if (open_files >= bfd_cache_max_open ()) { if (! close_one ()) return NULL; diff --git a/contrib/gdb-7/bfd/coff-bfd.c b/contrib/gdb-7/bfd/coff-bfd.c new file mode 100644 index 0000000000..21337bf76e --- /dev/null +++ b/contrib/gdb-7/bfd/coff-bfd.c @@ -0,0 +1,99 @@ +/* BFD COFF interfaces used outside of BFD. + Copyright (C) 1990-2015 Free Software Foundation, Inc. + Written by Cygnus Support. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "libcoff.h" + +/* Return the COFF syment for a symbol. */ + +bfd_boolean +bfd_coff_get_syment (bfd *abfd, + asymbol *symbol, + struct internal_syment *psyment) +{ + coff_symbol_type *csym; + + csym = coff_symbol_from (symbol); + if (csym == NULL || csym->native == NULL + || ! csym->native->is_sym) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + *psyment = csym->native->u.syment; + + if (csym->native->fix_value) + psyment->n_value = psyment->n_value - + (bfd_hostptr_t) obj_raw_syments (abfd); + + /* FIXME: We should handle fix_line here. */ + + return TRUE; +} + +/* Return the COFF auxent for a symbol. */ + +bfd_boolean +bfd_coff_get_auxent (bfd *abfd, + asymbol *symbol, + int indx, + union internal_auxent *pauxent) +{ + coff_symbol_type *csym; + combined_entry_type *ent; + + csym = coff_symbol_from (symbol); + + if (csym == NULL + || csym->native == NULL + || ! csym->native->is_sym + || indx >= csym->native->u.syment.n_numaux) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + ent = csym->native + indx + 1; + + BFD_ASSERT (! ent->is_sym); + *pauxent = ent->u.auxent; + + if (ent->fix_tag) + pauxent->x_sym.x_tagndx.l = + ((combined_entry_type *) pauxent->x_sym.x_tagndx.p + - obj_raw_syments (abfd)); + + if (ent->fix_end) + pauxent->x_sym.x_fcnary.x_fcn.x_endndx.l = + ((combined_entry_type *) pauxent->x_sym.x_fcnary.x_fcn.x_endndx.p + - obj_raw_syments (abfd)); + + if (ent->fix_scnlen) + pauxent->x_csect.x_scnlen.l = + ((combined_entry_type *) pauxent->x_csect.x_scnlen.p + - obj_raw_syments (abfd)); + + return TRUE; +} diff --git a/contrib/gdb-7/bfd/coff-bfd.h b/contrib/gdb-7/bfd/coff-bfd.h new file mode 100644 index 0000000000..1ca5f69f91 --- /dev/null +++ b/contrib/gdb-7/bfd/coff-bfd.h @@ -0,0 +1,86 @@ +/* BFD COFF interfaces used outside of BFD. + Copyright (C) 1990-2015 Free Software Foundation, Inc. + Written by Cygnus Support. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 structure is used for a comdat section, as in PE. A comdat + section is associated with a particular symbol. When the linker + sees a comdat section, it keeps only one of the sections with a + given name and associated with a given symbol. */ + +struct coff_comdat_info +{ + /* The name of the symbol associated with a comdat section. */ + const char *name; + + /* The local symbol table index of the symbol associated with a + comdat section. This is only meaningful to the object file format + specific code; it is not an index into the list returned by + bfd_canonicalize_symtab. */ + long symbol; +}; + +/* The used_by_bfd field of a section may be set to a pointer to this + structure. */ + +struct coff_section_tdata +{ + /* The relocs, swapped into COFF internal form. This may be NULL. */ + struct internal_reloc *relocs; + /* If this is TRUE, the relocs entry may not be freed. */ + bfd_boolean keep_relocs; + /* The section contents. This may be NULL. */ + bfd_byte *contents; + /* If this is TRUE, the contents entry may not be freed. */ + bfd_boolean keep_contents; + /* Information cached by coff_find_nearest_line. */ + bfd_vma offset; + unsigned int i; + const char *function; + /* Optional information about a COMDAT entry; NULL if not COMDAT. */ + struct coff_comdat_info *comdat; + int line_base; + /* A pointer used for .stab linking optimizations. */ + void * stab_info; + /* Available for individual backends. */ + void * tdata; +}; + +/* An accessor macro for the coff_section_tdata structure. */ +#define coff_section_data(abfd, sec) \ + ((struct coff_section_tdata *) (sec)->used_by_bfd) + +#define bfd_coff_get_comdat_section(abfd, sec) \ + ((bfd_get_flavour (abfd) == bfd_target_coff_flavour \ + && coff_section_data (abfd, sec) != NULL) \ + ? coff_section_data (abfd, sec)->comdat : NULL) + +#define coff_symbol_from(symbol) \ + ((bfd_family_coff (bfd_asymbol_bfd (symbol)) \ + && bfd_asymbol_bfd (symbol)->tdata.coff_obj_data) \ + ? (coff_symbol_type *) (symbol) : NULL) + +struct internal_syment; +union internal_auxent; + +extern bfd_boolean bfd_coff_get_syment + (bfd *, struct bfd_symbol *, struct internal_syment *); + +extern bfd_boolean bfd_coff_get_auxent + (bfd *, struct bfd_symbol *, int, union internal_auxent *); diff --git a/contrib/gdb-7/bfd/coffgen.c b/contrib/gdb-7/bfd/coffgen.c index 7d48ea9cf6..481e4a5c91 100644 --- a/contrib/gdb-7/bfd/coffgen.c +++ b/contrib/gdb-7/bfd/coffgen.c @@ -1,7 +1,5 @@ /* Support for the generic parts of COFF, for BFD. - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 - Free Software Foundation, Inc. + Copyright (C) 1990-2015 Free Software Foundation, Inc. Written by Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -86,9 +84,8 @@ make_a_section_from_file (bfd *abfd, strings = _bfd_coff_read_string_table (abfd); if (strings == NULL) return FALSE; - /* FIXME: For extra safety, we should make sure that - strindex does not run us past the end, but right now we - don't know the length of the string table. */ + if ((bfd_size_type)(strindex + 2) >= obj_coff_strings_len (abfd)) + return FALSE; strings += strindex; name = (char *) bfd_alloc (abfd, (bfd_size_type) strlen (strings) + 1 + 1); @@ -149,8 +146,9 @@ make_a_section_from_file (bfd *abfd, /* Compress/decompress DWARF debug sections with names: .debug_* and .zdebug_*, after the section flags is set. */ if ((flags & SEC_DEBUGGING) + && strlen (name) > 7 && ((name[1] == 'd' && name[6] == '_') - || (name[1] == 'z' && name[7] == '_'))) + || (strlen (name) > 8 && name[1] == 'z' && name[7] == '_'))) { enum { nothing, compress, decompress } action = nothing; char *new_name = NULL; @@ -180,18 +178,21 @@ make_a_section_from_file (bfd *abfd, abfd, name); return FALSE; } - if (name[1] != 'z') + if (return_section->compress_status == COMPRESS_SECTION_DONE) { - unsigned int len = strlen (name); + if (name[1] != 'z') + { + unsigned int len = strlen (name); - new_name = bfd_alloc (abfd, len + 2); - if (new_name == NULL) - return FALSE; - new_name[0] = '.'; - new_name[1] = 'z'; - memcpy (new_name + 2, name + 1, len); + new_name = bfd_alloc (abfd, len + 2); + if (new_name == NULL) + return FALSE; + new_name[0] = '.'; + new_name[1] = 'z'; + memcpy (new_name + 2, name + 1, len); + } } - break; + break; case decompress: if (!bfd_init_section_decompress_status (abfd, return_section)) { @@ -221,8 +222,12 @@ make_a_section_from_file (bfd *abfd, /* Read in a COFF object and make it into a BFD. This is used by ECOFF as well. */ - -static const bfd_target * +const bfd_target * +coff_real_object_p (bfd *, + unsigned, + struct internal_filehdr *, + struct internal_aouthdr *); +const bfd_target * coff_real_object_p (bfd *abfd, unsigned nscns, struct internal_filehdr *internal_f, @@ -364,6 +369,10 @@ coff_object_p (bfd *abfd) bfd_release (abfd, opthdr); return NULL; } + /* PR 17512: file: 11056-1136-0.004. */ + if (internal_f.f_opthdr < aoutsz) + memset (((char *) opthdr) + internal_f.f_opthdr, 0, aoutsz - internal_f.f_opthdr); + bfd_coff_swap_aouthdr_in (abfd, opthdr, (void *) &internal_a); bfd_release (abfd, opthdr); } @@ -462,6 +471,11 @@ _bfd_coff_internal_syment_name (bfd *abfd, if (strings == NULL) return NULL; } + /* PR 17910: Only check for string overflow if the length has been set. + Some DLLs, eg those produced by Visual Studio, may not set the length field. */ + if (obj_coff_strings_len (abfd) > 0 + && sym->_n._n_n._n_offset >= obj_coff_strings_len (abfd)) + return NULL; return strings + sym->_n._n_n._n_offset; } } @@ -625,22 +639,6 @@ coff_count_linenumbers (bfd *abfd) return total; } -/* Takes a bfd and a symbol, returns a pointer to the coff specific - area of the symbol if there is one. */ - -coff_symbol_type * -coff_symbol_from (bfd *ignore_abfd ATTRIBUTE_UNUSED, - asymbol *symbol) -{ - if (!bfd_family_coff (bfd_asymbol_bfd (symbol))) - return (coff_symbol_type *) NULL; - - if (bfd_asymbol_bfd (symbol)->tdata.coff_obj_data == (coff_data_type *) NULL) - return (coff_symbol_type *) NULL; - - return (coff_symbol_type *) symbol; -} - static void fixup_symbol_value (bfd *abfd, coff_symbol_type *coff_symbol_ptr, @@ -757,13 +755,16 @@ coff_renumber_symbols (bfd *bfd_ptr, int *first_undef) for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) { - coff_symbol_type *coff_symbol_ptr = coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]); + coff_symbol_type *coff_symbol_ptr; + + coff_symbol_ptr = coff_symbol_from (symbol_ptr_ptr[symbol_index]); symbol_ptr_ptr[symbol_index]->udata.i = symbol_index; if (coff_symbol_ptr && coff_symbol_ptr->native) { combined_entry_type *s = coff_symbol_ptr->native; int i; + BFD_ASSERT (s->is_sym); if (s->u.syment.n_sclass == C_FILE) { if (last_file != NULL) @@ -800,14 +801,15 @@ coff_mangle_symbols (bfd *bfd_ptr) for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) { - coff_symbol_type *coff_symbol_ptr = - coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]); + coff_symbol_type *coff_symbol_ptr; + coff_symbol_ptr = coff_symbol_from (symbol_ptr_ptr[symbol_index]); if (coff_symbol_ptr && coff_symbol_ptr->native) { int i; combined_entry_type *s = coff_symbol_ptr->native; + BFD_ASSERT (s->is_sym); if (s->fix_value) { /* FIXME: We should use a union here. */ @@ -831,6 +833,8 @@ coff_mangle_symbols (bfd *bfd_ptr) for (i = 0; i < s->u.syment.n_numaux; i++) { combined_entry_type *a = s + i + 1; + + BFD_ASSERT (! a->is_sym); if (a->fix_tag) { a->u.auxent.x_sym.x_tagndx.l = @@ -874,6 +878,7 @@ coff_fix_symbol_name (bfd *abfd, } name_length = strlen (name); + BFD_ASSERT (native->is_sym); if (native->u.syment.n_sclass == C_FILE && native->u.syment.n_numaux > 0) { @@ -889,6 +894,7 @@ coff_fix_symbol_name (bfd *abfd, else strncpy (native->u.syment._n._n_name, ".file", SYMNMLEN); + BFD_ASSERT (! (native + 1)->is_sym); auxent = &(native + 1)->u.auxent; filnmlen = bfd_coff_filnmlen (abfd); @@ -991,6 +997,8 @@ coff_write_symbol (bfd *abfd, void * buf; bfd_size_type symesz; + BFD_ASSERT (native->is_sym); + if (native->u.syment.n_sclass == C_FILE) symbol->flags |= BSF_DEBUGGING; @@ -1031,6 +1039,7 @@ coff_write_symbol (bfd *abfd, return FALSE; for (j = 0; j < native->u.syment.n_numaux; j++) { + BFD_ASSERT (! (native + j + 1)->is_sym); bfd_coff_swap_aux_out (abfd, &((native + j + 1)->u.auxent), type, n_sclass, (int) j, @@ -1076,10 +1085,12 @@ coff_write_alien_symbol (bfd *abfd, { symbol->name = ""; if (isym != NULL) - memset (isym, 0, sizeof(*isym)); + memset (isym, 0, sizeof (*isym)); return TRUE; } native = dummy; + native->is_sym = TRUE; + native[1].is_sym = FALSE; native->u.syment.n_type = T_NULL; native->u.syment.n_flags = 0; native->u.syment.n_numaux = 0; @@ -1106,7 +1117,7 @@ coff_write_alien_symbol (bfd *abfd, name to keep it from being put in the string table. */ symbol->name = ""; if (isym != NULL) - memset (isym, 0, sizeof(*isym)); + memset (isym, 0, sizeof (*isym)); return TRUE; } else @@ -1120,7 +1131,7 @@ coff_write_alien_symbol (bfd *abfd, /* Copy the any flags from the file header into the symbol. FIXME: Why? */ { - coff_symbol_type *c = coff_symbol_from (abfd, symbol); + coff_symbol_type *c = coff_symbol_from (symbol); if (c != (coff_symbol_type *) NULL) native->u.syment.n_flags = bfd_asymbol_bfd (&c->symbol)->flags; } @@ -1165,6 +1176,7 @@ coff_write_native_symbol (bfd *abfd, return TRUE; } + BFD_ASSERT (native->is_sym); /* If this symbol has an associated line number, we must store the symbol index in the line number field. We also tag the auxent to point to the right place in the lineno table. */ @@ -1251,7 +1263,7 @@ coff_write_symbols (bfd *abfd) for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) { asymbol *symbol = *p; - coff_symbol_type *c_symbol = coff_symbol_from (abfd, symbol); + coff_symbol_type *c_symbol = coff_symbol_from (symbol); if (c_symbol == (coff_symbol_type *) NULL || c_symbol->native == (combined_entry_type *) NULL) @@ -1274,8 +1286,9 @@ coff_write_symbols (bfd *abfd) symbol which has no associated section and we do not have to worry about this, all we need to know is that it is local. */ current_error_handler = bfd_set_error_handler (null_error_handler); + BFD_ASSERT (c_symbol->native->is_sym); sym_class = bfd_coff_classify_symbol (abfd, - &c_symbol->native->u.syment); + &c_symbol->native->u.syment); (void) bfd_set_error_handler (current_error_handler); n_sclass = &c_symbol->native->u.syment.n_sclass; @@ -1350,7 +1363,7 @@ coff_write_symbols (bfd *abfd) { asymbol *q = *p; size_t name_length = strlen (q->name); - coff_symbol_type *c_symbol = coff_symbol_from (abfd, q); + coff_symbol_type *c_symbol = coff_symbol_from (q); size_t maxlen; /* Figure out whether the symbol name should go in the string @@ -1366,6 +1379,9 @@ coff_write_symbols (bfd *abfd) file name, nor does it go in the .debug section. */ maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN; + else if (! c_symbol->native->is_sym) + maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN; + else if (bfd_coff_symname_in_debug (abfd, &c_symbol->native->u.syment)) /* This symbol name is in the XCOFF .debug section. @@ -1456,6 +1472,7 @@ coff_write_linenumbers (bfd *abfd) { /* Found a linenumber entry, output. */ struct internal_lineno out; + memset ((void *) & out, 0, sizeof (out)); out.l_lnno = 0; out.l_addr.l_symndx = l->u.offset; @@ -1503,6 +1520,7 @@ coff_pointerize_aux (bfd *abfd, unsigned int type = symbol->u.syment.n_type; unsigned int n_sclass = symbol->u.syment.n_sclass; + BFD_ASSERT (symbol->is_sym); if (coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) { if ((*coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) @@ -1516,6 +1534,7 @@ coff_pointerize_aux (bfd *abfd, if (n_sclass == C_FILE) return; + BFD_ASSERT (! auxent->is_sym); /* Otherwise patch up. */ #define N_TMASK coff_data (abfd)->local_n_tmask #define N_BTSHFT coff_data (abfd)->local_n_btshft @@ -1543,7 +1562,7 @@ coff_pointerize_aux (bfd *abfd, we didn't want to go to the trouble until someone needed it. */ static char * -build_debug_section (bfd *abfd) +build_debug_section (bfd *abfd, asection ** sect_return) { char *debug_section; file_ptr position; @@ -1571,6 +1590,8 @@ build_debug_section (bfd *abfd) || bfd_bread (debug_section, sec_size, abfd) != sec_size || bfd_seek (abfd, position, SEEK_SET) != 0) return NULL; + + * sect_return = sect; return debug_section; } @@ -1633,7 +1654,9 @@ _bfd_coff_get_external_symbols (bfd *abfd) /* Read in the external strings. The strings are not loaded until they are needed. This is because we have no simple way of - detecting a missing string table in an archive. */ + detecting a missing string table in an archive. If the strings + are loaded then the STRINGS and STRINGS_LEN fields in the + coff_tdata structure will be set. */ const char * _bfd_coff_read_string_table (bfd *abfd) @@ -1683,10 +1706,16 @@ _bfd_coff_read_string_table (bfd *abfd) return NULL; } - strings = (char *) bfd_malloc (strsize); + strings = (char *) bfd_malloc (strsize + 1); if (strings == NULL) return NULL; + /* PR 17521 file: 079-54929-0.004. + A corrupt file could contain an index that points into the first + STRING_SIZE_SIZE bytes of the string table, so make sure that + they are zero. */ + memset (strings, 0, STRING_SIZE_SIZE); + if (bfd_bread (strings + STRING_SIZE_SIZE, strsize - STRING_SIZE_SIZE, abfd) != strsize - STRING_SIZE_SIZE) { @@ -1695,7 +1724,9 @@ _bfd_coff_read_string_table (bfd *abfd) } obj_coff_strings (abfd) = strings; - + obj_coff_strings_len (abfd) = strsize; + /* Terminate the string table, just in case. */ + strings[strsize] = 0; return strings; } @@ -1715,6 +1746,7 @@ _bfd_coff_free_symbols (bfd *abfd) { free (obj_coff_strings (abfd)); obj_coff_strings (abfd) = NULL; + obj_coff_strings_len (abfd) = 0; } return TRUE; } @@ -1735,21 +1767,22 @@ coff_get_normalized_symtab (bfd *abfd) char *raw_src; char *raw_end; const char *string_table = NULL; - char *debug_section = NULL; + asection * debug_sec = NULL; + char *debug_sec_data = NULL; bfd_size_type size; if (obj_raw_syments (abfd) != NULL) return obj_raw_syments (abfd); + if (! _bfd_coff_get_external_symbols (abfd)) + return NULL; + size = obj_raw_syment_count (abfd) * sizeof (combined_entry_type); internal = (combined_entry_type *) bfd_zalloc (abfd, size); if (internal == NULL && size != 0) return NULL; internal_end = internal + obj_raw_syment_count (abfd); - - if (! _bfd_coff_get_external_symbols (abfd)) - return NULL; - + raw_src = (char *) obj_coff_external_syms (abfd); /* Mark the end of the symbols. */ @@ -1764,23 +1797,43 @@ coff_get_normalized_symtab (bfd *abfd) raw_src < raw_end; raw_src += symesz, internal_ptr++) { - unsigned int i; + bfd_coff_swap_sym_in (abfd, (void *) raw_src, (void *) & internal_ptr->u.syment); symbol_ptr = internal_ptr; + internal_ptr->is_sym = TRUE; + + /* PR 17512: file: 1353-1166-0.004. */ + if (symbol_ptr->u.syment.n_sclass == C_FILE + && symbol_ptr->u.syment.n_numaux > 0 + && raw_src + symesz + symbol_ptr->u.syment.n_numaux + * symesz > raw_end) + { + bfd_release (abfd, internal); + return NULL; + } for (i = 0; i < symbol_ptr->u.syment.n_numaux; i++) { internal_ptr++; + /* PR 17512: Prevent buffer overrun. */ + if (internal_ptr >= internal_end) + { + bfd_release (abfd, internal); + return NULL; + } + raw_src += symesz; bfd_coff_swap_aux_in (abfd, (void *) raw_src, symbol_ptr->u.syment.n_type, symbol_ptr->u.syment.n_sclass, (int) i, symbol_ptr->u.syment.n_numaux, &(internal_ptr->u.auxent)); + + internal_ptr->is_sym = FALSE; coff_pointerize_aux (abfd, internal, symbol_ptr, i, internal_ptr); } @@ -1794,12 +1847,18 @@ coff_get_normalized_symtab (bfd *abfd) for (internal_ptr = internal; internal_ptr < internal_end; internal_ptr++) { + BFD_ASSERT (internal_ptr->is_sym); + if (internal_ptr->u.syment.n_sclass == C_FILE && internal_ptr->u.syment.n_numaux > 0) { + combined_entry_type * aux = internal_ptr + 1; + /* Make a file symbol point to the name in the auxent, since the text ".file" is redundant. */ - if ((internal_ptr + 1)->u.auxent.x_file.x_n.x_zeroes == 0) + BFD_ASSERT (! aux->is_sym); + + if (aux->u.auxent.x_file.x_n.x_zeroes == 0) { /* The filename is a long one, point into the string table. */ if (string_table == NULL) @@ -1809,10 +1868,12 @@ coff_get_normalized_symtab (bfd *abfd) return NULL; } - internal_ptr->u.syment._n._n_n._n_offset = - ((bfd_hostptr_t) - (string_table - + (internal_ptr + 1)->u.auxent.x_file.x_n.x_offset)); + if ((bfd_size_type)(aux->u.auxent.x_file.x_n.x_offset) + >= obj_coff_strings_len (abfd)) + internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) _(""); + else + internal_ptr->u.syment._n._n_n._n_offset = + (bfd_hostptr_t) (string_table + (aux->u.auxent.x_file.x_n.x_offset)); } else { @@ -1822,15 +1883,15 @@ coff_get_normalized_symtab (bfd *abfd) if (internal_ptr->u.syment.n_numaux > 1 && coff_data (abfd)->pe) internal_ptr->u.syment._n._n_n._n_offset = - ((bfd_hostptr_t) - copy_name (abfd, - (internal_ptr + 1)->u.auxent.x_file.x_fname, - internal_ptr->u.syment.n_numaux * symesz)); + (bfd_hostptr_t) + copy_name (abfd, + aux->u.auxent.x_file.x_fname, + internal_ptr->u.syment.n_numaux * symesz); else internal_ptr->u.syment._n._n_n._n_offset = ((bfd_hostptr_t) copy_name (abfd, - (internal_ptr + 1)->u.auxent.x_file.x_fname, + aux->u.auxent.x_file.x_fname, (size_t) bfd_coff_filnmlen (abfd))); } } @@ -1867,18 +1928,33 @@ coff_get_normalized_symtab (bfd *abfd) if (string_table == NULL) return NULL; } - internal_ptr->u.syment._n._n_n._n_offset = - ((bfd_hostptr_t) - (string_table - + internal_ptr->u.syment._n._n_n._n_offset)); + if (internal_ptr->u.syment._n._n_n._n_offset >= obj_coff_strings_len (abfd) + || string_table + internal_ptr->u.syment._n._n_n._n_offset < string_table) + internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) _(""); + else + internal_ptr->u.syment._n._n_n._n_offset = + ((bfd_hostptr_t) + (string_table + + internal_ptr->u.syment._n._n_n._n_offset)); } else { /* Long name in debug section. Very similar. */ - if (debug_section == NULL) - debug_section = build_debug_section (abfd); - internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) - (debug_section + internal_ptr->u.syment._n._n_n._n_offset); + if (debug_sec_data == NULL) + debug_sec_data = build_debug_section (abfd, & debug_sec); + if (debug_sec_data != NULL) + { + BFD_ASSERT (debug_sec != NULL); + /* PR binutils/17512: Catch out of range offsets into the debug data. */ + if (internal_ptr->u.syment._n._n_n._n_offset > debug_sec->size + || debug_sec_data + internal_ptr->u.syment._n._n_n._n_offset < debug_sec_data) + internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) _(""); + else + internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) + (debug_sec_data + internal_ptr->u.syment._n._n_n._n_offset); + } + else + internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) ""; } } internal_ptr += internal_ptr->u.syment.n_numaux; @@ -1911,7 +1987,7 @@ coff_make_empty_symbol (bfd *abfd) if (new_symbol == NULL) return NULL; new_symbol->symbol.section = 0; - new_symbol->native = 0; + new_symbol->native = NULL; new_symbol->lineno = NULL; new_symbol->done_lineno = FALSE; new_symbol->symbol.the_bfd = abfd; @@ -1937,6 +2013,7 @@ coff_bfd_make_debug_symbol (bfd *abfd, new_symbol->native = (combined_entry_type *) bfd_zalloc (abfd, amt); if (!new_symbol->native) return NULL; + new_symbol->native->is_sym = TRUE; new_symbol->symbol.section = bfd_abs_section_ptr; new_symbol->symbol.flags = BSF_DEBUGGING; new_symbol->lineno = NULL; @@ -1952,81 +2029,12 @@ coff_get_symbol_info (bfd *abfd, asymbol *symbol, symbol_info *ret) bfd_symbol_info (symbol, ret); if (coffsymbol (symbol)->native != NULL - && coffsymbol (symbol)->native->fix_value) + && coffsymbol (symbol)->native->fix_value + && coffsymbol (symbol)->native->is_sym) ret->value = coffsymbol (symbol)->native->u.syment.n_value - (bfd_hostptr_t) obj_raw_syments (abfd); } -/* Return the COFF syment for a symbol. */ - -bfd_boolean -bfd_coff_get_syment (bfd *abfd, - asymbol *symbol, - struct internal_syment *psyment) -{ - coff_symbol_type *csym; - - csym = coff_symbol_from (abfd, symbol); - if (csym == NULL || csym->native == NULL) - { - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - - *psyment = csym->native->u.syment; - - if (csym->native->fix_value) - psyment->n_value = psyment->n_value - - (bfd_hostptr_t) obj_raw_syments (abfd); - - /* FIXME: We should handle fix_line here. */ - - return TRUE; -} - -/* Return the COFF auxent for a symbol. */ - -bfd_boolean -bfd_coff_get_auxent (bfd *abfd, - asymbol *symbol, - int indx, - union internal_auxent *pauxent) -{ - coff_symbol_type *csym; - combined_entry_type *ent; - - csym = coff_symbol_from (abfd, symbol); - - if (csym == NULL - || csym->native == NULL - || indx >= csym->native->u.syment.n_numaux) - { - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - - ent = csym->native + indx + 1; - - *pauxent = ent->u.auxent; - - if (ent->fix_tag) - pauxent->x_sym.x_tagndx.l = - ((combined_entry_type *) pauxent->x_sym.x_tagndx.p - - obj_raw_syments (abfd)); - - if (ent->fix_end) - pauxent->x_sym.x_fcnary.x_fcn.x_endndx.l = - ((combined_entry_type *) pauxent->x_sym.x_fcnary.x_fcn.x_endndx.p - - obj_raw_syments (abfd)); - - if (ent->fix_scnlen) - pauxent->x_csect.x_scnlen.l = - ((combined_entry_type *) pauxent->x_csect.x_scnlen.p - - obj_raw_syments (abfd)); - - return TRUE; -} - /* Print out information about COFF symbol. */ void @@ -2060,6 +2068,15 @@ coff_print_symbol (bfd *abfd, fprintf (file, "[%3ld]", (long) (combined - root)); + /* PR 17512: file: 079-33786-0.001:0.1. */ + if (combined < obj_raw_syments (abfd) + || combined >= obj_raw_syments (abfd) + obj_raw_syment_count (abfd)) + { + fprintf (file, _(" %s"), symbol->name); + break; + } + + BFD_ASSERT (combined->is_sym); if (! combined->fix_value) val = (bfd_vma) combined->u.syment.n_value; else @@ -2079,6 +2096,7 @@ coff_print_symbol (bfd *abfd, combined_entry_type *auxp = combined + aux + 1; long tagndx; + BFD_ASSERT (! auxp->is_sym); if (auxp->fix_tag) tagndx = auxp->u.auxent.x_sym.x_tagndx.p - root; else @@ -2153,8 +2171,11 @@ coff_print_symbol (bfd *abfd, l++; while (l->line_number) { - fprintf (file, "\n%4d : ", l->line_number); - bfd_fprintf_vma (abfd, file, l->u.offset + symbol->section->vma); + if (l->line_number > 0) + { + fprintf (file, "\n%4d : ", l->line_number); + bfd_fprintf_vma (abfd, file, l->u.offset + symbol->section->vma); + } l++; } } @@ -2189,13 +2210,13 @@ _bfd_coff_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, bfd_boolean coff_find_nearest_line_with_names (bfd *abfd, - const struct dwarf_debug_section *debug_sections, - asection *section, asymbol **symbols, + asection *section, bfd_vma offset, const char **filename_ptr, const char **functionname_ptr, - unsigned int *line_ptr) + unsigned int *line_ptr, + const struct dwarf_debug_section *debug_sections) { bfd_boolean found; unsigned int i; @@ -2220,13 +2241,32 @@ coff_find_nearest_line_with_names (bfd *abfd, return TRUE; /* Also try examining DWARF2 debugging information. */ - if (_bfd_dwarf2_find_nearest_line (abfd, debug_sections, - section, symbols, offset, + if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset, filename_ptr, functionname_ptr, - line_ptr, NULL, 0, + line_ptr, NULL, debug_sections, 0, &coff_data(abfd)->dwarf2_find_line_info)) return TRUE; + /* If the DWARF lookup failed, but there is DWARF information available + then the problem might be that the file has been rebased. This tool + changes the VMAs of all the sections, but it does not update the DWARF + information. So try again, using a bias against the address sought. */ + if (coff_data (abfd)->dwarf2_find_line_info != NULL) + { + bfd_signed_vma bias; + + bias = _bfd_dwarf2_find_symbol_bias (symbols, + & coff_data (abfd)->dwarf2_find_line_info); + + if (bias + && _bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, + offset + bias, + filename_ptr, functionname_ptr, + line_ptr, NULL, debug_sections, 0, + &coff_data(abfd)->dwarf2_find_line_info)) + return TRUE; + } + *filename_ptr = 0; *functionname_ptr = 0; *line_ptr = 0; @@ -2246,6 +2286,7 @@ coff_find_nearest_line_with_names (bfd *abfd, pend = p + cof->raw_syment_count; while (p < pend) { + BFD_ASSERT (p->is_sym); if (p->u.syment.n_sclass == C_FILE) break; p += 1 + p->u.syment.n_numaux; @@ -2269,6 +2310,7 @@ coff_find_nearest_line_with_names (bfd *abfd, p2 < pend; p2 += 1 + p2->u.syment.n_numaux) { + BFD_ASSERT (p2->is_sym); if (p2->u.syment.n_scnum > 0 && (section == coff_section_from_bfd_index (abfd, @@ -2280,6 +2322,8 @@ coff_find_nearest_line_with_names (bfd *abfd, break; } } + if (p2 >= pend) + break; file_addr = (bfd_vma) p2->u.syment.n_value; /* PR 11512: Include the section address of the function name symbol. */ @@ -2344,6 +2388,8 @@ coff_find_nearest_line_with_names (bfd *abfd, if (coff->native) { combined_entry_type *s = coff->native; + + BFD_ASSERT (s->is_sym); s = s + 1 + s->u.syment.n_numaux; /* In XCOFF a debugging symbol can follow the @@ -2356,6 +2402,7 @@ coff_find_nearest_line_with_names (bfd *abfd, { /* The linenumber is stored in the auxent. */ union internal_auxent *a = &((s + 1)->u.auxent); + line_base = a->x_sym.x_misc.x_lnsz.x_lnno; *line_ptr = line_base; } @@ -2405,37 +2452,21 @@ coff_find_nearest_line_with_names (bfd *abfd, bfd_boolean coff_find_nearest_line (bfd *abfd, - asection *section, asymbol **symbols, + asection *section, bfd_vma offset, const char **filename_ptr, const char **functionname_ptr, - unsigned int *line_ptr) -{ - return coff_find_nearest_line_with_names (abfd, dwarf_debug_sections, - section, symbols, offset, - filename_ptr, functionname_ptr, - line_ptr); -} - -bfd_boolean -coff_find_nearest_line_discriminator (bfd *abfd, - asection *section, - asymbol **symbols, - bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr, - unsigned int *line_ptr, - unsigned int *discriminator) + unsigned int *line_ptr, + unsigned int *discriminator_ptr) { - *discriminator = 0; - return coff_find_nearest_line_with_names (abfd, dwarf_debug_sections, - section, symbols, offset, + if (discriminator_ptr) + *discriminator_ptr = 0; + return coff_find_nearest_line_with_names (abfd, symbols, section, offset, filename_ptr, functionname_ptr, - line_ptr); + line_ptr, dwarf_debug_sections); } - bfd_boolean coff_find_inliner_info (bfd *abfd, const char **filename_ptr, @@ -2473,7 +2504,7 @@ bfd_coff_set_symbol_class (bfd * abfd, { coff_symbol_type * csym; - csym = coff_symbol_from (abfd, symbol); + csym = coff_symbol_from (symbol); if (csym == NULL) { bfd_set_error (bfd_error_invalid_operation); @@ -2493,6 +2524,7 @@ bfd_coff_set_symbol_class (bfd * abfd, if (native == NULL) return FALSE; + native->is_sym = TRUE; native->u.syment.n_type = T_NULL; native->u.syment.n_sclass = symbol_class; @@ -2528,16 +2560,6 @@ bfd_coff_set_symbol_class (bfd * abfd, return TRUE; } -struct coff_comdat_info * -bfd_coff_get_comdat_section (bfd *abfd, struct bfd_section *sec) -{ - if (bfd_get_flavour (abfd) == bfd_target_coff_flavour - && coff_section_data (abfd, sec) != NULL) - return coff_section_data (abfd, sec)->comdat; - else - return NULL; -} - bfd_boolean _bfd_coff_section_already_linked (bfd *abfd, asection *sec, @@ -2604,3 +2626,431 @@ _bfd_coff_section_already_linked (bfd *abfd, info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); return FALSE; } + +/* Initialize COOKIE for input bfd ABFD. */ + +static bfd_boolean +init_reloc_cookie (struct coff_reloc_cookie *cookie, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + bfd *abfd) +{ + /* Sometimes the symbol table does not yet have been loaded here. */ + bfd_coff_slurp_symbol_table (abfd); + + cookie->abfd = abfd; + cookie->sym_hashes = obj_coff_sym_hashes (abfd); + + cookie->symbols = obj_symbols (abfd); + + return TRUE; +} + +/* Free the memory allocated by init_reloc_cookie, if appropriate. */ + +static void +fini_reloc_cookie (struct coff_reloc_cookie *cookie ATTRIBUTE_UNUSED, + bfd *abfd ATTRIBUTE_UNUSED) +{ + /* Nothing to do. */ +} + +/* Initialize the relocation information in COOKIE for input section SEC + of input bfd ABFD. */ + +static bfd_boolean +init_reloc_cookie_rels (struct coff_reloc_cookie *cookie, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + bfd *abfd, + asection *sec) +{ + if (sec->reloc_count == 0) + { + cookie->rels = NULL; + cookie->relend = NULL; + cookie->rel = NULL; + return TRUE; + } + + cookie->rels = _bfd_coff_read_internal_relocs (abfd, sec, FALSE, NULL, 0, NULL); + + if (cookie->rels == NULL) + return FALSE; + + cookie->rel = cookie->rels; + cookie->relend = (cookie->rels + sec->reloc_count); + return TRUE; +} + +/* Free the memory allocated by init_reloc_cookie_rels, + if appropriate. */ + +static void +fini_reloc_cookie_rels (struct coff_reloc_cookie *cookie, + asection *sec) +{ + if (cookie->rels && coff_section_data (NULL, sec)->relocs != cookie->rels) + free (cookie->rels); +} + +/* Initialize the whole of COOKIE for input section SEC. */ + +static bfd_boolean +init_reloc_cookie_for_section (struct coff_reloc_cookie *cookie, + struct bfd_link_info *info, + asection *sec) +{ + if (!init_reloc_cookie (cookie, info, sec->owner)) + return FALSE; + + if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec)) + { + fini_reloc_cookie (cookie, sec->owner); + return FALSE; + } + return TRUE; +} + +/* Free the memory allocated by init_reloc_cookie_for_section, + if appropriate. */ + +static void +fini_reloc_cookie_for_section (struct coff_reloc_cookie *cookie, + asection *sec) +{ + fini_reloc_cookie_rels (cookie, sec); + fini_reloc_cookie (cookie, sec->owner); +} + +static asection * +_bfd_coff_gc_mark_hook (asection *sec, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + struct internal_reloc *rel ATTRIBUTE_UNUSED, + struct coff_link_hash_entry *h, + struct internal_syment *sym) +{ + if (h != NULL) + { + switch (h->root.type) + { + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + return h->root.u.def.section; + + case bfd_link_hash_common: + return h->root.u.c.p->section; + + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + default: + break; + } + return NULL; + } + + return coff_section_from_bfd_index (sec->owner, sym->n_scnum); +} + +/* COOKIE->rel describes a relocation against section SEC, which is + a section we've decided to keep. Return the section that contains + the relocation symbol, or NULL if no section contains it. */ + +static asection * +_bfd_coff_gc_mark_rsec (struct bfd_link_info *info, asection *sec, + coff_gc_mark_hook_fn gc_mark_hook, + struct coff_reloc_cookie *cookie) +{ + struct coff_link_hash_entry *h; + + h = cookie->sym_hashes[cookie->rel->r_symndx]; + if (h != NULL) + { + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct coff_link_hash_entry *) h->root.u.i.link; + + return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); + } + + return (*gc_mark_hook) (sec, info, cookie->rel, NULL, + &(cookie->symbols + + obj_convert (sec->owner)[cookie->rel->r_symndx])->native->u.syment); +} + +static bfd_boolean _bfd_coff_gc_mark + (struct bfd_link_info *, asection *, coff_gc_mark_hook_fn); + +/* COOKIE->rel describes a relocation against section SEC, which is + a section we've decided to keep. Mark the section that contains + the relocation symbol. */ + +static bfd_boolean +_bfd_coff_gc_mark_reloc (struct bfd_link_info *info, + asection *sec, + coff_gc_mark_hook_fn gc_mark_hook, + struct coff_reloc_cookie *cookie) +{ + asection *rsec; + + rsec = _bfd_coff_gc_mark_rsec (info, sec, gc_mark_hook, cookie); + if (rsec && !rsec->gc_mark) + { + if (bfd_get_flavour (rsec->owner) != bfd_target_coff_flavour) + rsec->gc_mark = 1; + else if (!_bfd_coff_gc_mark (info, rsec, gc_mark_hook)) + return FALSE; + } + return TRUE; +} + +/* The mark phase of garbage collection. For a given section, mark + it and any sections in this section's group, and all the sections + which define symbols to which it refers. */ + +static bfd_boolean +_bfd_coff_gc_mark (struct bfd_link_info *info, + asection *sec, + coff_gc_mark_hook_fn gc_mark_hook) +{ + bfd_boolean ret = TRUE; + + sec->gc_mark = 1; + + /* Look through the section relocs. */ + if ((sec->flags & SEC_RELOC) != 0 + && sec->reloc_count > 0) + { + struct coff_reloc_cookie cookie; + + if (!init_reloc_cookie_for_section (&cookie, info, sec)) + ret = FALSE; + else + { + for (; cookie.rel < cookie.relend; cookie.rel++) + { + if (!_bfd_coff_gc_mark_reloc (info, sec, gc_mark_hook, &cookie)) + { + ret = FALSE; + break; + } + } + fini_reloc_cookie_for_section (&cookie, sec); + } + } + + return ret; +} + +static bfd_boolean +_bfd_coff_gc_mark_extra_sections (struct bfd_link_info *info, + coff_gc_mark_hook_fn mark_hook ATTRIBUTE_UNUSED) +{ + bfd *ibfd; + + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + asection *isec; + bfd_boolean some_kept; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) + continue; + + /* Ensure all linker created sections are kept, and see whether + any other section is already marked. */ + some_kept = FALSE; + for (isec = ibfd->sections; isec != NULL; isec = isec->next) + { + if ((isec->flags & SEC_LINKER_CREATED) != 0) + isec->gc_mark = 1; + else if (isec->gc_mark) + some_kept = TRUE; + } + + /* If no section in this file will be kept, then we can + toss out debug sections. */ + if (!some_kept) + continue; + + /* Keep debug and special sections like .comment when they are + not part of a group, or when we have single-member groups. */ + for (isec = ibfd->sections; isec != NULL; isec = isec->next) + if ((isec->flags & SEC_DEBUGGING) != 0 + || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) + isec->gc_mark = 1; + } + return TRUE; +} + +/* Sweep symbols in swept sections. Called via coff_link_hash_traverse. */ + +static bfd_boolean +coff_gc_sweep_symbol (struct coff_link_hash_entry *h, + void *data ATTRIBUTE_UNUSED) +{ + if (h->root.type == bfd_link_hash_warning) + h = (struct coff_link_hash_entry *) h->root.u.i.link; + + if ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && !h->root.u.def.section->gc_mark + && !(h->root.u.def.section->owner->flags & DYNAMIC)) + { + /* Do our best to hide the symbol. */ + h->root.u.def.section = bfd_und_section_ptr; + h->symbol_class = C_HIDDEN; + } + + return TRUE; +} + +/* The sweep phase of garbage collection. Remove all garbage sections. */ + +typedef bfd_boolean (*gc_sweep_hook_fn) + (bfd *, struct bfd_link_info *, asection *, const struct internal_reloc *); + +static bfd_boolean +coff_gc_sweep (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) +{ + bfd *sub; + + for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) + { + asection *o; + + if (bfd_get_flavour (sub) != bfd_target_coff_flavour) + continue; + + for (o = sub->sections; o != NULL; o = o->next) + { + /* Keep debug and special sections. */ + if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0 + || (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) + o->gc_mark = 1; + else if (CONST_STRNEQ (o->name, ".idata") + || CONST_STRNEQ (o->name, ".pdata") + || CONST_STRNEQ (o->name, ".xdata") + || CONST_STRNEQ (o->name, ".rsrc")) + o->gc_mark = 1; + + if (o->gc_mark) + continue; + + /* Skip sweeping sections already excluded. */ + if (o->flags & SEC_EXCLUDE) + continue; + + /* Since this is early in the link process, it is simple + to remove a section from the output. */ + o->flags |= SEC_EXCLUDE; + + if (info->print_gc_sections && o->size != 0) + _bfd_error_handler (_("Removing unused section '%s' in file '%B'"), sub, o->name); + +#if 0 + /* But we also have to update some of the relocation + info we collected before. */ + if (gc_sweep_hook + && (o->flags & SEC_RELOC) != 0 + && o->reloc_count > 0 + && !bfd_is_abs_section (o->output_section)) + { + struct internal_reloc *internal_relocs; + bfd_boolean r; + + internal_relocs + = _bfd_coff_link_read_relocs (o->owner, o, NULL, NULL, + info->keep_memory); + if (internal_relocs == NULL) + return FALSE; + + r = (*gc_sweep_hook) (o->owner, info, o, internal_relocs); + + if (coff_section_data (o)->relocs != internal_relocs) + free (internal_relocs); + + if (!r) + return FALSE; + } +#endif + } + } + + /* Remove the symbols that were in the swept sections from the dynamic + symbol table. */ + coff_link_hash_traverse (coff_hash_table (info), coff_gc_sweep_symbol, + NULL); + + return TRUE; +} + +/* Keep all sections containing symbols undefined on the command-line, + and the section containing the entry symbol. */ + +static void +_bfd_coff_gc_keep (struct bfd_link_info *info) +{ + struct bfd_sym_chain *sym; + + for (sym = info->gc_sym_list; sym != NULL; sym = sym->next) + { + struct coff_link_hash_entry *h; + + h = coff_link_hash_lookup (coff_hash_table (info), sym->name, + FALSE, FALSE, FALSE); + + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && !bfd_is_abs_section (h->root.u.def.section)) + h->root.u.def.section->flags |= SEC_KEEP; + } +} + +/* Do mark and sweep of unused sections. */ + +bfd_boolean +bfd_coff_gc_sections (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) +{ + bfd *sub; + + /* FIXME: Should we implement this? */ +#if 0 + const bfd_coff_backend_data *bed = coff_backend_info (abfd); + + if (!bed->can_gc_sections + || !is_coff_hash_table (info->hash)) + { + (*_bfd_error_handler)(_("Warning: gc-sections option ignored")); + return TRUE; + } +#endif + + _bfd_coff_gc_keep (info); + + /* Grovel through relocs to find out who stays ... */ + for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) + { + asection *o; + + if (bfd_get_flavour (sub) != bfd_target_coff_flavour) + continue; + + for (o = sub->sections; o != NULL; o = o->next) + { + if (((o->flags & (SEC_EXCLUDE | SEC_KEEP)) == SEC_KEEP + || CONST_STRNEQ (o->name, ".vectors") + || CONST_STRNEQ (o->name, ".ctors") + || CONST_STRNEQ (o->name, ".dtors")) + && !o->gc_mark) + { + if (!_bfd_coff_gc_mark (info, o, _bfd_coff_gc_mark_hook)) + return FALSE; + } + } + } + + /* Allow the backend to mark additional target specific sections. */ + _bfd_coff_gc_mark_extra_sections (info, _bfd_coff_gc_mark_hook); + + /* ... and mark SEC_EXCLUDE for those that go. */ + return coff_gc_sweep (abfd, info); +} diff --git a/contrib/gdb-7/bfd/compress.c b/contrib/gdb-7/bfd/compress.c index eb3bc536ff..775194867d 100644 --- a/contrib/gdb-7/bfd/compress.c +++ b/contrib/gdb-7/bfd/compress.c @@ -1,6 +1,5 @@ /* Compressed section support (intended for debug sections). - Copyright 2008, 2010, 2011, 2012 - Free Software Foundation, Inc. + Copyright (C) 2008-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -20,13 +19,13 @@ MA 02110-1301, USA. */ #include "sysdep.h" +#include #include "bfd.h" #include "libbfd.h" -#ifdef HAVE_ZLIB_H -#include -#endif +#include "safe-ctype.h" + +#define MAX_COMPRESSION_HEADER_SIZE 24 -#ifdef HAVE_ZLIB_H static bfd_boolean decompress_contents (bfd_byte *compressed_buffer, bfd_size_type compressed_size, @@ -38,103 +37,168 @@ decompress_contents (bfd_byte *compressed_buffer, /* 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 - 12; - strm.next_in = (Bytef*) compressed_buffer + 12; + /* PR 18313: The state field in the z_stream structure is supposed + to be invisible to the user (ie us), but some compilers will + still complain about it being used without initialisation. So + we first zero the entire z_stream structure and then set the fields + that we need. */ + memset (& strm, 0, sizeof strm); + strm.avail_in = compressed_size; + strm.next_in = (Bytef*) compressed_buffer; strm.avail_out = uncompressed_size; + BFD_ASSERT (Z_OK == 0); rc = inflateInit (&strm); while (strm.avail_in > 0 && strm.avail_out > 0) { if (rc != Z_OK) - return FALSE; + break; strm.next_out = ((Bytef*) uncompressed_buffer + (uncompressed_size - strm.avail_out)); rc = inflate (&strm, Z_FINISH); if (rc != Z_STREAM_END) - return FALSE; + break; rc = inflateReset (&strm); } - rc = inflateEnd (&strm); + rc |= inflateEnd (&strm); return rc == Z_OK && strm.avail_out == 0; } -#endif -/* -FUNCTION - bfd_compress_section_contents +/* Compress data of the size specified in @var{uncompressed_size} + and pointed to by @var{uncompressed_buffer} using zlib and store + as the contents field. This function assumes the contents + field was allocated using bfd_malloc() or equivalent. -SYNOPSIS - bfd_boolean bfd_compress_section_contents - (bfd *abfd, asection *section, bfd_byte *uncompressed_buffer, - bfd_size_type uncompressed_size); + Return the uncompressed size if the full section contents is + compressed successfully. Otherwise return 0. */ -DESCRIPTION - - Compress data of the size specified in @var{uncompressed_size} - and pointed to by @var{uncompressed_buffer} using zlib and store - as the contents field. This function assumes the contents - field was allocated using bfd_malloc() or equivalent. If zlib - is not installed on this machine, the input is unmodified. - - Return @code{TRUE} if the full section contents is compressed - successfully. -*/ - -bfd_boolean -bfd_compress_section_contents (bfd *abfd ATTRIBUTE_UNUSED, - sec_ptr sec ATTRIBUTE_UNUSED, - bfd_byte *uncompressed_buffer ATTRIBUTE_UNUSED, - bfd_size_type uncompressed_size ATTRIBUTE_UNUSED) +static bfd_size_type +bfd_compress_section_contents (bfd *abfd, sec_ptr sec, + bfd_byte *uncompressed_buffer, + bfd_size_type uncompressed_size) { -#ifndef HAVE_ZLIB_H - bfd_set_error (bfd_error_invalid_operation); - return FALSE; -#else uLong compressed_size; - bfd_byte *compressed_buffer; + bfd_byte *buffer; + bfd_size_type buffer_size; + bfd_boolean decompress; + int zlib_size = 0; + int orig_compression_header_size; + bfd_size_type orig_uncompressed_size; + int header_size = bfd_get_compression_header_size (abfd, NULL); + bfd_boolean compressed + = bfd_is_section_compressed_with_header (abfd, sec, + &orig_compression_header_size, + &orig_uncompressed_size); + + /* Either ELF compression header or the 12-byte, "ZLIB" + 8-byte size, + overhead in .zdebug* section. */ + if (!header_size) + header_size = 12; + + if (compressed) + { + /* We shouldn't decompress unsupported compressed section. */ + if (orig_compression_header_size < 0) + abort (); - compressed_size = compressBound (uncompressed_size) + 12; - compressed_buffer = (bfd_byte *) bfd_malloc (compressed_size); + /* Different compression schemes. Just move the compressed section + contents to the right position. */ + if (orig_compression_header_size == 0) + { + /* Convert it from .zdebug* section. Get the uncompressed + size first. We need to substract the 12-byte overhead in + .zdebug* section. Set orig_compression_header_size to + the 12-bye overhead. */ + orig_compression_header_size = 12; + zlib_size = uncompressed_size - 12; + } + else + { + /* Convert it to .zdebug* section. */ + zlib_size = uncompressed_size - orig_compression_header_size; + } - if (compressed_buffer == NULL) - return FALSE; + /* Add the header size. */ + compressed_size = zlib_size + header_size; + } + else + compressed_size = compressBound (uncompressed_size) + header_size; - if (compress ((Bytef*) compressed_buffer + 12, - &compressed_size, - (const Bytef*) uncompressed_buffer, - uncompressed_size) != Z_OK) + /* Uncompress if it leads to smaller size. */ + if (compressed && compressed_size > orig_uncompressed_size) { - free (compressed_buffer); - bfd_set_error (bfd_error_bad_value); - return FALSE; + decompress = TRUE; + buffer_size = orig_uncompressed_size; + } + else + { + decompress = FALSE; + buffer_size = compressed_size; } + buffer = (bfd_byte *) bfd_alloc (abfd, buffer_size); + if (buffer == NULL) + return 0; - /* Write the zlib header. In this case, it should be "ZLIB" followed - by the uncompressed section size, 8 bytes in big-endian order. */ - memcpy (compressed_buffer, "ZLIB", 4); - compressed_buffer[11] = uncompressed_size; uncompressed_size >>= 8; - compressed_buffer[10] = uncompressed_size; uncompressed_size >>= 8; - compressed_buffer[9] = uncompressed_size; uncompressed_size >>= 8; - compressed_buffer[8] = uncompressed_size; uncompressed_size >>= 8; - compressed_buffer[7] = uncompressed_size; uncompressed_size >>= 8; - compressed_buffer[6] = uncompressed_size; uncompressed_size >>= 8; - compressed_buffer[5] = uncompressed_size; uncompressed_size >>= 8; - compressed_buffer[4] = uncompressed_size; - compressed_size += 12; - - /* Free the uncompressed contents if we compress in place. */ - if (uncompressed_buffer == sec->contents) - free (uncompressed_buffer); - - sec->contents = compressed_buffer; + if (compressed) + { + sec->size = orig_uncompressed_size; + if (decompress) + { + if (!decompress_contents (uncompressed_buffer + + orig_compression_header_size, + zlib_size, buffer, buffer_size)) + { + bfd_set_error (bfd_error_bad_value); + bfd_release (abfd, buffer); + return 0; + } + free (uncompressed_buffer); + sec->contents = buffer; + sec->compress_status = COMPRESS_SECTION_DONE; + return orig_uncompressed_size; + } + else + { + bfd_update_compression_header (abfd, buffer, sec); + memmove (buffer + header_size, + uncompressed_buffer + orig_compression_header_size, + zlib_size); + } + } + else + { + if (compress ((Bytef*) buffer + header_size, + &compressed_size, + (const Bytef*) uncompressed_buffer, + uncompressed_size) != Z_OK) + { + bfd_release (abfd, buffer); + bfd_set_error (bfd_error_bad_value); + return 0; + } + + compressed_size += header_size; + /* PR binutils/18087: If compression didn't make the section smaller, + just keep it uncompressed. */ + if (compressed_size < uncompressed_size) + bfd_update_compression_header (abfd, buffer, sec); + else + { + /* NOTE: There is a small memory leak here since + uncompressed_buffer is malloced and won't be freed. */ + bfd_release (abfd, buffer); + sec->contents = uncompressed_buffer; + sec->compress_status = COMPRESS_SECTION_NONE; + return uncompressed_size; + } + } + + free (uncompressed_buffer); + sec->contents = buffer; sec->size = compressed_size; sec->compress_status = COMPRESS_SECTION_DONE; - return TRUE; -#endif /* HAVE_ZLIB_H */ + return uncompressed_size; } /* @@ -151,7 +215,8 @@ DESCRIPTION return @var{*ptr} with memory malloc'd by this function. Return @code{TRUE} if the full section contents is retrieved - successfully. + successfully. If the section has no contents then this function + returns @code{TRUE} but @var{*ptr} is set to NULL. */ bfd_boolean @@ -159,19 +224,21 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) { bfd_size_type sz; bfd_byte *p = *ptr; -#ifdef HAVE_ZLIB_H bfd_boolean ret; bfd_size_type save_size; bfd_size_type save_rawsize; bfd_byte *compressed_buffer; -#endif + unsigned int compression_header_size; if (abfd->direction != write_direction && sec->rawsize != 0) sz = sec->rawsize; else sz = sec->size; if (sz == 0) - return TRUE; + { + *ptr = NULL; + return TRUE; + } switch (sec->compress_status) { @@ -182,6 +249,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) if (p == NULL) return FALSE; } + if (!bfd_get_section_contents (abfd, sec, p, 0, sz)) { if (*ptr != p) @@ -192,10 +260,6 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) return TRUE; case DECOMPRESS_SECTION_SIZED: -#ifndef HAVE_ZLIB_H - bfd_set_error (bfd_error_invalid_operation); - return FALSE; -#else /* Read in the full compressed section contents. */ compressed_buffer = (bfd_byte *) bfd_malloc (sec->compressed_size); if (compressed_buffer == NULL) @@ -222,7 +286,13 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) if (p == NULL) goto fail_compressed; - if (!decompress_contents (compressed_buffer, sec->compressed_size, p, sz)) + compression_header_size = bfd_get_compression_header_size (abfd, sec); + if (compression_header_size == 0) + /* Set header size to the zlib header size if it is a + SHF_COMPRESSED section. */ + compression_header_size = 12; + if (!decompress_contents (compressed_buffer + compression_header_size, + sec->compressed_size, p, sz)) { bfd_set_error (bfd_error_bad_value); if (p != *ptr) @@ -235,9 +305,10 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) free (compressed_buffer); *ptr = p; return TRUE; -#endif case COMPRESS_SECTION_DONE: + if (sec->contents == NULL) + return FALSE; if (p == NULL) { p = (bfd_byte *) bfd_malloc (sz); @@ -245,7 +316,9 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) return FALSE; *ptr = p; } - memcpy (p, sec->contents, sz); + /* PR 17512; file: 5bc29788. */ + if (p != sec->contents) + memcpy (p, sec->contents, sz); return TRUE; default: @@ -275,39 +348,106 @@ bfd_cache_section_contents (asection *sec, void *contents) sec->flags |= SEC_IN_MEMORY; } - /* FUNCTION - bfd_is_section_compressed + bfd_is_section_compressed_with_header SYNOPSIS - bfd_boolean bfd_is_section_compressed - (bfd *abfd, asection *section); + bfd_boolean bfd_is_section_compressed_with_header + (bfd *abfd, asection *section, + int *compression_header_size_p, + bfd_size_type *uncompressed_size_p); DESCRIPTION - Return @code{TRUE} if @var{section} is compressed. + Return @code{TRUE} if @var{section} is compressed. Compression + header size is returned in @var{compression_header_size_p} and + uncompressed size is returned in @var{uncompressed_size_p}. If + compression is unsupported, compression header size is returned + with -1 and uncompressed size is returned with 0. */ bfd_boolean -bfd_is_section_compressed (bfd *abfd, sec_ptr sec) +bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec, + int *compression_header_size_p, + bfd_size_type *uncompressed_size_p) { - bfd_byte compressed_buffer [12]; + bfd_byte header[MAX_COMPRESSION_HEADER_SIZE]; + int compression_header_size; + int header_size; unsigned int saved = sec->compress_status; bfd_boolean compressed; + compression_header_size = bfd_get_compression_header_size (abfd, sec); + if (compression_header_size > MAX_COMPRESSION_HEADER_SIZE) + abort (); + header_size = compression_header_size ? compression_header_size : 12; + /* Don't decompress the section. */ sec->compress_status = COMPRESS_SECTION_NONE; - /* Read the zlib header. In this case, it should be "ZLIB" followed - by the uncompressed section size, 8 bytes in big-endian order. */ - compressed = (bfd_get_section_contents (abfd, sec, compressed_buffer, 0, 12) - && CONST_STRNEQ ((char*) compressed_buffer, "ZLIB")); + /* Read the header. */ + if (bfd_get_section_contents (abfd, sec, header, 0, header_size)) + { + if (compression_header_size == 0) + /* In this case, it should be "ZLIB" followed by the uncompressed + section size, 8 bytes in big-endian order. */ + compressed = CONST_STRNEQ ((char*) header , "ZLIB"); + else + compressed = TRUE; + } + else + compressed = FALSE; + + *uncompressed_size_p = sec->size; + if (compressed) + { + if (compression_header_size != 0) + { + if (!bfd_check_compression_header (abfd, header, sec, + uncompressed_size_p)) + compression_header_size = -1; + } + /* Check for the pathalogical case of a debug string section that + contains the string ZLIB.... as the first entry. We assume that + no uncompressed .debug_str section would ever be big enough to + have the first byte of its (big-endian) size be non-zero. */ + else if (strcmp (sec->name, ".debug_str") == 0 + && ISPRINT (header[4])) + compressed = FALSE; + else + *uncompressed_size_p = bfd_getb64 (header + 4); + } /* Restore compress_status. */ sec->compress_status = saved; + *compression_header_size_p = compression_header_size; return compressed; } +/* +FUNCTION + bfd_is_section_compressed + +SYNOPSIS + bfd_boolean bfd_is_section_compressed + (bfd *abfd, asection *section); + +DESCRIPTION + Return @code{TRUE} if @var{section} is compressed. +*/ + +bfd_boolean +bfd_is_section_compressed (bfd *abfd, sec_ptr sec) +{ + int compression_header_size; + bfd_size_type uncompressed_size; + return (bfd_is_section_compressed_with_header (abfd, sec, + &compression_header_size, + &uncompressed_size) + && compression_header_size >= 0 + && uncompressed_size > 0); +} + /* FUNCTION bfd_init_section_decompress_status @@ -322,53 +462,55 @@ DESCRIPTION DECOMPRESS_SECTION_SIZED. Return @code{FALSE} if the section is not a valid compressed - section or zlib is not installed on this machine. Otherwise, - return @code{TRUE}. + section. Otherwise, return @code{TRUE}. */ bfd_boolean -bfd_init_section_decompress_status (bfd *abfd ATTRIBUTE_UNUSED, - sec_ptr sec ATTRIBUTE_UNUSED) +bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec) { -#ifndef HAVE_ZLIB_H - bfd_set_error (bfd_error_invalid_operation); - return FALSE; -#else - bfd_byte compressed_buffer [12]; + bfd_byte header[MAX_COMPRESSION_HEADER_SIZE]; + int compression_header_size; + int header_size; bfd_size_type uncompressed_size; + compression_header_size = bfd_get_compression_header_size (abfd, sec); + if (compression_header_size > MAX_COMPRESSION_HEADER_SIZE) + abort (); + header_size = compression_header_size ? compression_header_size : 12; + + /* Read the header. */ if (sec->rawsize != 0 || sec->contents != NULL || sec->compress_status != COMPRESS_SECTION_NONE - || !bfd_get_section_contents (abfd, sec, compressed_buffer, 0, 12)) + || !bfd_get_section_contents (abfd, sec, header, 0, header_size)) { bfd_set_error (bfd_error_invalid_operation); return FALSE; } - /* Read the zlib header. In this case, it should be "ZLIB" followed - by the uncompressed section size, 8 bytes in big-endian order. */ - if (! CONST_STRNEQ ((char*) compressed_buffer, "ZLIB")) + if (compression_header_size == 0) + { + /* In this case, it should be "ZLIB" followed by the uncompressed + section size, 8 bytes in big-endian order. */ + if (! CONST_STRNEQ ((char*) header, "ZLIB")) + { + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + uncompressed_size = bfd_getb64 (header + 4); + } + else if (!bfd_check_compression_header (abfd, header, sec, + &uncompressed_size)) { bfd_set_error (bfd_error_wrong_format); return FALSE; } - uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[11]; - sec->compressed_size = sec->size; sec->size = uncompressed_size; sec->compress_status = DECOMPRESS_SECTION_SIZED; return TRUE; -#endif } /* @@ -384,18 +526,12 @@ DESCRIPTION compressed size and set compress_status to COMPRESS_SECTION_DONE. Return @code{FALSE} if the section is not a valid compressed - section or zlib is not installed on this machine. Otherwise, - return @code{TRUE}. + section. Otherwise, return @code{TRUE}. */ bfd_boolean -bfd_init_section_compress_status (bfd *abfd ATTRIBUTE_UNUSED, - sec_ptr sec ATTRIBUTE_UNUSED) +bfd_init_section_compress_status (bfd *abfd, sec_ptr sec) { -#ifndef HAVE_ZLIB_H - bfd_set_error (bfd_error_invalid_operation); - return FALSE; -#else bfd_size_type uncompressed_size; bfd_byte *uncompressed_buffer; bfd_boolean ret; @@ -418,11 +554,50 @@ bfd_init_section_compress_status (bfd *abfd ATTRIBUTE_UNUSED, 0, uncompressed_size)) ret = FALSE; else - ret = bfd_compress_section_contents (abfd, sec, - uncompressed_buffer, - uncompressed_size); + { + uncompressed_size = bfd_compress_section_contents (abfd, sec, + uncompressed_buffer, + uncompressed_size); + ret = uncompressed_size != 0; + } - free (uncompressed_buffer); return ret; -#endif +} + +/* +FUNCTION + bfd_compress_section + +SYNOPSIS + bfd_boolean bfd_compress_section + (bfd *abfd, asection *section, bfd_byte *uncompressed_buffer); + +DESCRIPTION + If open for write, compress section, update section size with + compressed size and set compress_status to COMPRESS_SECTION_DONE. + + Return @code{FALSE} if compression fail. Otherwise, return + @code{TRUE}. +*/ + +bfd_boolean +bfd_compress_section (bfd *abfd, sec_ptr sec, bfd_byte *uncompressed_buffer) +{ + bfd_size_type uncompressed_size = sec->size; + + /* Error if not opened for write. */ + if (abfd->direction != write_direction + || uncompressed_size == 0 + || uncompressed_buffer == NULL + || sec->contents != NULL + || sec->compressed_size != 0 + || sec->compress_status != COMPRESS_SECTION_NONE) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + /* Compress it. */ + return bfd_compress_section_contents (abfd, sec, uncompressed_buffer, + uncompressed_size) != 0; } diff --git a/contrib/gdb-7/bfd/config.bfd b/contrib/gdb-7/bfd/config.bfd index 10820e2cba..e08bb3b254 100644 --- a/contrib/gdb-7/bfd/config.bfd +++ b/contrib/gdb-7/bfd/config.bfd @@ -1,6 +1,6 @@ # config.bfd # -# Copyright 2012, 2013 Free Software Foundation +# Copyright (C) 2012-2015 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 @@ -48,6 +48,11 @@ targ_underscore=no # Catch obsolete configurations. case $targ in + openrisc-*-* | or32-*-*) + echo "*** Configuration $targ is obsolete." >&2 + echo "*** Use or1k-*-elf or or1k-*-linux as the target instead" >&2 + exit 1 + ;; null) if test "x$enable_obsolete" != xyes; then echo "*** Configuration $targ is obsolete." >&2 @@ -59,24 +64,23 @@ case $targ in esac case $targ in - m68*-apple-aux* | \ - m68*-apollo-* | \ - m68*-bull-sysv* | \ - m68*-*-rtemscoff* | \ - maxq-*-coff | \ - i960-*-rtems* | \ - or32-*-rtems* | \ - m68*-*-lynxos* | \ - sparc-*-lynxos* | \ - vax-*-vms* | \ - arm-*-oabi | \ + *-go32-rtems* | \ a29k-* | \ + arm-*-oabi | \ hppa*-*-rtems* | \ - *-go32-rtems* | \ + i960-*-rtems* | \ i[3-7]86*-*-rtemscoff* | \ + m68*-*-lynxos* | \ + m68*-*-rtemscoff* | \ + m68*-apollo-* | \ + m68*-apple-aux* | \ + m68*-bull-sysv* | \ + maxq-*-coff | \ mips*el-*-rtems* | \ powerpcle-*-rtems* | \ sparc*-*-rtemsaout* | \ + sparc-*-lynxos* | \ + vax-*-vms* | \ null) echo "*** Configuration $targ is obsolete." >&2 echo "*** Support has been REMOVED." >&2 @@ -109,8 +113,9 @@ m68*) targ_archs=bfd_m68k_arch ;; m88*) targ_archs=bfd_m88k_arch ;; microblaze*) targ_archs=bfd_microblaze_arch ;; mips*) targ_archs=bfd_mips_arch ;; +nds32*) targ_archs=bfd_nds32_arch ;; nios2*) targ_archs=bfd_nios2_arch ;; -or32*) targ_archs=bfd_or32_arch ;; +or1k*|or1knd*) targ_archs=bfd_or1k_arch ;; pdp11*) targ_archs=bfd_pdp11_arch ;; pj*) targ_archs="bfd_pj_arch bfd_i386_arch";; powerpc*) targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;; @@ -122,6 +127,7 @@ spu*) targ_archs=bfd_spu_arch ;; tilegx*) targ_archs=bfd_tilegx_arch ;; tilepro*) targ_archs=bfd_tilepro_arch ;; v850*) targ_archs="bfd_v850_arch bfd_v850_rh850_arch" ;; +visium*) targ_archs=bfd_visium_arch ;; x86_64*) targ_archs=bfd_i386_arch ;; xtensa*) targ_archs=bfd_xtensa_arch ;; xgate) targ_archs=bfd_xgate_arch ;; @@ -163,28 +169,33 @@ case "${targ}" in # START OF targmatch.h #ifdef BFD64 aarch64-*-elf) - targ_defvec=bfd_elf64_littleaarch64_vec - targ_selvecs="bfd_elf64_bigaarch64_vec bfd_elf32_littlearm_vec bfd_elf32_bigarm_vec" + targ_defvec=aarch64_elf64_le_vec + targ_selvecs="aarch64_elf64_be_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec" want64=true ;; aarch64_be-*-elf) - targ_defvec=bfd_elf64_bigaarch64_vec - targ_selvecs="bfd_elf64_littleaarch64_vec bfd_elf32_bigarm_vec bfd_elf32_littlearm_vec" + targ_defvec=aarch64_elf64_be_vec + targ_selvecs="aarch64_elf64_le_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_be_vec arm_elf32_le_vec" + want64=true + ;; + aarch64-*-freebsd*) + targ_defvec=aarch64_elf64_le_vec + targ_selvecs="aarch64_elf64_be_vec arm_elf32_le_vec arm_elf32_be_vec" want64=true ;; aarch64-*-linux*) - targ_defvec=bfd_elf64_littleaarch64_vec - targ_selvecs="bfd_elf64_bigaarch64_vec bfd_elf32_littlearm_vec bfd_elf32_bigarm_vec" + targ_defvec=aarch64_elf64_le_vec + targ_selvecs="aarch64_elf64_be_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec" want64=true ;; aarch64_be-*-linux*) - targ_defvec=bfd_elf64_bigaarch64_vec - targ_selvecs="bfd_elf64_littleaarch64_vec bfd_elf32_bigarm_vec bfd_elf32_littlearm_vec" + targ_defvec=aarch64_elf64_be_vec + targ_selvecs="aarch64_elf64_le_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_be_vec arm_elf32_le_vec" want64=true ;; alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu) - targ_defvec=bfd_elf64_alpha_freebsd_vec - targ_selvecs="bfd_elf64_alpha_vec ecoffalpha_little_vec" + targ_defvec=alpha_elf64_fbsd_vec + targ_selvecs="alpha_elf64_vec alpha_ecoff_le_vec" want64=true # FreeBSD <= 4.0 supports only the old nonstandard way of ABI labelling. case "${targ}" in @@ -193,170 +204,170 @@ case "${targ}" in esac ;; alpha*-*-netbsd* | alpha*-*-openbsd*) - targ_defvec=bfd_elf64_alpha_vec - targ_selvecs=ecoffalpha_little_vec + targ_defvec=alpha_elf64_vec + targ_selvecs=alpha_ecoff_le_vec want64=true ;; alpha*-*-netware*) - targ_defvec=ecoffalpha_little_vec - targ_selvecs=nlm32_alpha_vec + targ_defvec=alpha_ecoff_le_vec + targ_selvecs=alpha_nlm32_vec want64=true ;; - alpha*-*-linuxecoff*) - targ_defvec=ecoffalpha_little_vec - targ_selvecs=bfd_elf64_alpha_vec + alpha*-*-linux*ecoff*) + targ_defvec=alpha_ecoff_le_vec + targ_selvecs=alpha_elf64_vec want64=true ;; alpha*-*-linux-* | alpha*-*-elf*) - targ_defvec=bfd_elf64_alpha_vec - targ_selvecs=ecoffalpha_little_vec + targ_defvec=alpha_elf64_vec + targ_selvecs=alpha_ecoff_le_vec want64=true ;; alpha*-*-*vms*) - targ_defvec=vms_alpha_vec - targ_selvecs=vms_lib_txt_vec + targ_defvec=alpha_vms_vec + targ_selvecs=alpha_vms_lib_txt_vec want64=true ;; alpha*-*-*) - targ_defvec=ecoffalpha_little_vec + targ_defvec=alpha_ecoff_le_vec want64=true ;; ia64*-*-freebsd* | ia64*-*-netbsd* | ia64*-*-linux-* | ia64*-*-elf* | ia64*-*-kfreebsd*-gnu) - targ_defvec=bfd_elf64_ia64_little_vec - targ_selvecs="bfd_elf64_ia64_big_vec bfd_pei_ia64_vec" + targ_defvec=ia64_elf64_le_vec + targ_selvecs="ia64_elf64_be_vec ia64_pei_vec" want64=true ;; ia64*-*-hpux*) - targ_defvec=bfd_elf32_ia64_hpux_big_vec - targ_selvecs="bfd_elf64_ia64_hpux_big_vec" + targ_defvec=ia64_elf32_hpux_be_vec + targ_selvecs="ia64_elf64_hpux_be_vec" want64=true ;; ia64*-*-*vms*) - targ_defvec=bfd_elf64_ia64_vms_vec - targ_selvecs=vms_lib_txt_vec + targ_defvec=ia64_elf64_vms_vec + targ_selvecs=alpha_vms_lib_txt_vec want64=true ;; sparc64-*-freebsd* | sparc64-*-kfreebsd*-gnu) - targ_defvec=bfd_elf64_sparc_freebsd_vec - targ_selvecs="bfd_elf64_sparc_vec bfd_elf32_sparc_vec sunos_big_vec" + targ_defvec=sparc_elf64_fbsd_vec + targ_selvecs="sparc_elf64_vec sparc_elf32_vec sparc_aout_sunos_be_vec" ;; sparc64-*-netbsd* | sparc64-*-openbsd*) - targ_defvec=bfd_elf64_sparc_vec - targ_selvecs="bfd_elf32_sparc_vec sunos_big_vec" + targ_defvec=sparc_elf64_vec + targ_selvecs="sparc_elf32_vec sparc_aout_sunos_be_vec" want64=true ;; #endif /* BFD64 */ am34-*-linux* | am33_2.0-*-linux*) - targ_defvec=bfd_elf32_am33lin_vec + targ_defvec=am33_elf32_linux_vec ;; arc-*-elf*) - targ_defvec=bfd_elf32_littlearc_vec - targ_selvecs=bfd_elf32_bigarc_vec + targ_defvec=arc_elf32_le_vec + targ_selvecs=arc_elf32_be_vec ;; arm-*-nacl*) - targ_defvec=bfd_elf32_littlearm_nacl_vec - targ_selvecs="bfd_elf32_bigarm_nacl_vec bfd_elf32_i386_nacl_vec" - targ64_selvecs="bfd_elf32_x86_64_nacl_vec bfd_elf64_x86_64_nacl_vec" + targ_defvec=arm_elf32_nacl_le_vec + targ_selvecs="arm_elf32_nacl_be_vec i386_elf32_nacl_vec" + targ64_selvecs="x86_64_elf32_nacl_vec x86_64_elf64_nacl_vec" targ_archs="$targ_archs bfd_i386_arch" ;; armeb-*-nacl*) - targ_defvec=bfd_elf32_bigarm_nacl_vec - targ_selvecs="bfd_elf32_littlearm_nacl_vec bfd_elf32_i386_nacl_vec" - targ64_selvecs="bfd_elf32_x86_64_nacl_vec bfd_elf64_x86_64_nacl_vec" + targ_defvec=arm_elf32_nacl_be_vec + targ_selvecs="arm_elf32_nacl_le_vec i386_elf32_nacl_vec" + targ64_selvecs="x86_64_elf32_nacl_vec x86_64_elf64_nacl_vec" targ_archs="$targ_archs bfd_i386_arch" ;; armeb-*-netbsdelf*) - targ_defvec=bfd_elf32_bigarm_vec - targ_selvecs="bfd_elf32_littlearm_vec armnetbsd_vec" + targ_defvec=arm_elf32_be_vec + targ_selvecs="arm_elf32_le_vec arm_aout_nbsd_vec" ;; arm-*-netbsdelf*) - targ_defvec=bfd_elf32_littlearm_vec - targ_selvecs="bfd_elf32_bigarm_vec armnetbsd_vec" + targ_defvec=arm_elf32_le_vec + targ_selvecs="arm_elf32_be_vec arm_aout_nbsd_vec" ;; arm-*-netbsd* | arm-*-openbsd*) - targ_defvec=armnetbsd_vec - targ_selvecs="bfd_elf32_littlearm_vec bfd_elf32_bigarm_vec" + targ_defvec=arm_aout_nbsd_vec + targ_selvecs="arm_elf32_le_vec arm_elf32_be_vec" targ_underscore=yes - targ_cflags=-D__QNXTARGET__ ;; arm-*-nto* | nto*arm*) - targ_defvec=bfd_elf32_littlearm_vec - targ_selvecs=bfd_elf32_bigarm_vec + targ_defvec=arm_elf32_le_vec + targ_selvecs=arm_elf32_be_vec + targ_cflags=-D__QNXTARGET__ ;; arm-*-riscix*) - targ_defvec=riscix_vec + targ_defvec=arm_aout_riscix_vec ;; arm-epoc-pe*) - targ_defvec=arm_epoc_pe_little_vec - targ_selvecs="arm_epoc_pe_little_vec arm_epoc_pe_big_vec arm_epoc_pei_little_vec arm_epoc_pei_big_vec" + targ_defvec=arm_pe_epoc_le_vec + targ_selvecs="arm_pe_epoc_le_vec arm_pe_epoc_be_vec arm_pei_epoc_le_vec arm_pei_epoc_be_vec" targ_underscore=no targ_cflags=-DARM_COFF_BUGFIX ;; arm-wince-pe | arm-*-wince | arm*-*-mingw32ce* | arm*-*-cegcc*) - targ_defvec=arm_wince_pe_little_vec - targ_selvecs="arm_wince_pe_little_vec arm_wince_pe_big_vec arm_wince_pei_little_vec arm_wince_pei_big_vec" + targ_defvec=arm_pe_wince_le_vec + targ_selvecs="arm_pe_wince_le_vec arm_pe_wince_be_vec arm_pei_wince_le_vec arm_pei_wince_be_vec" targ_underscore=no targ_cflags="-DARM_WINCE -DARM_COFF_BUGFIX" ;; arm-*-pe*) - targ_defvec=armpe_little_vec - targ_selvecs="armpe_little_vec armpe_big_vec armpei_little_vec armpei_big_vec" + targ_defvec=arm_pe_le_vec + targ_selvecs="arm_pe_le_vec arm_pe_be_vec arm_pei_le_vec arm_pei_be_vec" targ_underscore=yes ;; arm-*-aout | armel-*-aout) - targ_defvec=aout_arm_little_vec - targ_selvecs=aout_arm_big_vec + targ_defvec=arm_aout_le_vec + targ_selvecs=arm_aout_be_vec ;; armeb-*-aout) - targ_defvec=aout_arm_big_vec - targ_selvecs=aout_arm_little_vec + targ_defvec=arm_aout_be_vec + targ_selvecs=arm_aout_le_vec ;; arm-*-coff) - targ_defvec=armcoff_little_vec - targ_selvecs=armcoff_big_vec + targ_defvec=arm_coff_le_vec + targ_selvecs=arm_coff_be_vec targ_underscore=yes ;; arm-*-rtems*) - targ_defvec=bfd_elf32_littlearm_vec - targ_selvecs=bfd_elf32_bigarm_vec + targ_defvec=arm_elf32_le_vec + targ_selvecs=arm_elf32_be_vec ;; - armeb-*-elf | arm*b-*-linux-*) - targ_defvec=bfd_elf32_bigarm_vec - targ_selvecs=bfd_elf32_littlearm_vec + armeb-*-elf | arm*b-*-freebsd* | arm*b-*-linux-* | armeb-*-eabi*) + targ_defvec=arm_elf32_be_vec + targ_selvecs=arm_elf32_le_vec ;; arm-*-kaos*) - targ_defvec=bfd_elf32_littlearm_vec - targ_selvecs=bfd_elf32_bigarm_vec + targ_defvec=arm_elf32_le_vec + targ_selvecs=arm_elf32_be_vec ;; - arm-*-elf | arm-*-freebsd* | arm*-*-linux-* | arm*-*-conix* | \ + arm-*-elf | arm*-*-freebsd* | arm*-*-linux-* | arm*-*-conix* | \ arm*-*-uclinux* | arm-*-kfreebsd*-gnu | \ arm*-*-eabi* ) - targ_defvec=bfd_elf32_littlearm_vec - targ_selvecs=bfd_elf32_bigarm_vec + targ_defvec=arm_elf32_le_vec + targ_selvecs=arm_elf32_be_vec ;; arm*-*-vxworks | arm*-*-windiss) - targ_defvec=bfd_elf32_littlearm_vxworks_vec - targ_selvecs=bfd_elf32_bigarm_vxworks_vec + targ_defvec=arm_elf32_vxworks_le_vec + targ_selvecs=arm_elf32_vxworks_be_vec ;; arm*-*-symbianelf*) - targ_defvec=bfd_elf32_littlearm_symbian_vec - targ_selvecs=bfd_elf32_bigarm_symbian_vec + targ_defvec=arm_elf32_symbian_le_vec + targ_selvecs=arm_elf32_symbian_be_vec ;; arm9e-*-elf) - targ_defvec=bfd_elf32_littlearm_vec - targ_selvecs=bfd_elf32_bigarm_vec + targ_defvec=arm_elf32_le_vec + targ_selvecs=arm_elf32_be_vec ;; avr-*-*) - targ_defvec=bfd_elf32_avr_vec + targ_defvec=avr_elf32_vec ;; bfin-*-*) - targ_defvec=bfd_elf32_bfin_vec - targ_selvecs=bfd_elf32_bfinfdpic_vec + targ_defvec=bfin_elf32_vec + targ_selvecs=bfin_elf32_fdpic_vec targ_underscore=yes ;; @@ -380,211 +391,223 @@ case "${targ}" in ;; cr16-*-elf* | cr16*-*-uclinux*) - targ_defvec=bfd_elf32_cr16_vec + targ_defvec=cr16_elf32_vec targ_underscore=yes ;; cr16c-*-elf*) - targ_defvec=bfd_elf32_cr16c_vec + targ_defvec=cr16c_elf32_vec targ_underscore=yes ;; cris-*-* | crisv32-*-*) targ_defvec=cris_aout_vec - targ_selvecs="bfd_elf32_us_cris_vec bfd_elf32_cris_vec ieee_vec" - targ_underscore=yes # Note: not true for bfd_elf32_cris_vec. + targ_selvecs="cris_elf32_us_vec cris_elf32_vec ieee_vec" + targ_underscore=yes # Note: not true for cris_elf32_vec. ;; crx-*-elf*) - targ_defvec=bfd_elf32_crx_vec + targ_defvec=crx_elf32_vec targ_underscore=yes ;; d10v-*-*) - targ_defvec=bfd_elf32_d10v_vec + targ_defvec=d10v_elf32_vec ;; dlx-*-elf*) - targ_defvec=bfd_elf32_dlx_big_vec - targ_selvecs="bfd_elf32_dlx_big_vec" + targ_defvec=dlx_elf32_be_vec + targ_selvecs="dlx_elf32_be_vec" ;; d30v-*-*) - targ_defvec=bfd_elf32_d30v_vec + targ_defvec=d30v_elf32_vec ;; epiphany-*-elf) - targ_defvec=bfd_elf32_epiphany_vec + targ_defvec=epiphany_elf32_vec ;; fido-*-elf* ) - targ_defvec=bfd_elf32_m68k_vec - targ_selvecs="m68kcoff_vec ieee_vec" + targ_defvec=m68k_elf32_vec + targ_selvecs="m68k_coff_vec ieee_vec" ;; fr30-*-elf) - targ_defvec=bfd_elf32_fr30_vec + targ_defvec=fr30_elf32_vec ;; frv-*-elf) - targ_defvec=bfd_elf32_frv_vec - targ_selvecs=bfd_elf32_frvfdpic_vec + targ_defvec=frv_elf32_vec + targ_selvecs=frv_elf32_fdpic_vec ;; frv-*-*linux*) - targ_defvec=bfd_elf32_frvfdpic_vec - targ_selvecs=bfd_elf32_frv_vec + targ_defvec=frv_elf32_fdpic_vec + targ_selvecs=frv_elf32_vec ;; moxie-*-elf | moxie-*-rtems* | moxie-*-uclinux) - targ_defvec=bfd_elf32_bigmoxie_vec - targ_selvecs=bfd_elf32_littlemoxie_vec + targ_defvec=moxie_elf32_be_vec + targ_selvecs=moxie_elf32_le_vec + ;; + + moxie-*-moxiebox*) + targ_defvec=moxie_elf32_le_vec ;; h8300*-*-rtemscoff*) - targ_defvec=h8300coff_vec + targ_defvec=h8300_coff_vec targ_underscore=yes ;; h8300*-*-elf | h8300*-*-rtems*) - targ_defvec=bfd_elf32_h8300_vec + targ_defvec=h8300_elf32_vec targ_underscore=yes ;; + h8300*-*-linux*) + targ_defvec=h8300_elf32_linux_vec + ;; + h8300*-*-*) - targ_defvec=h8300coff_vec + targ_defvec=h8300_coff_vec targ_underscore=yes ;; h8500-*-*) - targ_defvec=h8500coff_vec + targ_defvec=h8500_coff_vec targ_underscore=yes ;; #ifdef BFD64 hppa*64*-*-linux-*) - targ_defvec=bfd_elf64_hppa_linux_vec - targ_selvecs=bfd_elf64_hppa_vec + targ_defvec=hppa_elf64_linux_vec + targ_selvecs=hppa_elf64_vec want64=true ;; hppa*64*-*-hpux11*) - targ_defvec=bfd_elf64_hppa_vec - targ_selvecs=bfd_elf64_hppa_linux_vec + targ_defvec=hppa_elf64_vec + targ_selvecs=hppa_elf64_linux_vec targ_cflags=-DHPUX_LARGE_AR_IDS want64=true ;; #endif hppa*-*-linux-*) - targ_defvec=bfd_elf32_hppa_linux_vec - targ_selvecs=bfd_elf32_hppa_vec + targ_defvec=hppa_elf32_linux_vec + targ_selvecs=hppa_elf32_vec ;; hppa*-*-netbsd*) - targ_defvec=bfd_elf32_hppa_nbsd_vec - targ_selvecs="bfd_elf32_hppa_vec bfd_elf32_hppa_linux_vec" + targ_defvec=hppa_elf32_nbsd_vec + targ_selvecs="hppa_elf32_vec hppa_elf32_linux_vec" ;; hppa*-*-*elf* | hppa*-*-lites* | hppa*-*-sysv4* | hppa*-*-openbsd*) - targ_defvec=bfd_elf32_hppa_vec - targ_selvecs=bfd_elf32_hppa_linux_vec + targ_defvec=hppa_elf32_vec + targ_selvecs=hppa_elf32_linux_vec ;; hppa*-*-bsd*) - targ_defvec=som_vec - targ_selvecs=bfd_elf32_hppa_vec + targ_defvec=hppa_som_vec + targ_selvecs=hppa_elf32_vec ;; hppa*-*-hpux* | hppa*-*-hiux* | hppa*-*-mpeix*) - targ_defvec=som_vec + targ_defvec=hppa_som_vec ;; hppa*-*-osf*) - targ_defvec=som_vec - targ_selvecs=bfd_elf32_hppa_vec + targ_defvec=hppa_som_vec + targ_selvecs=hppa_elf32_vec ;; i370-*-*) - targ_defvec=bfd_elf32_i370_vec - targ_selvecs="bfd_elf32_i370_vec" + targ_defvec=i370_elf32_vec + targ_selvecs="i370_elf32_vec" ;; i[3-7]86-*-sco3.2v5*coff) - targ_defvec=i386coff_vec - targ_selvecs=bfd_elf32_i386_vec + targ_defvec=i386_coff_vec + targ_selvecs=i386_elf32_vec ;; i[3-7]86-*-sysv4* | i[3-7]86-*-unixware* | \ - i[3-7]86-*-elf | i[3-7]86-*-sco3.2v5* | \ + i[3-7]86-*-elf* | i[3-7]86-*-sco3.2v5* | \ i[3-7]86-*-dgux* | i[3-7]86-*-sysv5*) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs=i386coff_vec + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_coff_vec" ;; i[3-7]86-*-solaris2*) - targ_defvec=bfd_elf32_i386_sol2_vec - targ_selvecs="i386coff_vec" - targ64_selvecs="bfd_elf64_x86_64_sol2_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec" + targ_defvec=i386_elf32_sol2_vec + targ_selvecs="i386_coff_vec" + targ64_selvecs="x86_64_elf64_sol2_vec l1om_elf64_vec k1om_elf64_vec" want64=true ;; #ifdef BFD64 x86_64-*-solaris2*) - targ_defvec=bfd_elf32_i386_sol2_vec - targ_selvecs="bfd_elf64_x86_64_sol2_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec i386coff_vec" + targ_defvec=i386_elf32_sol2_vec + targ_selvecs="x86_64_elf64_sol2_vec l1om_elf64_vec k1om_elf64_vec i386_coff_vec" want64=true ;; #endif i[3-7]86-*-kaos*) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs=bfd_elf32_i386_vec + targ_defvec=i386_elf32_vec + targ_selvecs=i386_elf32_vec ;; i[3-7]86-*-nto*) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs=i386coff_vec + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_coff_vec" ;; i[3-7]86-*-aros*) - targ_defvec=bfd_elf32_i386_vec + targ_defvec=i386_elf32_vec + targ_selvecs=iamcu_elf32_vec ;; i[3-7]86-*-chorus*) - targ_defvec=bfd_elf32_i386_vec + targ_defvec=i386_elf32_vec + targ_selvecs=iamcu_elf32_vec ;; i[3-7]86-*-dicos*) - targ_defvec=bfd_elf32_i386_vec - targ64_selvecs="bfd_elf64_x86_64_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec" + targ_defvec=i386_elf32_vec + targ_selvecs=iamcu_elf32_vec + targ64_selvecs="x86_64_elf64_vec l1om_elf64_vec k1om_elf64_vec" ;; *-*-msdosdjgpp* | *-*-go32* ) - targ_defvec=go32coff_vec - targ_selvecs="go32stubbedcoff_vec i386aout_vec" + targ_defvec=i386_coff_go32_vec + targ_selvecs="i386_coff_go32stubbed_vec i386_aout_vec" ;; i[3-7]86-*-sysv* | i[3-7]86-*-isc* | i[3-7]86-*-sco* | i[3-7]86-*-coff | \ i[3-7]86-*-aix*) - targ_defvec=i386coff_vec + targ_defvec=i386_coff_vec ;; i[3-7]86-*-rtems*) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs="i386coff_vec i386aout_vec" + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_coff_vec i386_aout_vec" ;; i[3-7]86-*-darwin* | i[3-7]86-*-macos10* | i[3-7]86-*-rhapsody*) - targ_defvec=mach_o_i386_vec + targ_defvec=i386_mach_o_vec targ_selvecs="mach_o_le_vec mach_o_be_vec mach_o_fat_vec pef_vec pef_xlib_vec sym_vec" - targ64_selvecs=mach_o_x86_64_vec + targ64_selvecs=x86_64_mach_o_vec targ_archs="$targ_archs bfd_powerpc_arch bfd_rs6000_arch" ;; i[3-7]86-sequent-bsd*) - targ_defvec=i386dynix_vec + targ_defvec=i386_aout_dynix_vec targ_underscore=yes ;; i[3-7]86-*-bsd*) - targ_defvec=i386bsd_vec + targ_defvec=i386_aout_bsd_vec targ_underscore=yes ;; i[3-7]86-*-dragonfly*) - targ_defvec=bfd_elf32_i386_vec - targ64_selvecs="bfd_elf64_x86_64_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec" + targ_defvec=i386_elf32_vec + targ_selvecs=iamcu_elf32_vec + targ64_selvecs="x86_64_elf64_vec l1om_elf64_vec k1om_elf64_vec" ;; i[3-7]86-*-freebsdaout* | i[3-7]86-*-freebsd[12].* | \ i[3-7]86-*-freebsd[12]) - targ_defvec=i386freebsd_vec - targ_selvecs=i386bsd_vec + targ_defvec=i386_aout_fbsd_vec + targ_selvecs=i386_aout_bsd_vec targ_underscore=yes ;; i[3-7]86-*-freebsd* | i[3-7]86-*-kfreebsd*-gnu) - targ_defvec=bfd_elf32_i386_freebsd_vec - targ_selvecs="bfd_elf32_i386_vec i386pei_vec i386coff_vec" - targ64_selvecs="bfd_elf64_x86_64_freebsd_vec bfd_elf64_x86_64_vec x86_64pei_vec bfd_elf64_l1om_vec bfd_elf64_l1om_freebsd_vec bfd_elf64_k1om_vec bfd_elf64_k1om_freebsd_vec" + targ_defvec=i386_elf32_fbsd_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec i386_pei_vec i386_coff_vec" + targ64_selvecs="x86_64_elf64_fbsd_vec x86_64_elf64_vec x86_64_pei_vec l1om_elf64_vec l1om_elf64_fbsd_vec k1om_elf64_vec k1om_elf64_fbsd_vec" # FreeBSD <= 4.0 supports only the old nonstandard way of ABI labelling. case "${targ}" in i[3-7]86-*-freebsd3* | i[3-7]86-*-freebsd4 | i[3-7]86-*-freebsd4.0*) @@ -592,585 +615,589 @@ case "${targ}" in esac ;; i[3-7]86-*-netbsdelf* | i[3-7]86-*-netbsd*-gnu* | i[3-7]86-*-knetbsd*-gnu) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs=i386netbsd_vec - targ64_selvecs="bfd_elf64_x86_64_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec" + targ_defvec=i386_elf32_vec + targ_selvecs="i386_aout_nbsd_vec iamcu_elf32_vec" + targ64_selvecs="x86_64_elf64_vec l1om_elf64_vec k1om_elf64_vec" ;; i[3-7]86-*-netbsdpe*) - targ_defvec=i386pe_vec - targ_selvecs="i386pe_vec i386pei_vec bfd_elf32_i386_vec" + targ_defvec=i386_pe_vec + targ_selvecs="i386_pe_vec i386_pei_vec i386_elf32_vec iamcu_elf32_vec" ;; i[3-7]86-*-netbsdaout* | i[3-7]86-*-netbsd* | \ i[3-7]86-*-openbsd[0-2].* | i[3-7]86-*-openbsd3.[0-3]) - targ_defvec=i386netbsd_vec - targ_selvecs="bfd_elf32_i386_vec i386bsd_vec" + targ_defvec=i386_aout_nbsd_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec i386_aout_bsd_vec" targ_underscore=yes ;; i[3-7]86-*-openbsd*) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs=i386netbsd_vec + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_aout_nbsd_vec" ;; i[3-7]86-*-netware*) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs="nlm32_i386_vec i386coff_vec i386aout_vec" + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_nlm32_vec i386_coff_vec i386_aout_vec" ;; i[3-7]86-*-linux*aout*) - targ_defvec=i386linux_vec - targ_selvecs=bfd_elf32_i386_vec + targ_defvec=i386_aout_linux_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec" targ_underscore=yes ;; i[3-7]86-*-linux-*) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs="i386linux_vec i386pei_vec" - targ64_selvecs="bfd_elf64_x86_64_vec bfd_elf32_x86_64_vec x86_64pei_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec" + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_aout_linux_vec i386_pei_vec" + targ64_selvecs="x86_64_elf64_vec x86_64_elf32_vec x86_64_pei_vec l1om_elf64_vec k1om_elf64_vec" ;; i[3-7]86-*-nacl*) - targ_defvec=bfd_elf32_i386_nacl_vec - targ_selvecs="bfd_elf32_bigarm_nacl_vec bfd_elf32_littlearm_nacl_vec" - targ64_selvecs="bfd_elf64_x86_64_nacl_vec bfd_elf32_x86_64_nacl_vec" + targ_defvec=i386_elf32_nacl_vec + targ_selvecs="arm_elf32_nacl_be_vec arm_elf32_nacl_le_vec" + targ64_selvecs="x86_64_elf64_nacl_vec x86_64_elf32_nacl_vec" targ_archs="$targ_archs bfd_arm_arch" ;; #ifdef BFD64 + x86_64-*-cloudabi*) + targ_defvec=x86_64_elf64_cloudabi_vec + want64=true + ;; x86_64-*-darwin*) - targ_defvec=mach_o_x86_64_vec - targ_selvecs="mach_o_i386_vec mach_o_le_vec mach_o_be_vec mach_o_fat_vec pef_vec pef_xlib_vec sym_vec" + targ_defvec=x86_64_mach_o_vec + targ_selvecs="i386_mach_o_vec mach_o_le_vec mach_o_be_vec mach_o_fat_vec pef_vec pef_xlib_vec sym_vec" targ_archs="$targ_archs bfd_powerpc_arch bfd_rs6000_arch" want64=true ;; x86_64-*-dicos*) - targ_defvec=bfd_elf64_x86_64_vec - targ_selvecs="bfd_elf32_i386_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec" + targ_defvec=x86_64_elf64_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec l1om_elf64_vec k1om_elf64_vec" want64=true ;; x86_64-*-elf*) - targ_defvec=bfd_elf64_x86_64_vec - targ_selvecs="bfd_elf32_i386_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec i386coff_vec" + targ_defvec=x86_64_elf64_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec x86_64_elf32_vec l1om_elf64_vec k1om_elf64_vec" want64=true ;; x86_64-*-dragonfly*) - targ_defvec=bfd_elf64_x86_64_vec - targ_selvecs="bfd_elf32_i386_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec" + targ_defvec=x86_64_elf64_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec l1om_elf64_vec k1om_elf64_vec" want64=true ;; x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) - targ_defvec=bfd_elf64_x86_64_freebsd_vec - targ_selvecs="bfd_elf32_i386_freebsd_vec i386coff_vec i386pei_vec x86_64pei_vec bfd_elf32_i386_vec bfd_elf64_x86_64_vec bfd_elf64_l1om_vec bfd_elf64_l1om_freebsd_vec bfd_elf64_k1om_vec bfd_elf64_k1om_freebsd_vec" + targ_defvec=x86_64_elf64_fbsd_vec + targ_selvecs="i386_elf32_fbsd_vec iamcu_elf32_vec i386_coff_vec i386_pei_vec x86_64_pei_vec i386_elf32_vec x86_64_elf64_vec l1om_elf64_vec l1om_elf64_fbsd_vec k1om_elf64_vec k1om_elf64_fbsd_vec" want64=true ;; x86_64-*-netbsd* | x86_64-*-openbsd*) - targ_defvec=bfd_elf64_x86_64_vec - targ_selvecs="bfd_elf32_i386_vec i386netbsd_vec i386coff_vec i386pei_vec x86_64pei_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec" + targ_defvec=x86_64_elf64_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec i386_aout_nbsd_vec i386_coff_vec i386_pei_vec x86_64_pei_vec l1om_elf64_vec k1om_elf64_vec" want64=true ;; x86_64-*-linux-*) - targ_defvec=bfd_elf64_x86_64_vec - targ_selvecs="bfd_elf32_i386_vec bfd_elf32_x86_64_vec i386linux_vec i386pei_vec x86_64pei_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec" + targ_defvec=x86_64_elf64_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec x86_64_elf32_vec i386_aout_linux_vec i386_pei_vec x86_64_pei_vec l1om_elf64_vec k1om_elf64_vec" want64=true ;; x86_64-*-nacl*) - targ_defvec=bfd_elf32_x86_64_nacl_vec - targ_selvecs="bfd_elf32_i386_nacl_vec bfd_elf64_x86_64_nacl_vec bfd_elf32_bigarm_nacl_vec bfd_elf32_littlearm_nacl_vec" + targ_defvec=x86_64_elf32_nacl_vec + targ_selvecs="i386_elf32_nacl_vec x86_64_elf64_nacl_vec arm_elf32_nacl_be_vec arm_elf32_nacl_le_vec" targ_archs="$targ_archs bfd_arm_arch" want64=true ;; x86_64-*-mingw* | x86_64-*-pe | x86_64-*-pep | x86_64-*-cygwin) - targ_defvec=x86_64pe_vec - targ_selvecs="x86_64pe_vec x86_64pei_vec bfd_elf64_x86_64_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec i386pe_vec i386pei_vec bfd_elf32_i386_vec" + targ_defvec=x86_64_pe_vec + targ_selvecs="x86_64_pe_vec x86_64_pei_vec x86_64_pe_be_vec x86_64_elf64_vec l1om_elf64_vec k1om_elf64_vec i386_pe_vec i386_pei_vec i386_elf32_vec iamcu_elf32_vec" want64=true targ_underscore=no ;; x86_64-*-rdos*) - targ_defvec=bfd_elf64_x86_64_vec + targ_defvec=x86_64_elf64_vec want64=true ;; #endif i[3-7]86-*-lynxos*) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs="i386lynx_coff_vec i386lynx_aout_vec" + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_coff_lynx_vec i386_aout_lynx_vec" ;; i[3-7]86-*-gnu*) - targ_defvec=bfd_elf32_i386_vec + targ_defvec=i386_elf32_vec + targ_selvecs=iamcu_elf32_vec ;; i[3-7]86-*-mach* | i[3-7]86-*-osf1mk*) - targ_defvec=i386mach3_vec + targ_defvec=i386_aout_mach3_vec targ_cflags=-DSTAT_FOR_EXEC targ_underscore=yes ;; i[3-7]86-*-os9k) - targ_defvec=i386os9k_vec + targ_defvec=i386_aout_os9k_vec ;; i[3-7]86-*-msdos*) - targ_defvec=i386aout_vec - targ_selvecs=i386msdos_vec + targ_defvec=i386_aout_vec + targ_selvecs=i386_msdos_vec ;; i[3-7]86-*-moss*) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs="i386msdos_vec i386aout_vec" + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_msdos_vec i386_aout_vec" ;; i[3-7]86-*-beospe*) - targ_defvec=i386pe_vec - targ_selvecs="i386pe_vec i386pei_vec" + targ_defvec=i386_pe_vec + targ_selvecs="i386_pe_vec i386_pei_vec" ;; i[3-7]86-*-beoself* | i[3-7]86-*-beos*) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs="i386pe_vec i386pei_vec" + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_pe_vec i386_pei_vec" ;; i[3-7]86-*-interix*) - targ_defvec=i386pei_vec - targ_selvecs="i386pe_vec" + targ_defvec=i386_pei_vec + targ_selvecs="i386_pe_vec" # FIXME: This should eventually be checked at runtime. targ_cflags=-DSTRICT_PE_FORMAT ;; i[3-7]86-*-rdos*) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs=i386coff_vec + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_coff_vec" ;; i[3-7]86-*-mingw32* | i[3-7]86-*-cygwin* | i[3-7]86-*-winnt | i[3-7]86-*-pe) - targ_defvec=i386pe_vec - targ_selvecs="i386pe_vec i386pei_vec bfd_elf32_i386_vec" + targ_defvec=i386_pe_vec + targ_selvecs="i386_pe_vec i386_pei_vec i386_elf32_vec iamcu_elf32_vec" targ_underscore=yes ;; i[3-7]86-none-*) - targ_defvec=i386coff_vec + targ_defvec=i386_coff_vec ;; i[3-7]86-*-aout* | i[3-7]86*-*-vsta*) - targ_defvec=i386aout_vec + targ_defvec=i386_aout_vec ;; i[3-7]86-*-vxworks*) - targ_defvec=bfd_elf32_i386_vxworks_vec + targ_defvec=i386_elf32_vxworks_vec targ_underscore=yes ;; i[3-7]86-*-chaos) - targ_defvec=bfd_elf32_i386_vec - targ_selfvecs=i386chaos_vec + targ_defvec=i386_elf32_vec + targ_selfvecs="iamcu_elf32_vec i386chaos_vec" ;; i860-*-mach3* | i860-*-osf1* | i860-*-coff*) - targ_defvec=i860coff_vec + targ_defvec=i860_coff_vec ;; i860-stardent-sysv4* | i860-stardent-elf*) - targ_defvec=bfd_elf32_i860_little_vec - targ_selvecs="bfd_elf32_i860_vec bfd_elf32_i860_little_vec" + targ_defvec=i860_elf32_le_vec + targ_selvecs="i860_elf32_vec i860_elf32_le_vec" ;; i860-*-sysv4* | i860-*-elf*) - targ_defvec=bfd_elf32_i860_vec + targ_defvec=i860_elf32_vec ;; i960-*-vxworks4* | i960-*-vxworks5.0) - targ_defvec=b_out_vec_little_host - targ_selvecs="b_out_vec_big_host icoff_little_vec icoff_big_vec ieee_vec" + targ_defvec=bout_le_vec + targ_selvecs="bout_be_vec icoff_le_vec icoff_be_vec ieee_vec" targ_underscore=yes ;; i960-*-vxworks5.* | i960-*-coff* | i960-*-sysv*) - targ_defvec=icoff_little_vec - targ_selvecs="icoff_big_vec b_out_vec_little_host b_out_vec_big_host ieee_vec" + targ_defvec=icoff_le_vec + targ_selvecs="icoff_be_vec bout_le_vec bout_be_vec ieee_vec" targ_underscore=yes ;; i960-*-vxworks* | i960-*-aout* | i960-*-bout* | i960-*-nindy*) - targ_defvec=b_out_vec_little_host - targ_selvecs="b_out_vec_big_host icoff_little_vec icoff_big_vec ieee_vec" + targ_defvec=bout_le_vec + targ_selvecs="bout_be_vec icoff_le_vec icoff_be_vec ieee_vec" targ_underscore=yes ;; i960-*-elf*) - targ_defvec=bfd_elf32_i960_vec - targ_selvecs="icoff_little_vec icoff_big_vec" + targ_defvec=i960_elf32_vec + targ_selvecs="icoff_le_vec icoff_be_vec" ;; ip2k-*-elf) - targ_defvec=bfd_elf32_ip2k_vec + targ_defvec=ip2k_elf32_vec ;; iq2000-*-elf) - targ_defvec=bfd_elf32_iq2000_vec + targ_defvec=iq2000_elf32_vec ;; lm32-*-elf | lm32-*-rtems*) - targ_defvec=bfd_elf32_lm32_vec - targ_selvecs=bfd_elf32_lm32fdpic_vec + targ_defvec=lm32_elf32_vec + targ_selvecs=lm32_elf32_fdpic_vec ;; lm32-*-*linux*) - targ_defvec=bfd_elf32_lm32fdpic_vec - targ_selvecs=bfd_elf32_lm32_vec + targ_defvec=lm32_elf32_fdpic_vec + targ_selvecs=lm32_elf32_vec ;; m32c-*-elf | m32c-*-rtems*) - targ_defvec=bfd_elf32_m32c_vec + targ_defvec=m32c_elf32_vec ;; m32r*le-*-linux*) - targ_defvec=bfd_elf32_m32rlelin_vec - targ_selvecs="bfd_elf32_m32rlin_vec bfd_elf32_m32rlelin_vec" + targ_defvec=m32r_elf32_linux_le_vec + targ_selvecs="m32r_elf32_linux_vec m32r_elf32_linux_le_vec" ;; m32r*-*-linux*) - targ_defvec=bfd_elf32_m32rlin_vec - targ_selvecs="bfd_elf32_m32rlin_vec bfd_elf32_m32rlelin_vec" + targ_defvec=m32r_elf32_linux_vec + targ_selvecs="m32r_elf32_linux_vec m32r_elf32_linux_le_vec" ;; m32r*le-*-*) - targ_defvec=bfd_elf32_m32rle_vec - targ_selvecs="bfd_elf32_m32r_vec bfd_elf32_m32rle_vec" + targ_defvec=m32r_elf32_le_vec + targ_selvecs="m32r_elf32_vec m32r_elf32_le_vec" ;; m32r-*-*) - targ_defvec=bfd_elf32_m32r_vec + targ_defvec=m32r_elf32_vec ;; m68hc11-*-* | m6811-*-*) - targ_defvec=bfd_elf32_m68hc11_vec - targ_selvecs="bfd_elf32_m68hc11_vec bfd_elf32_m68hc12_vec" + targ_defvec=m68hc11_elf32_vec + targ_selvecs="m68hc11_elf32_vec m68hc12_elf32_vec" ;; m68hc12-*-* | m6812-*-*) - targ_defvec=bfd_elf32_m68hc12_vec - targ_selvecs="bfd_elf32_m68hc11_vec bfd_elf32_m68hc12_vec" + targ_defvec=m68hc12_elf32_vec + targ_selvecs="m68hc11_elf32_vec m68hc12_elf32_vec" ;; m68*-motorola-sysv*) - targ_defvec=m68ksysvcoff_vec + targ_defvec=m68k_coff_sysv_vec ;; m68*-hp-bsd*) - targ_defvec=hp300bsd_vec + targ_defvec=m68k_aout_hp300bsd_vec targ_underscore=yes ;; m68*-*-aout*) - targ_defvec=aout0_big_vec - # We include cisco_core_big_vec here, rather than making a separate cisco + targ_defvec=aout0_be_vec + # We include core_cisco_be_vec here, rather than making a separate cisco # configuration, so that cisco-core.c gets routinely tested at # least for compilation. - targ_selvecs="cisco_core_big_vec ieee_vec" + targ_selvecs="core_cisco_be_vec ieee_vec" targ_underscore=yes ;; m68*-*-elf* | m68*-*-sysv4* | m68*-*-uclinux*) - targ_defvec=bfd_elf32_m68k_vec - targ_selvecs="m68kcoff_vec ieee_vec" + targ_defvec=m68k_elf32_vec + targ_selvecs="m68k_coff_vec ieee_vec" ;; m68*-*-rtems*) - targ_defvec=bfd_elf32_m68k_vec - targ_selvecs="m68kcoff_vec versados_vec ieee_vec aout0_big_vec" + targ_defvec=m68k_elf32_vec + targ_selvecs="m68k_coff_vec m68k_versados_vec ieee_vec aout0_be_vec" ;; m68*-*-coff* | m68*-*-sysv*) - targ_defvec=m68kcoff_vec - targ_selvecs="m68kcoff_vec versados_vec ieee_vec" + targ_defvec=m68k_coff_vec + targ_selvecs="m68k_coff_vec m68k_versados_vec ieee_vec" ;; m68*-*-hpux*) - targ_defvec=hp300hpux_vec + targ_defvec=m68k_aout_hp300hpux_vec targ_underscore=yes ;; m68*-*-linux*aout*) - targ_defvec=m68klinux_vec - targ_selvecs=bfd_elf32_m68k_vec + targ_defvec=m68k_aout_linux_vec + targ_selvecs=m68k_elf32_vec targ_underscore=yes ;; m68*-*-linux-*) - targ_defvec=bfd_elf32_m68k_vec - targ_selvecs=m68klinux_vec + targ_defvec=m68k_elf32_vec + targ_selvecs=m68k_aout_linux_vec ;; m68*-*-gnu*) - targ_defvec=bfd_elf32_m68k_vec + targ_defvec=m68k_elf32_vec # targ_selvecs=m68kmach3_vec # targ_cflags=-DSTAT_FOR_EXEC ;; m68*-hp*-netbsd*) - targ_defvec=m68k4knetbsd_vec - targ_selvecs="m68knetbsd_vec hp300bsd_vec sunos_big_vec" + targ_defvec=m68k_aout_4knbsd_vec + targ_selvecs="m68k_aout_nbsd_vec m68k_aout_hp300bsd_vec sparc_aout_sunos_be_vec" targ_underscore=yes ;; m68*-*-netbsdelf*) - targ_defvec=bfd_elf32_m68k_vec - targ_selvecs="m68knetbsd_vec m68k4knetbsd_vec hp300bsd_vec sunos_big_vec" + targ_defvec=m68k_elf32_vec + targ_selvecs="m68k_aout_nbsd_vec m68k_aout_4knbsd_vec m68k_aout_hp300bsd_vec sparc_aout_sunos_be_vec" ;; m68*-*-netbsdaout* | m68*-*-netbsd*) - targ_defvec=m68knetbsd_vec - targ_selvecs="m68k4knetbsd_vec bfd_elf32_m68k_vec hp300bsd_vec sunos_big_vec" + targ_defvec=m68k_aout_nbsd_vec + targ_selvecs="m68k_aout_4knbsd_vec m68k_elf32_vec m68k_aout_hp300bsd_vec sparc_aout_sunos_be_vec" targ_underscore=yes ;; m68*-*-openbsd*) - targ_defvec=m68knetbsd_vec - targ_selvecs="m68k4knetbsd_vec hp300bsd_vec sunos_big_vec" + targ_defvec=m68k_aout_nbsd_vec + targ_selvecs="m68k_aout_4knbsd_vec m68k_aout_hp300bsd_vec sparc_aout_sunos_be_vec" targ_underscore=yes ;; m68*-*-sunos* | m68*-*-os68k* | m68*-*-vxworks* | m68*-netx-* | \ m68*-*-bsd* | m68*-*-vsta*) - targ_defvec=sunos_big_vec + targ_defvec=sparc_aout_sunos_be_vec targ_underscore=yes ;; m68*-ericsson-*) - targ_defvec=sunos_big_vec - targ_selvecs="m68kcoff_vec versados_vec tekhex_vec" + targ_defvec=sparc_aout_sunos_be_vec + targ_selvecs="m68k_coff_vec m68k_versados_vec tekhex_vec" targ_underscore=yes ;; m68*-cbm-*) - targ_defvec=bfd_elf32_m68k_vec - targ_selvecs=m68kcoff_vec + targ_defvec=m68k_elf32_vec + targ_selvecs=m68k_coff_vec ;; m68*-*-psos*) - targ_defvec=bfd_elf32_m68k_vec + targ_defvec=m68k_elf32_vec targ_selvecs=ieee_vec targ_underscore=yes ;; m88*-harris-cxux* | m88*-*-dgux* | m88*-*-sysv4*) - targ_defvec=bfd_elf32_m88k_vec - targ_selvecs=m88kbcs_vec + targ_defvec=m88k_elf32_vec + targ_selvecs=m88k_coff_bcs_vec ;; m88*-*-mach3*) - targ_defvec=m88kmach3_vec + targ_defvec=m88k_aout_mach3_vec targ_cflags=-DSTAT_FOR_EXEC ;; m88*-*-openbsd*) - targ_defvec=m88kopenbsd_vec + targ_defvec=m88k_aout_obsd_vec targ_underscore=yes ;; m88*-*-*) - targ_defvec=m88kbcs_vec + targ_defvec=m88k_coff_bcs_vec targ_underscore=yes ;; mcore-*-elf) - targ_defvec=bfd_elf32_mcore_big_vec - targ_selvecs="bfd_elf32_mcore_big_vec bfd_elf32_mcore_little_vec" + targ_defvec=mcore_elf32_be_vec + targ_selvecs="mcore_elf32_be_vec mcore_elf32_le_vec" ;; mcore-*-pe) - targ_defvec=mcore_pe_big_vec - targ_selvecs="mcore_pe_big_vec mcore_pe_little_vec mcore_pei_big_vec mcore_pei_little_vec" + targ_defvec=mcore_pe_be_vec + targ_selvecs="mcore_pe_be_vec mcore_pe_le_vec mcore_pei_be_vec mcore_pei_le_vec" ;; mep-*-elf) - targ_defvec=bfd_elf32_mep_vec - targ_selvecs=bfd_elf32_mep_little_vec + targ_defvec=mep_elf32_vec + targ_selvecs=mep_elf32_le_vec ;; metag-*-*) - targ_defvec=bfd_elf32_metag_vec + targ_defvec=metag_elf32_vec targ_underscore=yes ;; microblazeel*-*) - targ_defvec=bfd_elf32_microblazeel_vec - targ_selvecs=bfd_elf32_microblaze_vec + targ_defvec=microblaze_elf32_le_vec + targ_selvecs=microblaze_elf32_vec ;; microblaze*-*) - targ_defvec=bfd_elf32_microblaze_vec - targ_selvecs=bfd_elf32_microblazeel_vec + targ_defvec=microblaze_elf32_vec + targ_selvecs=microblaze_elf32_le_vec ;; mips*-big-*) - targ_defvec=ecoff_big_vec - targ_selvecs=ecoff_little_vec + targ_defvec=mips_ecoff_be_vec + targ_selvecs=mips_ecoff_le_vec ;; +#ifdef BFD64 mips*el-*-netbsd*) - targ_defvec=bfd_elf32_tradlittlemips_vec - targ_selvecs="bfd_elf32_tradbigmips_vec bfd_elf64_tradbigmips_vec bfd_elf64_tradlittlemips_vec ecoff_little_vec ecoff_big_vec" + targ_defvec=mips_elf32_trad_le_vec + targ_selvecs="mips_elf32_trad_be_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec mips_ecoff_le_vec mips_ecoff_be_vec" ;; mips*-*-netbsd*) - targ_defvec=bfd_elf32_tradbigmips_vec - targ_selvecs="bfd_elf32_tradlittlemips_vec bfd_elf64_tradbigmips_vec bfd_elf64_tradlittlemips_vec ecoff_big_vec ecoff_little_vec" + targ_defvec=mips_elf32_trad_be_vec + targ_selvecs="mips_elf32_trad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec mips_ecoff_be_vec mips_ecoff_le_vec" ;; +#endif mips*-dec-* | mips*el-*-ecoff*) - targ_defvec=ecoff_little_vec - targ_selvecs=ecoff_big_vec + targ_defvec=mips_ecoff_le_vec + targ_selvecs=mips_ecoff_be_vec ;; mips*-*-ecoff*) - targ_defvec=ecoff_big_vec - targ_selvecs=ecoff_little_vec + targ_defvec=mips_ecoff_be_vec + targ_selvecs=mips_ecoff_le_vec ;; #ifdef BFD64 mips*-*-irix6*) - targ_defvec=bfd_elf32_nbigmips_vec - targ_selvecs="bfd_elf32_nlittlemips_vec bfd_elf32_bigmips_vec bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" - want64=true + targ_defvec=mips_elf32_n_be_vec + targ_selvecs="mips_elf32_n_le_vec mips_elf32_be_vec mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec" ;; mips64*-ps2-elf*) - targ_defvec=bfd_elf32_nlittlemips_vec - targ_selvecs="bfd_elf32_nlittlemips_vec bfd_elf32_nbigmips_vec bfd_elf32_bigmips_vec bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" - want64=true + targ_defvec=mips_elf32_n_le_vec + targ_selvecs="mips_elf32_n_le_vec mips_elf32_n_be_vec mips_elf32_be_vec mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec" ;; -#endif mips*-ps2-elf*) - targ_defvec=bfd_elf32_littlemips_vec - targ_selvecs="bfd_elf32_bigmips_vec bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" + targ_defvec=mips_elf32_le_vec + targ_selvecs="mips_elf32_be_vec mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec" ;; mips*-*-irix5*) - targ_defvec=bfd_elf32_bigmips_vec - targ_selvecs="bfd_elf32_littlemips_vec ecoff_big_vec ecoff_little_vec" + targ_defvec=mips_elf32_be_vec + targ_selvecs="mips_elf32_le_vec mips_ecoff_be_vec mips_ecoff_le_vec" ;; +#endif mips*-sgi-* | mips*-*-bsd*) - targ_defvec=ecoff_big_vec - targ_selvecs=ecoff_little_vec + targ_defvec=mips_ecoff_be_vec + targ_selvecs=mips_ecoff_le_vec ;; mips*-*-lnews*) - targ_defvec=ecoff_biglittle_vec - targ_selvecs="ecoff_little_vec ecoff_big_vec" + targ_defvec=mips_ecoff_bele_vec + targ_selvecs="mips_ecoff_le_vec mips_ecoff_be_vec" ;; +#ifdef BFD64 mips*-*-sysv4*) - targ_defvec=bfd_elf32_tradbigmips_vec - targ_selvecs="bfd_elf32_tradlittlemips_vec ecoff_big_vec ecoff_little_vec" + targ_defvec=mips_elf32_trad_be_vec + targ_selvecs="mips_elf32_trad_le_vec mips_ecoff_be_vec mips_ecoff_le_vec" ;; +#endif mips*-*-sysv* | mips*-*-riscos*) - targ_defvec=ecoff_big_vec - targ_selvecs=ecoff_little_vec + targ_defvec=mips_ecoff_be_vec + targ_selvecs=mips_ecoff_le_vec ;; #ifdef BFD64 mips*el-*-vxworks*) - targ_defvec=bfd_elf32_littlemips_vxworks_vec - targ_selvecs="bfd_elf32_littlemips_vec bfd_elf32_bigmips_vxworks_vec bfd_elf32_bigmips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" - want64=true + targ_defvec=mips_elf32_vxworks_le_vec + targ_selvecs="mips_elf32_le_vec mips_elf32_vxworks_be_vec mips_elf32_be_vec mips_elf64_be_vec mips_elf64_le_vec" ;; mips*-*-vxworks*) - targ_defvec=bfd_elf32_bigmips_vxworks_vec - targ_selvecs="bfd_elf32_bigmips_vec bfd_elf32_littlemips_vxworks_vec bfd_elf32_bigmips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" - want64=true + targ_defvec=mips_elf32_vxworks_be_vec + targ_selvecs="mips_elf32_be_vec mips_elf32_vxworks_le_vec mips_elf32_be_vec mips_elf64_be_vec mips_elf64_le_vec" ;; -#endif mips*el-sde-elf*) - targ_defvec=bfd_elf32_tradlittlemips_vec - targ_selvecs="bfd_elf32_tradbigmips_vec bfd_elf32_ntradbigmips_vec bfd_elf32_ntradlittlemips_vec bfd_elf64_tradbigmips_vec bfd_elf64_tradlittlemips_vec" - want64=true + targ_defvec=mips_elf32_trad_le_vec + targ_selvecs="mips_elf32_trad_be_vec mips_elf32_ntrad_be_vec mips_elf32_ntrad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec" ;; - mips*-sde-elf* | mips*-mti-elf*) - targ_defvec=bfd_elf32_tradbigmips_vec - targ_selvecs="bfd_elf32_tradlittlemips_vec bfd_elf32_ntradbigmips_vec bfd_elf32_ntradlittlemips_vec bfd_elf64_tradbigmips_vec bfd_elf64_tradlittlemips_vec" - want64=true + mips*-sde-elf* | mips*-mti-elf* | mips*-img-elf*) + targ_defvec=mips_elf32_trad_be_vec + targ_selvecs="mips_elf32_trad_le_vec mips_elf32_ntrad_be_vec mips_elf32_ntrad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec" ;; mips*el-*-elf* | mips*el-*-vxworks* | mips*-*-chorus*) - targ_defvec=bfd_elf32_littlemips_vec - targ_selvecs="bfd_elf32_bigmips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" + targ_defvec=mips_elf32_le_vec + targ_selvecs="mips_elf32_be_vec mips_elf64_be_vec mips_elf64_le_vec" ;; mips*-*-elf* | mips*-*-rtems* | mips*-*-vxworks | mips*-*-windiss) - targ_defvec=bfd_elf32_bigmips_vec - targ_selvecs="bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" + targ_defvec=mips_elf32_be_vec + targ_selvecs="mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec" ;; mips*-*-none) - targ_defvec=bfd_elf32_bigmips_vec - targ_selvecs="bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" + targ_defvec=mips_elf32_be_vec + targ_selvecs="mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec" ;; -#ifdef BFD64 mips64*-*-openbsd*) - targ_defvec=bfd_elf64_tradbigmips_vec - targ_selvecs="bfd_elf32_ntradlittlemips_vec bfd_elf32_ntradbigmips_vec bfd_elf32_tradlittlemips_vec bfd_elf32_tradbigmips_vec bfd_elf64_tradlittlemips_vec" - want64=true + targ_defvec=mips_elf64_trad_be_vec + targ_selvecs="mips_elf32_ntrad_le_vec mips_elf32_ntrad_be_vec mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf64_trad_le_vec" ;; -#endif mips*el-*-openbsd*) - targ_defvec=bfd_elf32_littlemips_vec - targ_selvecs="bfd_elf32_bigmips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec ecoff_little_vec ecoff_big_vec" + targ_defvec=mips_elf32_le_vec + targ_selvecs="mips_elf32_be_vec mips_elf64_be_vec mips_elf64_le_vec mips_ecoff_le_vec mips_ecoff_be_vec" ;; mips*-*-openbsd*) - targ_defvec=bfd_elf32_bigmips_vec - targ_selvecs="bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec ecoff_big_vec ecoff_little_vec" + targ_defvec=mips_elf32_be_vec + targ_selvecs="mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec mips_ecoff_be_vec mips_ecoff_le_vec" ;; -#ifdef BFD64 mips64*el-*-linux*) - targ_defvec=bfd_elf32_ntradlittlemips_vec - targ_selvecs="bfd_elf32_ntradbigmips_vec bfd_elf32_tradlittlemips_vec bfd_elf32_tradbigmips_vec bfd_elf64_tradlittlemips_vec bfd_elf64_tradbigmips_vec" - want64=true + targ_defvec=mips_elf32_ntrad_le_vec + targ_selvecs="mips_elf32_ntrad_be_vec mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf64_trad_le_vec mips_elf64_trad_be_vec" ;; mips64*-*-linux*) - targ_defvec=bfd_elf32_ntradbigmips_vec - targ_selvecs="bfd_elf32_ntradlittlemips_vec bfd_elf32_tradbigmips_vec bfd_elf32_tradlittlemips_vec bfd_elf64_tradbigmips_vec bfd_elf64_tradlittlemips_vec" - want64=true + targ_defvec=mips_elf32_ntrad_be_vec + targ_selvecs="mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec" ;; mips*el-*-linux*) - targ_defvec=bfd_elf32_tradlittlemips_vec - targ_selvecs="bfd_elf32_tradbigmips_vec ecoff_little_vec ecoff_big_vec bfd_elf32_ntradlittlemips_vec bfd_elf64_tradlittlemips_vec bfd_elf32_ntradbigmips_vec bfd_elf64_tradbigmips_vec" - want64=true + targ_defvec=mips_elf32_trad_le_vec + targ_selvecs="mips_elf32_trad_be_vec mips_ecoff_le_vec mips_ecoff_be_vec mips_elf32_ntrad_le_vec mips_elf64_trad_le_vec mips_elf32_ntrad_be_vec mips_elf64_trad_be_vec" ;; mips*-*-linux*) - targ_defvec=bfd_elf32_tradbigmips_vec - targ_selvecs="bfd_elf32_tradlittlemips_vec ecoff_big_vec ecoff_little_vec bfd_elf32_ntradbigmips_vec bfd_elf64_tradbigmips_vec bfd_elf32_ntradlittlemips_vec bfd_elf64_tradlittlemips_vec" - want64=true + targ_defvec=mips_elf32_trad_be_vec + targ_selvecs="mips_elf32_trad_le_vec mips_ecoff_be_vec mips_ecoff_le_vec mips_elf32_ntrad_be_vec mips_elf64_trad_be_vec mips_elf32_ntrad_le_vec mips_elf64_trad_le_vec" ;; mips64*el-*-freebsd* | mips64*el-*-kfreebsd*-gnu) # FreeBSD vectors - targ_defvec=bfd_elf32_ntradlittlemips_freebsd_vec - targ_selvecs="bfd_elf32_ntradbigmips_freebsd_vec bfd_elf32_tradlittlemips_freebsd_vec bfd_elf32_tradbigmips_freebsd_vec bfd_elf64_tradlittlemips_freebsd_vec bfd_elf64_tradbigmips_freebsd_vec" + targ_defvec=mips_elf32_ntradfbsd_le_vec + targ_selvecs="mips_elf32_ntradfbsd_be_vec mips_elf32_tradfbsd_le_vec mips_elf32_tradfbsd_be_vec mips_elf64_tradfbsd_le_vec mips_elf64_tradfbsd_be_vec" # Generic vectors - targ_selvecs="${targ_selvecs} bfd_elf32_ntradlittlemips_vec bfd_elf32_ntradbigmips_vec bfd_elf32_tradlittlemips_vec bfd_elf32_tradbigmips_vec bfd_elf64_tradlittlemips_vec bfd_elf64_tradbigmips_vec" - want64=true + targ_selvecs="${targ_selvecs} mips_elf32_ntrad_le_vec mips_elf32_ntrad_be_vec mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf64_trad_le_vec mips_elf64_trad_be_vec" ;; mips64*-*-freebsd* | mips64*-*-kfreebsd*-gnu) # FreeBSD vectors - targ_defvec=bfd_elf32_ntradbigmips_freebsd_vec - targ_selvecs="bfd_elf32_ntradlittlemips_freebsd_vec bfd_elf32_tradbigmips_freebsd_vec bfd_elf32_tradlittlemips_freebsd_vec bfd_elf64_tradbigmips_freebsd_vec bfd_elf64_tradlittlemips_freebsd_vec" + targ_defvec=mips_elf32_ntradfbsd_be_vec + targ_selvecs="mips_elf32_ntradfbsd_le_vec mips_elf32_tradfbsd_be_vec mips_elf32_tradfbsd_le_vec mips_elf64_tradfbsd_be_vec mips_elf64_tradfbsd_le_vec" # Generic vectors - targ_selvecs="${targ_selvecs} bfd_elf32_ntradbigmips_vec bfd_elf32_ntradlittlemips_vec bfd_elf32_tradbigmips_vec bfd_elf32_tradlittlemips_vec bfd_elf64_tradbigmips_vec bfd_elf64_tradlittlemips_vec" - want64=true + targ_selvecs="${targ_selvecs} mips_elf32_ntrad_be_vec mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec" ;; -#endif mips*el-*-freebsd* | mips*el-*-kfreebsd*-gnu) # FreeBSD vectors - targ_defvec=bfd_elf32_tradlittlemips_freebsd_vec - targ_selvecs="bfd_elf32_tradbigmips_freebsd_vec bfd_elf32_ntradlittlemips_freebsd_vec bfd_elf64_tradlittlemips_freebsd_vec bfd_elf32_ntradbigmips_freebsd_vec bfd_elf64_tradbigmips_freebsd_vec" + targ_defvec=mips_elf32_tradfbsd_le_vec + targ_selvecs="mips_elf32_tradfbsd_be_vec mips_elf32_ntradfbsd_le_vec mips_elf64_tradfbsd_le_vec mips_elf32_ntradfbsd_be_vec mips_elf64_tradfbsd_be_vec" # Generic vectors - targ_selvecs="${targ_selvecs} bfd_elf32_tradlittlemips_vec bfd_elf32_tradbigmips_vec bfd_elf32_ntradlittlemips_vec bfd_elf64_tradlittlemips_vec bfd_elf32_ntradbigmips_vec bfd_elf64_tradbigmips_vec" - want64=true + targ_selvecs="${targ_selvecs} mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf32_ntrad_le_vec mips_elf64_trad_le_vec mips_elf32_ntrad_be_vec mips_elf64_trad_be_vec" ;; mips*-*-freebsd* | mips*-*-kfreebsd*-gnu) # FreeBSD vectors - targ_defvec=bfd_elf32_tradbigmips_freebsd_vec - targ_selvecs="bfd_elf32_tradlittlemips_freebsd_vec bfd_elf32_ntradbigmips_freebsd_vec bfd_elf64_tradbigmips_freebsd_vec bfd_elf32_ntradlittlemips_freebsd_vec bfd_elf64_tradlittlemips_freebsd_vec" + targ_defvec=mips_elf32_tradfbsd_be_vec + targ_selvecs="mips_elf32_tradfbsd_le_vec mips_elf32_ntradfbsd_be_vec mips_elf64_tradfbsd_be_vec mips_elf32_ntradfbsd_le_vec mips_elf64_tradfbsd_le_vec" # Generic vectors - targ_selvecs="${targ_selvecs} bfd_elf32_tradbigmips_vec bfd_elf32_tradlittlemips_vec bfd_elf32_ntradbigmips_vec bfd_elf64_tradbigmips_vec bfd_elf32_ntradlittlemips_vec bfd_elf64_tradlittlemips_vec" - want64=true + targ_selvecs="${targ_selvecs} mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf32_ntrad_be_vec mips_elf64_trad_be_vec mips_elf32_ntrad_le_vec mips_elf64_trad_le_vec" ;; -#ifdef BFD64 mmix-*-*) - targ_defvec=bfd_elf64_mmix_vec - targ_selvecs=bfd_mmo_vec + targ_defvec=mmix_elf64_vec + targ_selvecs=mmix_mmo_vec want64=true ;; #endif mn10200-*-*) - targ_defvec=bfd_elf32_mn10200_vec + targ_defvec=mn10200_elf32_vec ;; mn10300-*-*) - targ_defvec=bfd_elf32_mn10300_vec + targ_defvec=mn10300_elf32_vec targ_underscore=yes ;; mt-*-elf) - targ_defvec=bfd_elf32_mt_vec + targ_defvec=mt_elf32_vec ;; msp430-*-*) - targ_defvec=bfd_elf32_msp430_vec + targ_defvec=msp430_elf32_vec + targ_selvecs=msp430_elf32_ti_vec + ;; + + nds32*le-*-linux*) + targ_defvec=nds32_elf32_linux_le_vec + targ_selvecs=nds32_elf32_linux_be_vec + ;; + + nds32*be-*-linux*) + targ_defvec=nds32_elf32_linux_be_vec + targ_selvecs=nds32_elf32_linux_le_vec + ;; + + nds32*le-*-*) + targ_defvec=nds32_elf32_le_vec + targ_selvecs=nds32_elf32_be_vec + ;; + + nds32*be-*-*) + targ_defvec=nds32_elf32_be_vec + targ_selvecs=nds32_elf32_le_vec ;; ns32k-pc532-mach* | ns32k-pc532-ux*) - targ_defvec=pc532machaout_vec + targ_defvec=ns32k_aout_pc532mach_vec targ_underscore=yes ;; ns32k-*-netbsd* | ns32k-*-lites* | ns32k-*-openbsd*) - targ_defvec=pc532netbsd_vec + targ_defvec=ns32k_aout_pc532nbsd_vec targ_underscore=yes ;; nios2eb-*-*) - targ_defvec=bfd_elf32_bignios2_vec - targ_selvecs=bfd_elf32_littlenios2_vec + targ_defvec=nios2_elf32_be_vec + targ_selvecs=nios2_elf32_le_vec ;; nios2el-*-*) - targ_defvec=bfd_elf32_littlenios2_vec - targ_selvecs=bfd_elf32_bignios2_vec + targ_defvec=nios2_elf32_le_vec + targ_selvecs=nios2_elf32_be_vec ;; nios2-*-*) - targ_defvec=bfd_elf32_littlenios2_vec - targ_selvecs=bfd_elf32_bignios2_vec + targ_defvec=nios2_elf32_le_vec + targ_selvecs=nios2_elf32_be_vec ;; - openrisc-*-elf) - targ_defvec=bfd_elf32_openrisc_vec + or1k-*-elf | or1k-*-linux* | or1k-*-rtems*) + targ_defvec=or1k_elf32_vec ;; - or32-*-coff) - targ_defvec=or32coff_big_vec - targ_underscore=yes - ;; - - or32-*-elf) - targ_defvec=bfd_elf32_or32_big_vec + or1knd-*-elf | or1knd-*-linux* | or1knd-*-rtems*) + targ_defvec=or1k_elf32_vec ;; pdp11-*-*) @@ -1179,45 +1206,45 @@ case "${targ}" in ;; pj-*-*) - targ_defvec=bfd_elf32_pj_vec - targ_selvecs="bfd_elf32_pj_vec bfd_elf32_pjl_vec" + targ_defvec=pj_elf32_vec + targ_selvecs="pj_elf32_vec pj_elf32_le_vec" ;; pjl-*-*) - targ_defvec=bfd_elf32_pjl_vec - targ_selvecs="bfd_elf32_pjl_vec bfd_elf32_pj_vec bfd_elf32_i386_vec" + targ_defvec=pj_elf32_le_vec + targ_selvecs="pj_elf32_le_vec pj_elf32_vec i386_elf32_vec iamcu_elf32_vec" ;; powerpc-*-aix5.[01] | rs6000-*-aix5.[01]) - targ_defvec=rs6000coff_vec - targ_selvecs="aix5coff64_vec" + targ_defvec=rs6000_xcoff_vec + targ_selvecs="rs6000_xcoff64_aix_vec" want64=true ;; #ifdef BFD64 powerpc64-*-aix5.[01] | rs6000-*-aix5.[01]) - targ_defvec=aix5coff64_vec - targ_selvecs="rs6000coff_vec" + targ_defvec=rs6000_xcoff64_aix_vec + targ_selvecs="rs6000_xcoff_vec" want64=true ;; #endif powerpc-*-aix[5-9]* | rs6000-*-aix[5-9]*) targ_cflags=-DAIX_WEAK_SUPPORT - targ_defvec=rs6000coff_vec - targ_selvecs="aix5coff64_vec" + targ_defvec=rs6000_xcoff_vec + targ_selvecs="rs6000_xcoff64_aix_vec" want64=true ;; #ifdef BFD64 powerpc64-*-aix[5-9]* | rs6000-*-aix[5-9]*) targ_cflags=-DAIX_WEAK_SUPPORT - targ_defvec=aix5coff64_vec - targ_selvecs="rs6000coff_vec" + targ_defvec=rs6000_xcoff64_aix_vec + targ_selvecs="rs6000_xcoff_vec" want64=true ;; #endif powerpc-*-aix* | powerpc-*-beos* | rs6000-*-*) - targ_defvec=rs6000coff_vec - targ64_selvecs=rs6000coff64_vec + targ_defvec=rs6000_xcoff_vec + targ64_selvecs=rs6000_xcoff64_vec case "${targ}" in *-*-aix4.[3456789]* | *-*-aix[56789]*) want64=true;; @@ -1227,43 +1254,44 @@ case "${targ}" in ;; #ifdef BFD64 powerpc64-*-aix*) - targ_defvec=rs6000coff64_vec - targ_selvecs=rs6000coff_vec + targ_defvec=rs6000_xcoff64_vec + targ_selvecs=rs6000_xcoff_vec want64=true ;; powerpc64-*-freebsd*) - targ_defvec=bfd_elf64_powerpc_freebsd_vec - targ_selvecs="bfd_elf64_powerpc_vec bfd_elf32_powerpc_vec bfd_elf32_powerpc_freebsd_vec bfd_elf32_powerpcle_vec rs6000coff_vec rs6000coff64_vec aix5coff64_vec" + targ_defvec=powerpc_elf64_fbsd_vec + targ_selvecs="powerpc_elf64_vec powerpc_elf32_vec powerpc_elf32_fbsd_vec powerpc_elf32_le_vec rs6000_xcoff_vec rs6000_xcoff64_vec rs6000_xcoff64_aix_vec" want64=true ;; powerpc64-*-elf* | powerpc-*-elf64* | powerpc64-*-linux* | \ powerpc64-*-*bsd*) - targ_defvec=bfd_elf64_powerpc_vec - targ_selvecs="bfd_elf64_powerpcle_vec bfd_elf32_powerpc_vec bfd_elf32_powerpcle_vec rs6000coff_vec rs6000coff64_vec aix5coff64_vec" + targ_defvec=powerpc_elf64_vec + targ_selvecs="powerpc_elf64_le_vec powerpc_elf32_vec powerpc_elf32_le_vec rs6000_xcoff_vec rs6000_xcoff64_vec rs6000_xcoff64_aix_vec" want64=true ;; - powerpc64le-*-elf* | powerpcle-*-elf64*) - targ_defvec=bfd_elf64_powerpcle_vec - targ_selvecs="bfd_elf64_powerpc_vec bfd_elf32_powerpcle_vec bfd_elf32_powerpc_vec rs6000coff_vec rs6000coff64_vec aix5coff64_vec" + powerpc64le-*-elf* | powerpcle-*-elf64* | powerpc64le-*-linux* | \ + powerpc64le-*-*bsd*) + targ_defvec=powerpc_elf64_le_vec + targ_selvecs="powerpc_elf64_vec powerpc_elf32_le_vec powerpc_elf32_vec rs6000_xcoff_vec rs6000_xcoff64_vec rs6000_xcoff64_aix_vec" want64=true ;; #endif powerpc-*-*freebsd*) - targ_defvec=bfd_elf32_powerpc_freebsd_vec - targ_selvecs="rs6000coff_vec bfd_elf32_powerpc_vec bfd_elf32_powerpcle_vec ppcboot_vec" - targ64_selvecs="bfd_elf64_powerpc_vec bfd_elf64_powerpcle_vec bfd_elf64_powerpc_freebsd_vec" + targ_defvec=powerpc_elf32_fbsd_vec + targ_selvecs="rs6000_xcoff_vec powerpc_elf32_vec powerpc_elf32_le_vec powerpc_boot_vec" + targ64_selvecs="powerpc_elf64_vec powerpc_elf64_le_vec powerpc_elf64_fbsd_vec" ;; powerpc-*-*bsd* | powerpc-*-elf* | powerpc-*-sysv4* | powerpc-*-eabi* | \ powerpc-*-solaris2* | powerpc-*-linux-* | powerpc-*-rtems* | \ powerpc-*-chorus*) - targ_defvec=bfd_elf32_powerpc_vec - targ_selvecs="rs6000coff_vec bfd_elf32_powerpcle_vec ppcboot_vec" - targ64_selvecs="bfd_elf64_powerpc_vec bfd_elf64_powerpcle_vec" + targ_defvec=powerpc_elf32_vec + targ_selvecs="rs6000_xcoff_vec powerpc_elf32_le_vec powerpc_boot_vec" + targ64_selvecs="powerpc_elf64_vec powerpc_elf64_le_vec" ;; powerpc-*-kaos*) - targ_defvec=bfd_elf32_powerpc_vec - targ_selvecs="bfd_elf32_powerpcle_vec ppcboot_vec" - targ64_selvecs="bfd_elf64_powerpc_vec bfd_elf64_powerpcle_vec" + targ_defvec=powerpc_elf32_vec + targ_selvecs="powerpc_elf32_le_vec powerpc_boot_vec" + targ64_selvecs="powerpc_elf64_vec powerpc_elf64_le_vec" ;; powerpc-*-darwin* | powerpc-*-macos10* | powerpc-*-rhapsody*) targ_defvec=mach_o_be_vec @@ -1271,415 +1299,423 @@ case "${targ}" in targ_archs="$targ_archs bfd_i386_arch" ;; powerpc-*-macos*) - targ_defvec=pmac_xcoff_vec + targ_defvec=powerpc_xcoff_vec ;; powerpc-*-lynxos*) - targ_defvec=bfd_elf32_powerpc_vec - targ_selvecs="rs6000coff_vec" + targ_defvec=powerpc_elf32_vec + targ_selvecs="rs6000_xcoff_vec" targ_cflags=-DSMALL_ARCHIVE ;; powerpc-*-netware*) - targ_defvec=bfd_elf32_powerpc_vec - targ_selvecs="nlm32_powerpc_vec rs6000coff_vec" + targ_defvec=powerpc_elf32_vec + targ_selvecs="powerpc_nlm32_vec rs6000_xcoff_vec" ;; powerpc-*-nto*) - targ_defvec=bfd_elf32_powerpc_vec - targ_selvecs="rs6000coff_vec bfd_elf32_powerpcle_vec ppcboot_vec" + targ_defvec=powerpc_elf32_vec + targ_selvecs="rs6000_xcoff_vec powerpc_elf32_le_vec powerpc_boot_vec" ;; powerpc-*-vxworks* | powerpc-*-windiss*) - targ_defvec=bfd_elf32_powerpc_vxworks_vec - targ_selvecs="rs6000coff_vec bfd_elf32_powerpc_vec bfd_elf32_powerpcle_vec ppcboot_vec" - targ64_selvecs="bfd_elf64_powerpc_vec bfd_elf64_powerpcle_vec" + targ_defvec=powerpc_elf32_vxworks_vec + targ_selvecs="rs6000_xcoff_vec powerpc_elf32_vec powerpc_elf32_le_vec powerpc_boot_vec" + targ64_selvecs="powerpc_elf64_vec powerpc_elf64_le_vec" ;; powerpcle-*-nto*) - targ_defvec=bfd_elf32_powerpcle_vec - targ_selvecs="rs6000coff_vec bfd_elf32_powerpc_vec ppcboot_vec" + targ_defvec=powerpc_elf32_le_vec + targ_selvecs="rs6000_xcoff_vec powerpc_elf32_vec powerpc_boot_vec" ;; powerpcle-*-elf* | powerpcle-*-sysv4* | powerpcle-*-eabi* | \ powerpcle-*-solaris2* | powerpcle-*-linux-* | powerpcle-*-vxworks*) - targ_defvec=bfd_elf32_powerpcle_vec - targ_selvecs="rs6000coff_vec bfd_elf32_powerpc_vec ppcboot_vec" - targ64_selvecs="bfd_elf64_powerpc_vec bfd_elf64_powerpcle_vec" + targ_defvec=powerpc_elf32_le_vec + targ_selvecs="rs6000_xcoff_vec powerpc_elf32_vec powerpc_boot_vec" + targ64_selvecs="powerpc_elf64_vec powerpc_elf64_le_vec" ;; powerpcle-*-pe | powerpcle-*-winnt* | powerpcle-*-cygwin*) - targ_defvec=bfd_powerpcle_pe_vec - targ_selvecs="bfd_powerpcle_pei_vec bfd_powerpc_pei_vec bfd_powerpcle_pe_vec bfd_powerpc_pe_vec" + targ_defvec=powerpc_pe_le_vec + targ_selvecs="powerpc_pei_le_vec powerpc_pei_vec powerpc_pe_le_vec powerpc_pe_vec" ;; rl78-*-elf) - targ_defvec=bfd_elf32_rl78_vec + targ_defvec=rl78_elf32_vec ;; rx-*-elf) - targ_defvec=bfd_elf32_rx_le_vec - targ_selvecs="bfd_elf32_rx_be_vec bfd_elf32_rx_le_vec bfd_elf32_rx_be_ns_vec" + targ_defvec=rx_elf32_le_vec + targ_selvecs="rx_elf32_be_vec rx_elf32_le_vec rx_elf32_be_ns_vec" ;; s390-*-linux*) - targ_defvec=bfd_elf32_s390_vec - targ64_selvecs=bfd_elf64_s390_vec + targ_defvec=s390_elf32_vec + targ64_selvecs=s390_elf64_vec want64=true ;; #ifdef BFD64 s390x-*-linux*) - targ_defvec=bfd_elf64_s390_vec - targ_selvecs=bfd_elf32_s390_vec + targ_defvec=s390_elf64_vec + targ_selvecs=s390_elf32_vec want64=true ;; s390x-*-tpf*) - targ_defvec=bfd_elf64_s390_vec + targ_defvec=s390_elf64_vec want64=true ;; score*-*-elf*) - targ_defvec=bfd_elf32_bigscore_vec - targ_selvecs=bfd_elf32_littlescore_vec + targ_defvec=score_elf32_be_vec + targ_selvecs=score_elf32_le_vec ;; sh64l*-*-elf*) - targ_defvec=bfd_elf32_sh64l_vec - targ_selvecs="bfd_elf32_sh64_vec bfd_elf64_sh64l_vec bfd_elf64_sh64_vec bfd_elf32_shl_vec bfd_elf32_sh_vec" + targ_defvec=sh64_elf32_le_vec + targ_selvecs="sh64_elf32_vec sh64_elf64_le_vec sh64_elf64_vec sh_elf32_le_vec sh_elf32_vec" targ_underscore=yes want64=true ;; sh64-*-elf*) - targ_defvec=bfd_elf32_sh64_vec - targ_selvecs="bfd_elf32_sh64l_vec bfd_elf64_sh64_vec bfd_elf64_sh64l_vec bfd_elf32_sh_vec bfd_elf32_shl_vec" + targ_defvec=sh64_elf32_vec + targ_selvecs="sh64_elf32_le_vec sh64_elf64_vec sh64_elf64_le_vec sh_elf32_vec sh_elf32_le_vec" targ_underscore=yes want64=true ;; sh64eb-*-linux*) - targ_defvec=bfd_elf32_sh64blin_vec - targ_selvecs="bfd_elf32_sh64lin_vec bfd_elf64_sh64blin_vec bfd_elf64_sh64lin_vec bfd_elf32_shblin_vec bfd_elf32_shlin_vec" + targ_defvec=sh64_elf32_linux_be_vec + targ_selvecs="sh64_elf32_linux_vec sh64_elf64_linux_be_vec sh64_elf64_linux_vec sh_elf32_linux_be_vec sh_elf32_linux_vec" want64=true ;; sh64-*-linux*) - targ_defvec=bfd_elf32_sh64lin_vec - targ_selvecs="bfd_elf32_sh64blin_vec bfd_elf64_sh64lin_vec bfd_elf64_sh64blin_vec bfd_elf32_shlin_vec bfd_elf32_shblin_vec" + targ_defvec=sh64_elf32_linux_vec + targ_selvecs="sh64_elf32_linux_be_vec sh64_elf64_linux_vec sh64_elf64_linux_be_vec sh_elf32_linux_vec sh_elf32_linux_be_vec" want64=true ;; sh-*-linux*) - targ_defvec=bfd_elf32_shblin_vec - targ_selvecs="bfd_elf32_shlin_vec bfd_elf32_sh64lin_vec bfd_elf32_sh64blin_vec bfd_elf64_sh64lin_vec bfd_elf64_sh64blin_vec" + targ_defvec=sh_elf32_linux_be_vec + targ_selvecs="sh_elf32_linux_vec sh64_elf32_linux_vec sh64_elf32_linux_be_vec sh64_elf64_linux_vec sh64_elf64_linux_be_vec" want64=true ;; #endif /* BFD64 */ sh*eb-*-linux*) - targ_defvec=bfd_elf32_shblin_vec - targ_selvecs=bfd_elf32_shlin_vec + targ_defvec=sh_elf32_linux_be_vec + targ_selvecs=sh_elf32_linux_vec ;; sh*-*-linux*) - targ_defvec=bfd_elf32_shlin_vec - targ_selvecs=bfd_elf32_shblin_vec + targ_defvec=sh_elf32_linux_vec + targ_selvecs=sh_elf32_linux_be_vec ;; sh-*-uclinux* | sh[12]-*-uclinux*) - targ_defvec=bfd_elf32_sh_vec - targ_selvecs="bfd_elf32_shl_vec bfd_elf32_shblin_vec bfd_elf32_shlin_vec bfd_elf32_shfd_vec bfd_elf32_shbfd_vec" + targ_defvec=sh_elf32_vec + targ_selvecs="sh_elf32_le_vec sh_elf32_linux_be_vec sh_elf32_linux_vec sh_elf32_fdpic_le_vec sh_elf32_fdpic_be_vec" #ifdef BFD64 - targ_selvecs="${targ_selvecs} bfd_elf32_sh64lin_vec bfd_elf32_sh64blin_vec bfd_elf64_sh64lin_vec bfd_elf64_sh64blin_vec" + targ_selvecs="${targ_selvecs} sh64_elf32_linux_vec sh64_elf32_linux_be_vec sh64_elf64_linux_vec sh64_elf64_linux_be_vec" #endif ;; #ifdef BFD64 sh5le-*-netbsd*) - targ_defvec=bfd_elf32_sh64lnbsd_vec - targ_selvecs="bfd_elf32_sh64nbsd_vec bfd_elf64_sh64lnbsd_vec bfd_elf64_sh64nbsd_vec bfd_elf32_shnbsd_vec bfd_elf32_shlnbsd_vec" + targ_defvec=sh64_elf32_nbsd_le_vec + targ_selvecs="sh64_elf32_nbsd_vec sh64_elf64_nbsd_le_vec sh64_elf64_nbsd_vec sh_elf32_nbsd_vec sh_elf32_nbsd_le_vec" want64=true ;; sh5-*-netbsd*) - targ_defvec=bfd_elf32_sh64nbsd_vec - targ_selvecs="bfd_elf32_sh64lnbsd_vec bfd_elf64_sh64lnbsd_vec bfd_elf64_sh64nbsd_vec bfd_elf32_shnbsd_vec bfd_elf32_shlnbsd_vec" + targ_defvec=sh64_elf32_nbsd_vec + targ_selvecs="sh64_elf32_nbsd_le_vec sh64_elf64_nbsd_le_vec sh64_elf64_nbsd_vec sh_elf32_nbsd_vec sh_elf32_nbsd_le_vec" want64=true ;; sh64le-*-netbsd*) - targ_defvec=bfd_elf64_sh64lnbsd_vec - targ_selvecs="bfd_elf64_sh64nbsd_vec bfd_elf32_sh64lnbsd_vec bfd_elf32_sh64nbsd_vec bfd_elf32_shnbsd_vec bfd_elf32_shlnbsd_vec" + targ_defvec=sh64_elf64_nbsd_le_vec + targ_selvecs="sh64_elf64_nbsd_vec sh64_elf32_nbsd_le_vec sh64_elf32_nbsd_vec sh_elf32_nbsd_vec sh_elf32_nbsd_le_vec" want64=true ;; sh64-*-netbsd*) - targ_defvec=bfd_elf64_sh64nbsd_vec - targ_selvecs="bfd_elf64_sh64lnbsd_vec bfd_elf32_sh64lnbsd_vec bfd_elf32_sh64nbsd_vec bfd_elf32_shnbsd_vec bfd_elf32_shlnbsd_vec" + targ_defvec=sh64_elf64_nbsd_vec + targ_selvecs="sh64_elf64_nbsd_le_vec sh64_elf32_nbsd_le_vec sh64_elf32_nbsd_vec sh_elf32_nbsd_vec sh_elf32_nbsd_le_vec" want64=true ;; sh*l*-*-netbsdelf*) - targ_defvec=bfd_elf32_shlnbsd_vec - targ_selvecs="bfd_elf32_shnbsd_vec shcoff_vec shlcoff_vec bfd_elf32_sh64lnbsd_vec bfd_elf32_sh64nbsd_vec bfd_elf64_sh64lnbsd_vec bfd_elf64_sh64nbsd_vec" + targ_defvec=sh_elf32_nbsd_le_vec + targ_selvecs="sh_elf32_nbsd_vec sh_coff_vec sh_coff_le_vec sh64_elf32_nbsd_le_vec sh64_elf32_nbsd_vec sh64_elf64_nbsd_le_vec sh64_elf64_nbsd_vec" want64=true ;; sh-*-netbsdelf*) - targ_defvec=bfd_elf32_shnbsd_vec - targ_selvecs="bfd_elf32_shlnbsd_vec shcoff_vec shlcoff_vec bfd_elf32_sh64lnbsd_vec bfd_elf32_sh64nbsd_vec bfd_elf64_sh64lnbsd_vec bfd_elf64_sh64nbsd_vec" + targ_defvec=sh_elf32_nbsd_vec + targ_selvecs="sh_elf32_nbsd_le_vec sh_coff_vec sh_coff_le_vec sh64_elf32_nbsd_le_vec sh64_elf32_nbsd_vec sh64_elf64_nbsd_le_vec sh64_elf64_nbsd_vec" want64=true ;; #endif sh*-*-netbsdelf*) - targ_defvec=bfd_elf32_shnbsd_vec - targ_selvecs="bfd_elf32_shlnbsd_vec shcoff_vec shlcoff_vec" + targ_defvec=sh_elf32_nbsd_vec + targ_selvecs="sh_elf32_nbsd_le_vec sh_coff_vec sh_coff_le_vec" ;; sh*-*-symbianelf*) - targ_defvec=bfd_elf32_shl_symbian_vec - targ_selvecs="shlcoff_vec shlcoff_small_vec" + targ_defvec=sh_elf32_symbian_le_vec + targ_selvecs="sh_coff_le_vec sh_coff_small_le_vec" targ_underscore=yes ;; #ifdef BFD64 shl*-*-elf* | sh[1234]l*-*-elf* | sh3el*-*-elf* | shl*-*-kaos*) - targ_defvec=bfd_elf32_shl_vec - targ_selvecs="bfd_elf32_sh_vec shlcoff_vec shcoff_vec shlcoff_small_vec shcoff_small_vec bfd_elf32_sh64_vec bfd_elf32_sh64l_vec bfd_elf64_sh64_vec bfd_elf64_sh64l_vec" + targ_defvec=sh_elf32_le_vec + targ_selvecs="sh_elf32_vec sh_coff_le_vec sh_coff_vec sh_coff_small_le_vec sh_coff_small_vec sh64_elf32_vec sh64_elf32_le_vec sh64_elf64_vec sh64_elf64_le_vec" targ_underscore=yes want64=true ;; #endif sh-*-rtemscoff*) - targ_defvec=shcoff_vec - targ_selvecs="shcoff_vec shlcoff_vec shcoff_small_vec shlcoff_small_vec" + targ_defvec=sh_coff_vec + targ_selvecs="sh_coff_vec sh_coff_le_vec sh_coff_small_vec sh_coff_small_le_vec" targ_underscore=yes ;; #ifdef BFD64 sh-*-elf* | sh[1234]*-elf* | sh-*-rtems* | sh-*-kaos*) - targ_defvec=bfd_elf32_sh_vec - targ_selvecs="bfd_elf32_shl_vec shcoff_vec shlcoff_vec shcoff_small_vec shlcoff_small_vec bfd_elf32_sh64_vec bfd_elf32_sh64l_vec bfd_elf64_sh64_vec bfd_elf64_sh64l_vec" + targ_defvec=sh_elf32_vec + targ_selvecs="sh_elf32_le_vec sh_coff_vec sh_coff_le_vec sh_coff_small_vec sh_coff_small_le_vec sh64_elf32_vec sh64_elf32_le_vec sh64_elf64_vec sh64_elf64_le_vec" targ_underscore=yes want64=true ;; #endif sh-*-nto*) - targ_defvec=bfd_elf32_sh_vec - targ_selvecs="bfd_elf32_shl_vec shcoff_vec shlcoff_vec shcoff_small_vec shlcoff_small_vec" + targ_defvec=sh_elf32_vec + targ_selvecs="sh_elf32_le_vec sh_coff_vec sh_coff_le_vec sh_coff_small_vec sh_coff_small_le_vec" targ_underscore=yes ;; sh*-*-openbsd*) - targ_defvec=bfd_elf32_shlnbsd_vec - targ_selvecs="bfd_elf32_shnbsd_vec shcoff_vec shlcoff_vec" + targ_defvec=sh_elf32_nbsd_le_vec + targ_selvecs="sh_elf32_nbsd_vec sh_coff_vec sh_coff_le_vec" ;; sh-*-pe) - targ_defvec=shlpe_vec - targ_selvecs="shlpe_vec shlpei_vec" + targ_defvec=sh_pe_le_vec + targ_selvecs="sh_pe_le_vec sh_pei_le_vec" targ_underscore=yes ;; sh-*-vxworks) - targ_defvec=bfd_elf32_shvxworks_vec - targ_selvecs="bfd_elf32_shlvxworks_vec" + targ_defvec=sh_elf32_vxworks_vec + targ_selvecs="sh_elf32_vxworks_le_vec" # FIXME None of the following are actually used on this target, but # they're necessary for coff-sh.c (which is unconditionally used) to be # compiled correctly. - targ_selvecs="$targ_selvecs shcoff_vec shlcoff_vec shcoff_small_vec shlcoff_small_vec" + targ_selvecs="$targ_selvecs sh_coff_vec sh_coff_le_vec sh_coff_small_vec sh_coff_small_le_vec" targ_underscore=yes ;; sh-*-*) - targ_defvec=shcoff_vec - targ_selvecs="shcoff_vec shlcoff_vec shcoff_small_vec shlcoff_small_vec" + targ_defvec=sh_coff_vec + targ_selvecs="sh_coff_vec sh_coff_le_vec sh_coff_small_vec sh_coff_small_le_vec" targ_underscore=yes ;; sparclet-*-aout*) - targ_defvec=sunos_big_vec - targ_selvecs=sparcle_aout_vec + targ_defvec=sparc_aout_sunos_be_vec + targ_selvecs=sparc_aout_le_vec targ_underscore=yes ;; sparc86x-*-aout*) - targ_defvec=sunos_big_vec + targ_defvec=sparc_aout_sunos_be_vec targ_underscore=yes ;; sparclite-*-elf* | sparc86x-*-elf*) - targ_defvec=bfd_elf32_sparc_vec + targ_defvec=sparc_elf32_vec ;; sparc*-*-chorus*) - targ_defvec=bfd_elf32_sparc_vec + targ_defvec=sparc_elf32_vec ;; sparc-*-linux*aout*) - targ_defvec=sparclinux_vec - targ_selvecs="bfd_elf32_sparc_vec sunos_big_vec" + targ_defvec=sparc_aout_linux_vec + targ_selvecs="sparc_elf32_vec sparc_aout_sunos_be_vec" targ_underscore=yes ;; sparc-*-linux-* | sparcv*-*-linux-*) - targ_defvec=bfd_elf32_sparc_vec - targ_selvecs="sparclinux_vec bfd_elf64_sparc_vec sunos_big_vec" + targ_defvec=sparc_elf32_vec + targ_selvecs="sparc_aout_linux_vec sparc_elf64_vec sparc_aout_sunos_be_vec" ;; sparc-*-netbsdelf*) - targ_defvec=bfd_elf32_sparc_vec - targ_selvecs=sparcnetbsd_vec + targ_defvec=sparc_elf32_vec + targ_selvecs=sparc_aout_nbsd_vec ;; sparc-*-netbsdaout* | sparc-*-netbsd*) - targ_defvec=sparcnetbsd_vec - targ_selvecs=bfd_elf32_sparc_vec + targ_defvec=sparc_aout_nbsd_vec + targ_selvecs=sparc_elf32_vec targ_underscore=yes ;; sparc-*-openbsd[0-2].* | sparc-*-openbsd3.[0-1]) - targ_defvec=sparcnetbsd_vec + targ_defvec=sparc_aout_nbsd_vec targ_underscore=yes ;; sparc-*-openbsd*) - targ_defvec=bfd_elf32_sparc_vec - targ_selvecs=sparcnetbsd_vec + targ_defvec=sparc_elf32_vec + targ_selvecs=sparc_aout_nbsd_vec ;; sparc-*-elf*) - targ_defvec=bfd_elf32_sparc_vec - targ_selvecs=sunos_big_vec + targ_defvec=sparc_elf32_vec + targ_selvecs=sparc_aout_sunos_be_vec ;; sparc-*-solaris2.[0-6] | sparc-*-solaris2.[0-6].*) - targ_defvec=bfd_elf32_sparc_sol2_vec - targ_selvecs=sunos_big_vec + targ_defvec=sparc_elf32_sol2_vec + targ_selvecs=sparc_aout_sunos_be_vec ;; #ifdef BFD64 sparc-*-solaris2* | sparcv9-*-solaris2* | sparc64-*-solaris2*) - targ_defvec=bfd_elf32_sparc_sol2_vec - targ_selvecs="bfd_elf64_sparc_sol2_vec sunos_big_vec" + targ_defvec=sparc_elf32_sol2_vec + targ_selvecs="sparc_elf64_sol2_vec sparc_aout_sunos_be_vec" want64=true ;; #endif sparc-*-sysv4*) - targ_defvec=bfd_elf32_sparc_vec + targ_defvec=sparc_elf32_vec ;; sparc-*-vxworks*) - targ_defvec=bfd_elf32_sparc_vxworks_vec - targ_selvecs="bfd_elf32_sparc_vec sunos_big_vec" + targ_defvec=sparc_elf32_vxworks_vec + targ_selvecs="sparc_elf32_vec sparc_aout_sunos_be_vec" ;; sparc-*-netware*) - targ_defvec=bfd_elf32_sparc_vec - targ_selvecs="nlm32_sparc_vec sunos_big_vec" + targ_defvec=sparc_elf32_vec + targ_selvecs="sparc_nlm32_vec sparc_aout_sunos_be_vec" ;; #ifdef BFD64 sparc64-*-aout*) - targ_defvec=sunos_big_vec + targ_defvec=sparc_aout_sunos_be_vec targ_underscore=yes want64=true ;; sparc64*-*-linux-*) - targ_defvec=bfd_elf64_sparc_vec - targ_selvecs="bfd_elf32_sparc_vec sparclinux_vec sunos_big_vec" + targ_defvec=sparc_elf64_vec + targ_selvecs="sparc_elf32_vec sparc_aout_linux_vec sparc_aout_sunos_be_vec" want64=true ;; sparc64-*-elf* | sparc64-*-rtems* ) - targ_defvec=bfd_elf64_sparc_vec - targ_selvecs=bfd_elf32_sparc_vec + targ_defvec=sparc_elf64_vec + targ_selvecs=sparc_elf32_vec want64=true ;; #endif /* BFD64 */ sparc*-*-coff*) - targ_defvec=sparccoff_vec + targ_defvec=sparc_coff_vec ;; sparc-*-rtems*) - targ_defvec=bfd_elf32_sparc_vec - targ_selvecs="sunos_big_vec sparccoff_vec" + targ_defvec=sparc_elf32_vec + targ_selvecs="sparc_aout_sunos_be_vec sparc_coff_vec" ;; sparc*-*-*) - targ_defvec=sunos_big_vec + targ_defvec=sparc_aout_sunos_be_vec targ_underscore=yes ;; spu-*-elf) - targ_defvec=bfd_elf32_spu_vec + targ_defvec=spu_elf32_vec want64=true ;; -#if HAVE_host_aout_vec +#if HAVE_aout_vec tahoe-*-*) - targ_defvec=host_aout_vec + targ_defvec=aout_vec targ_underscore=yes ;; #endif tic6x-*-elf) - targ_defvec=bfd_elf32_tic6x_elf_le_vec - targ_selvecs="bfd_elf32_tic6x_elf_be_vec bfd_elf32_tic6x_le_vec bfd_elf32_tic6x_be_vec" + targ_defvec=tic6x_elf32_c6000_le_vec + targ_selvecs="tic6x_elf32_c6000_be_vec tic6x_elf32_le_vec tic6x_elf32_be_vec" ;; tic6x-*-uclinux) - targ_defvec=bfd_elf32_tic6x_linux_le_vec - targ_selvecs="bfd_elf32_tic6x_linux_be_vec bfd_elf32_tic6x_le_vec bfd_elf32_tic6x_be_vec" + targ_defvec=tic6x_elf32_linux_le_vec + targ_selvecs="tic6x_elf32_linux_be_vec tic6x_elf32_le_vec tic6x_elf32_be_vec" ;; tic80*-*-*) - targ_defvec=tic80coff_vec + targ_defvec=tic80_coff_vec targ_underscore=yes ;; #ifdef BFD64 tilegx-*-*) - targ_defvec=bfd_elf64_tilegx_le_vec - targ_selvecs="bfd_elf64_tilegx_be_vec bfd_elf32_tilegx_be_vec bfd_elf32_tilegx_le_vec" + targ_defvec=tilegx_elf64_le_vec + targ_selvecs="tilegx_elf64_be_vec tilegx_elf32_be_vec tilegx_elf32_le_vec" ;; tilegxbe-*-*) - targ_defvec=bfd_elf64_tilegx_be_vec - targ_selvecs="bfd_elf64_tilegx_le_vec bfd_elf32_tilegx_be_vec bfd_elf32_tilegx_le_vec" + targ_defvec=tilegx_elf64_be_vec + targ_selvecs="tilegx_elf64_le_vec tilegx_elf32_be_vec tilegx_elf32_le_vec" ;; #endif tilepro-*-*) - targ_defvec=bfd_elf32_tilepro_vec + targ_defvec=tilepro_elf32_vec + ;; + + ft32*-*-*) + targ_defvec=ft32_elf32_vec ;; v850*-*-*) - targ_defvec=bfd_elf32_v850_vec - targ_selvecs="bfd_elf32_v850_rh850_vec" + targ_defvec=v850_elf32_vec + targ_selvecs="v800_elf32_vec" ;; vax-*-netbsdelf*) - targ_defvec=bfd_elf32_vax_vec - targ_selvecs="vaxnetbsd_vec vax1knetbsd_vec" + targ_defvec=vax_elf32_vec + targ_selvecs="vax_aout_nbsd_vec vax_aout_1knbsd_vec" ;; vax-*-netbsdaout* | vax-*-netbsd*) - targ_defvec=vaxnetbsd_vec - targ_selvecs="bfd_elf32_vax_vec vax1knetbsd_vec" + targ_defvec=vax_aout_nbsd_vec + targ_selvecs="vax_elf32_vec vax_aout_1knbsd_vec" targ_underscore=yes ;; vax-*-bsd* | vax-*-ultrix*) - targ_defvec=vaxbsd_vec + targ_defvec=vax_aout_bsd_vec targ_underscore=yes ;; vax-*-openbsd*) - targ_defvec=vaxnetbsd_vec + targ_defvec=vax_aout_nbsd_vec targ_underscore=yes ;; vax-*-linux-*) - targ_defvec=bfd_elf32_vax_vec + targ_defvec=vax_elf32_vec ;; + visium-*-elf) + targ_defvec=visium_elf32_vec + ;; + we32k-*-*) - targ_defvec=we32kcoff_vec + targ_defvec=we32k_coff_vec ;; w65-*-*) - targ_defvec=w65_vec + targ_defvec=w65_coff_vec ;; xgate-*-*) - targ_defvec=bfd_elf32_xgate_vec - targ_selvecs="bfd_elf32_xgate_vec" + targ_defvec=xgate_elf32_vec + targ_selvecs="xgate_elf32_vec" ;; xstormy16-*-elf) - targ_defvec=bfd_elf32_xstormy16_vec + targ_defvec=xstormy16_elf32_vec ;; xtensa*-*-*) - targ_defvec=bfd_elf32_xtensa_le_vec - targ_selvecs=bfd_elf32_xtensa_be_vec + targ_defvec=xtensa_elf32_le_vec + targ_selvecs=xtensa_elf32_be_vec ;; xc16x-*-elf) - targ_defvec=bfd_elf32_xc16x_vec + targ_defvec=xc16x_elf32_vec ;; z80-*-*) - targ_defvec=z80coff_vec + targ_defvec=z80_coff_vec targ_underscore=no ;; z8k*-*-*) - targ_defvec=z8kcoff_vec + targ_defvec=z8k_coff_vec targ_underscore=yes ;; @@ -1688,17 +1724,17 @@ case "${targ}" in ;; *-adobe-*) - targ_defvec=a_out_adobe_vec + targ_defvec=aout_adobe_vec targ_underscore=yes ;; *-sony-*) - targ_defvec=newsos3_vec + targ_defvec=m68k_aout_newsos3_vec targ_underscore=yes ;; *-tandem-*) - targ_defvec=m68kcoff_vec + targ_defvec=m68k_coff_vec targ_selvecs=ieee_vec ;; # END OF targmatch.h @@ -1709,6 +1745,13 @@ case "${targ}" in ;; esac +# All MIPS ELF targets need a 64-bit bfd_vma. +case "${targ_defvec} ${targ_selvecs}" in + *mips_elf*) + want64=true + ;; +esac + case "${host64}${want64}" in *true*) targ_selvecs="${targ_selvecs} ${targ64_selvecs}" @@ -1720,24 +1763,31 @@ esac # to be used on an arbitrary ELF file for anything other than # relocation information. case "${targ_defvec} ${targ_selvecs}" in - *bfd_elf64* | *bfd_elf32_n*mips*) - targ_selvecs="${targ_selvecs} bfd_elf64_little_generic_vec bfd_elf64_big_generic_vec bfd_elf32_little_generic_vec bfd_elf32_big_generic_vec" + *elf64* | *mips_elf32_n*) + targ_selvecs="${targ_selvecs} elf64_le_vec elf64_be_vec elf32_le_vec elf32_be_vec" + ;; + *elf32*) + targ_selvecs="${targ_selvecs} elf32_le_vec elf32_be_vec" ;; - *bfd_elf32*) - targ_selvecs="${targ_selvecs} bfd_elf32_little_generic_vec bfd_elf32_big_generic_vec" +esac + +# If we support Intel MCU target, then add support for bfd_iamcu_arch. +case "${targ_defvec} ${targ_selvecs}" in + *iamcu_elf32*) + targ_archs="$targ_archs bfd_iamcu_arch" ;; esac # If we support Intel L1OM target, then add support for bfd_l1om_arch. case "${targ_defvec} ${targ_selvecs}" in - *bfd_elf64_l1om_vec*) + *l1om_elf64*) targ_archs="$targ_archs bfd_l1om_arch" ;; esac # If we support Intel K1OM target, then add support for bfd_k1om_arch. case "${targ_defvec} ${targ_selvecs}" in - *bfd_elf64_k1om_vec*) + *k1om_elf64*) targ_archs="$targ_archs bfd_k1om_arch" ;; esac diff --git a/contrib/gdb-7/bfd/corefile.c b/contrib/gdb-7/bfd/corefile.c index 8d6293849f..53f6b46f7d 100644 --- a/contrib/gdb-7/bfd/corefile.c +++ b/contrib/gdb-7/bfd/corefile.c @@ -1,6 +1,5 @@ /* Core file generic interface routines for BFD. - Copyright 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2002, 2003, 2005, - 2007 Free Software Foundation, Inc. + Copyright (C) 1990-2015 Free Software Foundation, Inc. Written by Cygnus Support. This file is part of BFD, the Binary File Descriptor library. diff --git a/contrib/gdb-7/bfd/cpu-ft32.c b/contrib/gdb-7/bfd/cpu-ft32.c new file mode 100644 index 0000000000..950a989cbe --- /dev/null +++ b/contrib/gdb-7/bfd/cpu-ft32.c @@ -0,0 +1,41 @@ +/* BFD support for the ft32 processor. + Copyright (C) 2013-2015 Free Software Foundation, Inc. + Written by FTDI (support@ftdichip.com) + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 "sysdep.h" +#include "bfd.h" +#include "libbfd.h" + + +const bfd_arch_info_type bfd_ft32_arch = + { + 32, /* 32 bits in a word. */ + 32, /* 32 bits in an address. */ + 8, /* 8 bits in a byte. */ + bfd_arch_ft32, /* enum bfd_architecture arch. */ + bfd_mach_ft32, + "ft32", /* Arch name. */ + "ft32", /* Printable name. */ + 2, /* Unsigned int section alignment power. */ + TRUE, /* The one and only. */ + bfd_default_compatible, + bfd_default_scan, + bfd_arch_default_fill, + 0, + }; diff --git a/contrib/gdb-7/bfd/cpu-i386.c b/contrib/gdb-7/bfd/cpu-i386.c index 6174612ebb..b727ac8190 100644 --- a/contrib/gdb-7/bfd/cpu-i386.c +++ b/contrib/gdb-7/bfd/cpu-i386.c @@ -1,7 +1,5 @@ /* BFD support for the Intel 386 architecture. - Copyright 1992, 1994, 1995, 1996, 1998, 2000, 2001, 2002, 2004, 2005, - 2007, 2009, 2010, 2011 - Free Software Foundation, Inc. + Copyright (C) 1992-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -119,6 +117,71 @@ bfd_arch_i386_long_nop_fill (bfd_size_type count, return bfd_arch_i386_fill (count, code, TRUE); } +/* Fill the buffer with zero, or one-byte nop instructions if CODE is TRUE. */ + +static void * +bfd_arch_i386_onebyte_nop_fill (bfd_size_type count, + bfd_boolean is_bigendian ATTRIBUTE_UNUSED, + bfd_boolean code) +{ + void *fill = bfd_malloc (count); + if (fill != NULL) + memset (fill, code ? 0x90 : 0, count); + return fill; +} + + +static const bfd_arch_info_type bfd_x64_32_nacl_arch = +{ + 64, /* 64 bits in a word */ + 64, /* 64 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_i386, + bfd_mach_x64_32_nacl, + "i386", + "i386:x64-32:nacl", + 3, + FALSE, + bfd_i386_compatible, + bfd_default_scan, + bfd_arch_i386_onebyte_nop_fill, + NULL +}; + +static const bfd_arch_info_type bfd_x86_64_nacl_arch = +{ + 64, /* 64 bits in a word */ + 64, /* 64 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_i386, + bfd_mach_x86_64_nacl, + "i386", + "i386:x86-64:nacl", + 3, + FALSE, + bfd_i386_compatible, + bfd_default_scan, + bfd_arch_i386_onebyte_nop_fill, + &bfd_x64_32_nacl_arch +}; + +const bfd_arch_info_type bfd_i386_nacl_arch = +{ + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_i386, + bfd_mach_i386_i386_nacl, + "i386", + "i386:nacl", + 3, + TRUE, + bfd_i386_compatible, + bfd_default_scan, + bfd_arch_i386_onebyte_nop_fill, + &bfd_x86_64_nacl_arch +}; + static const bfd_arch_info_type bfd_x64_32_arch_intel_syntax = { 64, /* 64 bits in a word */ @@ -133,7 +196,7 @@ static const bfd_arch_info_type bfd_x64_32_arch_intel_syntax = bfd_i386_compatible, bfd_default_scan, bfd_arch_i386_long_nop_fill, - 0 + &bfd_i386_nacl_arch }; static const bfd_arch_info_type bfd_x86_64_arch_intel_syntax = diff --git a/contrib/gdb-7/bfd/cpu-l1om.c b/contrib/gdb-7/bfd/cpu-iamcu.c similarity index 69% copy from contrib/gdb-7/bfd/cpu-l1om.c copy to contrib/gdb-7/bfd/cpu-iamcu.c index 46ac3a00c8..33d3dccd14 100644 --- a/contrib/gdb-7/bfd/cpu-l1om.c +++ b/contrib/gdb-7/bfd/cpu-iamcu.c @@ -1,6 +1,5 @@ -/* BFD support for the Intel L1OM architecture. - Copyright 2009 - Free Software Foundation, Inc. +/* BFD support for the Intel MCU architecture. + Copyright (C) 2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -26,15 +25,15 @@ extern void * bfd_arch_i386_short_nop_fill (bfd_size_type, bfd_boolean, bfd_boolean); -static const bfd_arch_info_type bfd_l1om_arch_intel_syntax = +static const bfd_arch_info_type bfd_iamcu_arch_intel_syntax = { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ 8, /* 8 bits in a byte */ - bfd_arch_l1om, - bfd_mach_l1om_intel_syntax, - "l1om:intel", - "l1om:intel", + bfd_arch_iamcu, + bfd_mach_i386_iamcu_intel_syntax, + "iamcu:intel", + "iamcu:intel", 3, TRUE, bfd_default_compatible, @@ -43,19 +42,19 @@ static const bfd_arch_info_type bfd_l1om_arch_intel_syntax = 0 }; -const bfd_arch_info_type bfd_l1om_arch = +const bfd_arch_info_type bfd_iamcu_arch = { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ 8, /* 8 bits in a byte */ - bfd_arch_l1om, - bfd_mach_l1om, - "l1om", - "l1om", + bfd_arch_iamcu, + bfd_mach_i386_iamcu, + "iamcu", + "iamcu", 3, TRUE, bfd_default_compatible, bfd_default_scan, bfd_arch_i386_short_nop_fill, - &bfd_l1om_arch_intel_syntax + &bfd_iamcu_arch_intel_syntax }; diff --git a/contrib/gdb-7/bfd/cpu-l1om.c b/contrib/gdb-7/bfd/cpu-l1om.c index 46ac3a00c8..a5fff914cb 100644 --- a/contrib/gdb-7/bfd/cpu-l1om.c +++ b/contrib/gdb-7/bfd/cpu-l1om.c @@ -1,6 +1,5 @@ /* BFD support for the Intel L1OM architecture. - Copyright 2009 - Free Software Foundation, Inc. + Copyright (C) 2009-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. diff --git a/contrib/gdb-7/bfd/cpu-nds32.c b/contrib/gdb-7/bfd/cpu-nds32.c new file mode 100644 index 0000000000..6c35ee46bb --- /dev/null +++ b/contrib/gdb-7/bfd/cpu-nds32.c @@ -0,0 +1,45 @@ +/* BFD support for the NDS32 processor + Copyright (C) 2012-2015 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include "elf-bfd.h" + +#define N(number, print, default, next) \ + {32, 32, 8, bfd_arch_nds32, number, "nds32", print, 4, default, \ + bfd_default_compatible, bfd_default_scan, bfd_arch_default_fill, next } + +#define NEXT &arch_info_struct[0] +#define NDS32V2_NEXT &arch_info_struct[1] +#define NDS32V3_NEXT &arch_info_struct[2] +#define NDS32V3M_NEXT &arch_info_struct[3] + +static const bfd_arch_info_type arch_info_struct[] = +{ + N (bfd_mach_n1h, "n1h", FALSE, NDS32V2_NEXT), + N (bfd_mach_n1h_v2, "n1h_v2", FALSE, NDS32V3_NEXT), + N (bfd_mach_n1h_v3, "n1h_v3", FALSE, NDS32V3M_NEXT), + N (bfd_mach_n1h_v3m, "n1h_v3m", FALSE, NULL), +}; + +const bfd_arch_info_type bfd_nds32_arch = + N (bfd_mach_n1, "n1h", TRUE, NEXT); diff --git a/contrib/gdb-7/bfd/cpu-or1k.c b/contrib/gdb-7/bfd/cpu-or1k.c new file mode 100644 index 0000000000..b95b1d801c --- /dev/null +++ b/contrib/gdb-7/bfd/cpu-or1k.c @@ -0,0 +1,59 @@ +/* BFD support for the OpenRISC 1000 architecture. + Copyright (C) 2002-2015 Free Software Foundation, Inc. + Contributed for OR32 by Ivan Guzvinec + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" + +const bfd_arch_info_type bfd_or1k_arch; +const bfd_arch_info_type bfd_or1knd_arch; + +const bfd_arch_info_type bfd_or1k_arch = + { + 32, /* 32 bits in a word. */ + 32, /* 32 bits in an address. */ + 8, /* 8 bits in a byte. */ + bfd_arch_or1k, + bfd_mach_or1k, + "or1k", + "or1k", + 4, + TRUE, + bfd_default_compatible, + bfd_default_scan, + bfd_arch_default_fill, + &bfd_or1knd_arch, + }; + +const bfd_arch_info_type bfd_or1knd_arch = + { + 32, /* 32 bits in a word. */ + 32, /* 32 bits in an address. */ + 8, /* 8 bits in a byte. */ + bfd_arch_or1k, + bfd_mach_or1knd, + "or1knd", + "or1knd", + 4, + FALSE, + bfd_default_compatible, + bfd_default_scan, + bfd_arch_default_fill, + NULL, + }; diff --git a/contrib/gdb-7/bfd/init.c b/contrib/gdb-7/bfd/cpu-visium.c similarity index 51% copy from contrib/gdb-7/bfd/init.c copy to contrib/gdb-7/bfd/cpu-visium.c index a023fb6878..a21bb11059 100644 --- a/contrib/gdb-7/bfd/init.c +++ b/contrib/gdb-7/bfd/cpu-visium.c @@ -1,7 +1,6 @@ -/* bfd initialization stuff - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 2003, 2005, 2007 - Free Software Foundation, Inc. - Written by Steve Chamberlain of Cygnus Support. +/* BFD support for the Visium processor. + + Copyright (C) 2003-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -17,39 +16,26 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ + Foundation, Inc., 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ #include "sysdep.h" #include "bfd.h" #include "libbfd.h" -/* -SECTION - Initialization - -SUBSECTION - Initialization functions - - These are the functions that handle initializing a BFD. -*/ - -/* -FUNCTION - bfd_init - -SYNOPSIS - void bfd_init (void); - -DESCRIPTION - This routine must be called before any other BFD function to - initialize magical internal data structures. -*/ - -/* Actually, there is currently nothing for this function to do. - However, someday it may be needed, so keep it around. */ - -void -bfd_init (void) +const bfd_arch_info_type bfd_visium_arch = { -} + 32, /* bits per word */ + 32, /* bits per address */ + 8, /* bits per byte */ + bfd_arch_visium, /* architecture */ + bfd_mach_visium, /* machine */ + "visium", /* architecture name */ + "visium", /* printable name */ + 2, /* section align power */ + TRUE, /* the default ? */ + bfd_default_compatible, /* architecture comparison fn */ + bfd_default_scan, /* string to architecture convert fn */ + bfd_arch_default_fill, /* default fill */ + NULL /* next in list */ +}; diff --git a/contrib/gdb-7/gdb/python/lib/gdb/command/__init__.py b/contrib/gdb-7/bfd/development.sh similarity index 78% copy from contrib/gdb-7/gdb/python/lib/gdb/command/__init__.py copy to contrib/gdb-7/bfd/development.sh index 21eaef8d9c..0e65c07882 100644 --- a/contrib/gdb-7/gdb/python/lib/gdb/command/__init__.py +++ b/contrib/gdb-7/bfd/development.sh @@ -1,5 +1,7 @@ -# Copyright (C) 2010-2013 Free Software Foundation, Inc. - +# Copyright (C) 2012-2015 Free Software Foundation, Inc. +# +# This file is part of GDB. +# # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or @@ -13,4 +15,5 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . - +# Controls whether to enable development-mode features by default. +development=false diff --git a/contrib/gdb-7/bfd/dwarf1.c b/contrib/gdb-7/bfd/dwarf1.c index 375f4cf166..9fef833f5b 100644 --- a/contrib/gdb-7/bfd/dwarf1.c +++ b/contrib/gdb-7/bfd/dwarf1.c @@ -1,6 +1,5 @@ /* DWARF 1 find nearest line (_bfd_dwarf1_find_nearest_line). - Copyright 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 1998-2015 Free Software Foundation, Inc. Written by Gavin Romig-Koch of Cygnus Solutions (gavin@cygnus.com). @@ -450,8 +449,8 @@ dwarf1_unit_find_nearest_line (struct dwarf1_debug* stash, bfd_boolean _bfd_dwarf1_find_nearest_line (bfd *abfd, - asection *section, asymbol **symbols, + asection *section, bfd_vma offset, const char **filename_ptr, const char **functionname_ptr, diff --git a/contrib/gdb-7/bfd/dwarf2.c b/contrib/gdb-7/bfd/dwarf2.c index 7a1a4aea0d..cbd4cf6486 100644 --- a/contrib/gdb-7/bfd/dwarf2.c +++ b/contrib/gdb-7/bfd/dwarf2.c @@ -1,6 +1,5 @@ /* DWARF 2 support. - Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 1994-2015 Free Software Foundation, Inc. Adapted from gdb/dwarf2read.c by Gavin Koch of Cygnus Solutions (gavin@cygnus.com). @@ -108,6 +107,16 @@ struct dwarf2_debug asection *sec; bfd_byte *sec_info_ptr; + /* Support for alternate debug info sections created by the DWZ utility: + This includes a pointer to an alternate bfd which contains *extra*, + possibly duplicate debug sections, and pointers to the loaded + .debug_str and .debug_info sections from this bfd. */ + bfd * alt_bfd_ptr; + bfd_byte * alt_dwarf_str_buffer; + bfd_size_type alt_dwarf_str_size; + bfd_byte * alt_dwarf_info_buffer; + bfd_size_type alt_dwarf_info_size; + /* A pointer to the memory block allocated for info_ptr. Neither info_ptr nor sec_info_ptr are guaranteed to stay pointing to the beginning of the malloc block. This is used only to free the @@ -147,8 +156,11 @@ struct dwarf2_debug use. */ struct funcinfo *inliner_chain; + /* Section VMAs at the time the stash was built. */ + bfd_vma *sec_vma; + /* Number of sections whose VMA we must adjust. */ - unsigned int adjusted_section_count; + int adjusted_section_count; /* Array of sections with adjusted VMA. */ struct adjusted_section *adjusted_sections; @@ -210,6 +222,9 @@ struct comp_unit /* The abbrev hash table. */ struct abbrev_info **abbrevs; + /* DW_AT_language. */ + int lang; + /* Note that an error was found by comp_unit_find_nearest_line. */ int error; @@ -290,6 +305,7 @@ const struct dwarf_debug_section dwarf_debug_sections[] = { ".debug_aranges", ".zdebug_aranges" }, { ".debug_frame", ".zdebug_frame" }, { ".debug_info", ".zdebug_info" }, + { ".debug_info", ".zdebug_info" }, { ".debug_line", ".zdebug_line" }, { ".debug_loc", ".zdebug_loc" }, { ".debug_macinfo", ".zdebug_macinfo" }, @@ -300,6 +316,7 @@ const struct dwarf_debug_section dwarf_debug_sections[] = { ".debug_static_func", ".zdebug_static_func" }, { ".debug_static_vars", ".zdebug_static_vars" }, { ".debug_str", ".zdebug_str", }, + { ".debug_str", ".zdebug_str", }, { ".debug_types", ".zdebug_types" }, /* GNU DWARF 1 extensions */ { ".debug_sfnames", ".zdebug_sfnames" }, @@ -312,12 +329,15 @@ const struct dwarf_debug_section dwarf_debug_sections[] = { NULL, NULL }, }; +/* NB/ Numbers in this enum must match up with indicies + into the dwarf_debug_sections[] array above. */ enum dwarf_debug_section_enum { debug_abbrev = 0, debug_aranges, debug_frame, debug_info, + debug_info_alt, debug_line, debug_loc, debug_macinfo, @@ -328,6 +348,7 @@ enum dwarf_debug_section_enum debug_static_func, debug_static_vars, debug_str, + debug_str_alt, debug_types, debug_sfnames, debug_srcinfo, @@ -383,7 +404,7 @@ info_hash_table_newfunc (struct bfd_hash_entry *entry, if (ret == NULL) { ret = (struct info_hash_entry *) bfd_hash_allocate (table, - sizeof (* ret)); + sizeof (* ret)); if (ret == NULL) return NULL; } @@ -443,7 +464,7 @@ insert_info_hash_table (struct info_hash_table *hash_table, return FALSE; node = (struct info_list_node *) bfd_hash_allocate (&hash_table->base, - sizeof (*node)); + sizeof (*node)); if (!node) return FALSE; @@ -484,20 +505,20 @@ read_section (bfd * abfd, asection *msec; const char *section_name = sec->uncompressed_name; - /* read_section is a noop if the section has already been read. */ - if (!*section_buffer) + /* The section may have already been read. */ + if (*section_buffer == NULL) { msec = bfd_get_section_by_name (abfd, section_name); if (! msec) { section_name = sec->compressed_name; - if (section_name != NULL) - msec = bfd_get_section_by_name (abfd, section_name); + if (section_name != NULL) + msec = bfd_get_section_by_name (abfd, section_name); } if (! msec) { (*_bfd_error_handler) (_("Dwarf Error: Can't find %s section."), - sec->uncompressed_name); + sec->uncompressed_name); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -535,101 +556,259 @@ read_section (bfd * abfd, return TRUE; } -/* VERBATIM - The following function up to the END VERBATIM mark are - copied directly from dwarf2read.c. */ - /* Read dwarf information from a buffer. */ static unsigned int -read_1_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf) +read_1_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf, bfd_byte *end) { + if (buf + 1 > end) + return 0; return bfd_get_8 (abfd, buf); } static int -read_1_signed_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf) +read_1_signed_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf, bfd_byte *end) { + if (buf + 1 > end) + return 0; return bfd_get_signed_8 (abfd, buf); } static unsigned int -read_2_bytes (bfd *abfd, bfd_byte *buf) +read_2_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end) { + if (buf + 2 > end) + return 0; return bfd_get_16 (abfd, buf); } static unsigned int -read_4_bytes (bfd *abfd, bfd_byte *buf) +read_4_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end) { + if (buf + 4 > end) + return 0; return bfd_get_32 (abfd, buf); } static bfd_uint64_t -read_8_bytes (bfd *abfd, bfd_byte *buf) +read_8_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end) { + if (buf + 8 > end) + return 0; return bfd_get_64 (abfd, buf); } static bfd_byte * read_n_bytes (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf, + bfd_byte *end, unsigned int size ATTRIBUTE_UNUSED) { + if (buf + size > end) + return NULL; return buf; } +/* Scans a NUL terminated string starting at BUF, returning a pointer to it. + Returns the number of characters in the string, *including* the NUL byte, + in BYTES_READ_PTR. This value is set even if the function fails. Bytes + at or beyond BUF_END will not be read. Returns NULL if there was a + problem, or if the string is empty. */ + static char * -read_string (bfd *abfd ATTRIBUTE_UNUSED, - bfd_byte *buf, - unsigned int *bytes_read_ptr) +read_string (bfd * abfd ATTRIBUTE_UNUSED, + bfd_byte * buf, + bfd_byte * buf_end, + unsigned int * bytes_read_ptr) { - /* Return a pointer to the embedded string. */ - char *str = (char *) buf; + bfd_byte *str = buf; + + if (buf >= buf_end) + { + * bytes_read_ptr = 0; + return NULL; + } if (*str == '\0') { - *bytes_read_ptr = 1; + * bytes_read_ptr = 1; return NULL; } - *bytes_read_ptr = strlen (str) + 1; - return str; + while (buf < buf_end) + if (* buf ++ == 0) + { + * bytes_read_ptr = buf - str; + return (char *) str; + } + + * bytes_read_ptr = buf - str; + return NULL; } -/* END VERBATIM */ +/* Reads an offset from BUF and then locates the string at this offset + inside the debug string section. Returns a pointer to the string. + Returns the number of bytes read from BUF, *not* the length of the string, + in BYTES_READ_PTR. This value is set even if the function fails. Bytes + at or beyond BUF_END will not be read from BUF. Returns NULL if there was + a problem, or if the string is empty. Does not check for NUL termination + of the string. */ static char * read_indirect_string (struct comp_unit * unit, bfd_byte * buf, + bfd_byte * buf_end, unsigned int * bytes_read_ptr) { bfd_uint64_t offset; struct dwarf2_debug *stash = unit->stash; char *str; + if (buf + unit->offset_size > buf_end) + { + * bytes_read_ptr = 0; + return NULL; + } + if (unit->offset_size == 4) - offset = read_4_bytes (unit->abfd, buf); + offset = read_4_bytes (unit->abfd, buf, buf_end); else - offset = read_8_bytes (unit->abfd, buf); + offset = read_8_bytes (unit->abfd, buf, buf_end); *bytes_read_ptr = unit->offset_size; if (! read_section (unit->abfd, &stash->debug_sections[debug_str], - stash->syms, offset, + stash->syms, offset, &stash->dwarf_str_buffer, &stash->dwarf_str_size)) return NULL; + if (offset >= stash->dwarf_str_size) + return NULL; str = (char *) stash->dwarf_str_buffer + offset; if (*str == '\0') return NULL; return str; } +/* Like read_indirect_string but uses a .debug_str located in + an alternate file pointed to by the .gnu_debugaltlink section. + Used to impement DW_FORM_GNU_strp_alt. */ + +static char * +read_alt_indirect_string (struct comp_unit * unit, + bfd_byte * buf, + bfd_byte * buf_end, + unsigned int * bytes_read_ptr) +{ + bfd_uint64_t offset; + struct dwarf2_debug *stash = unit->stash; + char *str; + + if (buf + unit->offset_size > buf_end) + { + * bytes_read_ptr = 0; + return NULL; + } + + if (unit->offset_size == 4) + offset = read_4_bytes (unit->abfd, buf, buf_end); + else + offset = read_8_bytes (unit->abfd, buf, buf_end); + + *bytes_read_ptr = unit->offset_size; + + if (stash->alt_bfd_ptr == NULL) + { + bfd * debug_bfd; + char * debug_filename = bfd_follow_gnu_debugaltlink (unit->abfd, DEBUGDIR); + + if (debug_filename == NULL) + return NULL; + + if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL + || ! bfd_check_format (debug_bfd, bfd_object)) + { + if (debug_bfd) + bfd_close (debug_bfd); + + /* FIXME: Should we report our failure to follow the debuglink ? */ + free (debug_filename); + return NULL; + } + stash->alt_bfd_ptr = debug_bfd; + } + + if (! read_section (unit->stash->alt_bfd_ptr, + stash->debug_sections + debug_str_alt, + NULL, /* FIXME: Do we need to load alternate symbols ? */ + offset, + &stash->alt_dwarf_str_buffer, + &stash->alt_dwarf_str_size)) + return NULL; + + if (offset >= stash->alt_dwarf_str_size) + return NULL; + str = (char *) stash->alt_dwarf_str_buffer + offset; + if (*str == '\0') + return NULL; + + return str; +} + +/* Resolve an alternate reference from UNIT at OFFSET. + Returns a pointer into the loaded alternate CU upon success + or NULL upon failure. */ + +static bfd_byte * +read_alt_indirect_ref (struct comp_unit * unit, + bfd_uint64_t offset) +{ + struct dwarf2_debug *stash = unit->stash; + + if (stash->alt_bfd_ptr == NULL) + { + bfd * debug_bfd; + char * debug_filename = bfd_follow_gnu_debugaltlink (unit->abfd, DEBUGDIR); + + if (debug_filename == NULL) + return FALSE; + + if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL + || ! bfd_check_format (debug_bfd, bfd_object)) + { + if (debug_bfd) + bfd_close (debug_bfd); + + /* FIXME: Should we report our failure to follow the debuglink ? */ + free (debug_filename); + return NULL; + } + stash->alt_bfd_ptr = debug_bfd; + } + + if (! read_section (unit->stash->alt_bfd_ptr, + stash->debug_sections + debug_info_alt, + NULL, /* FIXME: Do we need to load alternate symbols ? */ + offset, + &stash->alt_dwarf_info_buffer, + &stash->alt_dwarf_info_size)) + return NULL; + + if (offset >= stash->alt_dwarf_info_size) + return NULL; + return stash->alt_dwarf_info_buffer + offset; +} + static bfd_uint64_t -read_address (struct comp_unit *unit, bfd_byte *buf) +read_address (struct comp_unit *unit, bfd_byte *buf, bfd_byte * buf_end) { - int signed_vma = get_elf_backend_data (unit->abfd)->sign_extend_vma; + int signed_vma = 0; + + if (bfd_get_flavour (unit->abfd) == bfd_target_elf_flavour) + signed_vma = get_elf_backend_data (unit->abfd)->sign_extend_vma; + + if (buf + unit->addr_size > buf_end) + return 0; if (signed_vma) { @@ -693,23 +872,28 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash) { struct abbrev_info **abbrevs; bfd_byte *abbrev_ptr; + bfd_byte *abbrev_end; struct abbrev_info *cur_abbrev; unsigned int abbrev_number, bytes_read, abbrev_name; unsigned int abbrev_form, hash_number; bfd_size_type amt; if (! read_section (abfd, &stash->debug_sections[debug_abbrev], - stash->syms, offset, + stash->syms, offset, &stash->dwarf_abbrev_buffer, &stash->dwarf_abbrev_size)) return NULL; + if (offset >= stash->dwarf_abbrev_size) + return NULL; + amt = sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE; abbrevs = (struct abbrev_info **) bfd_zalloc (abfd, amt); if (abbrevs == NULL) return NULL; abbrev_ptr = stash->dwarf_abbrev_buffer + offset; - abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); + abbrev_end = stash->dwarf_abbrev_buffer + stash->dwarf_abbrev_size; + abbrev_number = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end); abbrev_ptr += bytes_read; /* Loop until we reach an abbrev number of 0. */ @@ -723,15 +907,15 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash) /* Read in abbrev header. */ cur_abbrev->number = abbrev_number; cur_abbrev->tag = (enum dwarf_tag) - read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); + safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end); abbrev_ptr += bytes_read; - cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr); + cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr, abbrev_end); abbrev_ptr += 1; /* Now read in declarations. */ - abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); + abbrev_name = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end); abbrev_ptr += bytes_read; - abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); + abbrev_form = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end); abbrev_ptr += bytes_read; while (abbrev_name) @@ -766,9 +950,9 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash) = (enum dwarf_attribute) abbrev_name; cur_abbrev->attrs[cur_abbrev->num_attrs++].form = (enum dwarf_form) abbrev_form; - abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); + abbrev_name = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end); abbrev_ptr += bytes_read; - abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); + abbrev_form = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end); abbrev_ptr += bytes_read; } @@ -786,28 +970,46 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash) if ((unsigned int) (abbrev_ptr - stash->dwarf_abbrev_buffer) >= stash->dwarf_abbrev_size) break; - abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); + abbrev_number = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end); abbrev_ptr += bytes_read; - if (lookup_abbrev (abbrev_number,abbrevs) != NULL) + if (lookup_abbrev (abbrev_number, abbrevs) != NULL) break; } return abbrevs; } -/* Read an attribute value described by an attribute form. */ +/* Returns true if the form is one which has a string value. */ + +static inline bfd_boolean +is_str_attr (enum dwarf_form form) +{ + return form == DW_FORM_string || form == DW_FORM_strp || form == DW_FORM_GNU_strp_alt; +} + +/* Read and fill in the value of attribute ATTR as described by FORM. + Read data starting from INFO_PTR, but never at or beyond INFO_PTR_END. + Returns an updated INFO_PTR taking into account the amount of data read. */ static bfd_byte * -read_attribute_value (struct attribute *attr, - unsigned form, - struct comp_unit *unit, - bfd_byte *info_ptr) +read_attribute_value (struct attribute * attr, + unsigned form, + struct comp_unit * unit, + bfd_byte * info_ptr, + bfd_byte * info_ptr_end) { bfd *abfd = unit->abfd; unsigned int bytes_read; struct dwarf_block *blk; bfd_size_type amt; + if (info_ptr >= info_ptr_end) + { + (*_bfd_error_handler) (_("Dwarf Error: Info pointer extends beyond end of attributes")); + bfd_set_error (bfd_error_bad_value); + return info_ptr; + } + attr->form = (enum dwarf_form) form; switch (form) @@ -818,22 +1020,23 @@ read_attribute_value (struct attribute *attr, if (unit->version == 3 || unit->version == 4) { if (unit->offset_size == 4) - attr->u.val = read_4_bytes (unit->abfd, info_ptr); + attr->u.val = read_4_bytes (unit->abfd, info_ptr, info_ptr_end); else - attr->u.val = read_8_bytes (unit->abfd, info_ptr); + attr->u.val = read_8_bytes (unit->abfd, info_ptr, info_ptr_end); info_ptr += unit->offset_size; break; } /* FALLTHROUGH */ case DW_FORM_addr: - attr->u.val = read_address (unit, info_ptr); + attr->u.val = read_address (unit, info_ptr, info_ptr_end); info_ptr += unit->addr_size; break; + case DW_FORM_GNU_ref_alt: case DW_FORM_sec_offset: if (unit->offset_size == 4) - attr->u.val = read_4_bytes (unit->abfd, info_ptr); + attr->u.val = read_4_bytes (unit->abfd, info_ptr, info_ptr_end); else - attr->u.val = read_8_bytes (unit->abfd, info_ptr); + attr->u.val = read_8_bytes (unit->abfd, info_ptr, info_ptr_end); info_ptr += unit->offset_size; break; case DW_FORM_block2: @@ -841,9 +1044,9 @@ read_attribute_value (struct attribute *attr, blk = (struct dwarf_block *) bfd_alloc (abfd, amt); if (blk == NULL) return NULL; - blk->size = read_2_bytes (abfd, info_ptr); + blk->size = read_2_bytes (abfd, info_ptr, info_ptr_end); info_ptr += 2; - blk->data = read_n_bytes (abfd, info_ptr, blk->size); + blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size); info_ptr += blk->size; attr->u.blk = blk; break; @@ -852,30 +1055,34 @@ read_attribute_value (struct attribute *attr, blk = (struct dwarf_block *) bfd_alloc (abfd, amt); if (blk == NULL) return NULL; - blk->size = read_4_bytes (abfd, info_ptr); + blk->size = read_4_bytes (abfd, info_ptr, info_ptr_end); info_ptr += 4; - blk->data = read_n_bytes (abfd, info_ptr, blk->size); + blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size); info_ptr += blk->size; attr->u.blk = blk; break; case DW_FORM_data2: - attr->u.val = read_2_bytes (abfd, info_ptr); + attr->u.val = read_2_bytes (abfd, info_ptr, info_ptr_end); info_ptr += 2; break; case DW_FORM_data4: - attr->u.val = read_4_bytes (abfd, info_ptr); + attr->u.val = read_4_bytes (abfd, info_ptr, info_ptr_end); info_ptr += 4; break; case DW_FORM_data8: - attr->u.val = read_8_bytes (abfd, info_ptr); + attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end); info_ptr += 8; break; case DW_FORM_string: - attr->u.str = read_string (abfd, info_ptr, &bytes_read); + attr->u.str = read_string (abfd, info_ptr, info_ptr_end, &bytes_read); info_ptr += bytes_read; break; case DW_FORM_strp: - attr->u.str = read_indirect_string (unit, info_ptr, &bytes_read); + attr->u.str = read_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_GNU_strp_alt: + attr->u.str = read_alt_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read); info_ptr += bytes_read; break; case DW_FORM_exprloc: @@ -884,9 +1091,9 @@ read_attribute_value (struct attribute *attr, blk = (struct dwarf_block *) bfd_alloc (abfd, amt); if (blk == NULL) return NULL; - blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + blk->size = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end); info_ptr += bytes_read; - blk->data = read_n_bytes (abfd, info_ptr, blk->size); + blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size); info_ptr += blk->size; attr->u.blk = blk; break; @@ -895,62 +1102,62 @@ read_attribute_value (struct attribute *attr, blk = (struct dwarf_block *) bfd_alloc (abfd, amt); if (blk == NULL) return NULL; - blk->size = read_1_byte (abfd, info_ptr); + blk->size = read_1_byte (abfd, info_ptr, info_ptr_end); info_ptr += 1; - blk->data = read_n_bytes (abfd, info_ptr, blk->size); + blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size); info_ptr += blk->size; attr->u.blk = blk; break; case DW_FORM_data1: - attr->u.val = read_1_byte (abfd, info_ptr); + attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end); info_ptr += 1; break; case DW_FORM_flag: - attr->u.val = read_1_byte (abfd, info_ptr); + attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end); info_ptr += 1; break; case DW_FORM_flag_present: attr->u.val = 1; break; case DW_FORM_sdata: - attr->u.sval = read_signed_leb128 (abfd, info_ptr, &bytes_read); + attr->u.sval = safe_read_leb128 (abfd, info_ptr, &bytes_read, TRUE, info_ptr_end); info_ptr += bytes_read; break; case DW_FORM_udata: - attr->u.val = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + attr->u.val = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end); info_ptr += bytes_read; break; case DW_FORM_ref1: - attr->u.val = read_1_byte (abfd, info_ptr); + attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end); info_ptr += 1; break; case DW_FORM_ref2: - attr->u.val = read_2_bytes (abfd, info_ptr); + attr->u.val = read_2_bytes (abfd, info_ptr, info_ptr_end); info_ptr += 2; break; case DW_FORM_ref4: - attr->u.val = read_4_bytes (abfd, info_ptr); + attr->u.val = read_4_bytes (abfd, info_ptr, info_ptr_end); info_ptr += 4; break; case DW_FORM_ref8: - attr->u.val = read_8_bytes (abfd, info_ptr); + attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end); info_ptr += 8; break; case DW_FORM_ref_sig8: - attr->u.val = read_8_bytes (abfd, info_ptr); + attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end); info_ptr += 8; break; case DW_FORM_ref_udata: - attr->u.val = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + attr->u.val = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end); info_ptr += bytes_read; break; case DW_FORM_indirect: - form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + form = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end); info_ptr += bytes_read; - info_ptr = read_attribute_value (attr, form, unit, info_ptr); + info_ptr = read_attribute_value (attr, form, unit, info_ptr, info_ptr_end); break; default: - (*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %u."), + (*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %#x."), form); bfd_set_error (bfd_error_bad_value); return NULL; @@ -961,16 +1168,44 @@ read_attribute_value (struct attribute *attr, /* Read an attribute described by an abbreviated attribute. */ static bfd_byte * -read_attribute (struct attribute *attr, - struct attr_abbrev *abbrev, - struct comp_unit *unit, - bfd_byte *info_ptr) +read_attribute (struct attribute * attr, + struct attr_abbrev * abbrev, + struct comp_unit * unit, + bfd_byte * info_ptr, + bfd_byte * info_ptr_end) { attr->name = abbrev->name; - info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr); + info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr, info_ptr_end); return info_ptr; } +/* Return whether DW_AT_name will return the same as DW_AT_linkage_name + for a function. */ + +static bfd_boolean +non_mangled (int lang) +{ + switch (lang) + { + default: + return FALSE; + + case DW_LANG_C89: + case DW_LANG_C: + case DW_LANG_Ada83: + case DW_LANG_Cobol74: + case DW_LANG_Cobol85: + case DW_LANG_Fortran77: + case DW_LANG_Pascal83: + case DW_LANG_C99: + case DW_LANG_Ada95: + case DW_LANG_PLI: + case DW_LANG_UPC: + case DW_LANG_C11: + return TRUE; + } +} + /* Source line information table routines. */ #define FILE_ALLOC_CHUNK 5 @@ -1029,14 +1264,15 @@ struct funcinfo struct funcinfo *caller_func; /* Source location file name where caller_func inlines this func. */ char *caller_file; - /* Source location line number where caller_func inlines this func. */ - int caller_line; /* Source location file name. */ char *file; + /* Source location line number where caller_func inlines this func. */ + int caller_line; /* Source location line number. */ int line; int tag; - char *name; + bfd_boolean is_linkage; + const char *name; struct arange arange; /* Where the symbol is defined. */ asection *sec; @@ -1192,7 +1428,7 @@ add_line_info (struct line_info_table *table, info->prev_line = table->lcl_head->prev_line; table->lcl_head->prev_line = info; if (address < seq->low_pc) - seq->low_pc = address; + seq->low_pc = address; } return TRUE; } @@ -1224,7 +1460,11 @@ concat_filename (struct line_info_table *table, unsigned int file) char *name; size_t len; - if (table->files[file - 1].dir) + if (table->files[file - 1].dir + /* PR 17512: file: 0317e960. */ + && table->files[file - 1].dir <= table->num_dirs + /* PR 17512: file: 7f3d2e4b. */ + && table->dirs != NULL) subdir_name = table->dirs[table->files[file - 1].dir - 1]; if (!subdir_name || !IS_ABSOLUTE_PATH (subdir_name)) @@ -1383,21 +1623,21 @@ sort_line_sequences (struct line_info_table* table) for (n = 1; n < table->num_sequences; n++) { if (sequences[n].low_pc < last_high_pc) - { + { if (sequences[n].last_line->address <= last_high_pc) /* Skip nested entries. */ continue; /* Trim overlapping entries. */ sequences[n].low_pc = last_high_pc; - } + } last_high_pc = sequences[n].last_line->address; if (n > num_sequences) - { - /* Close up the gap. */ - sequences[num_sequences].low_pc = sequences[n].low_pc; - sequences[num_sequences].last_line = sequences[n].last_line; - } + { + /* Close up the gap. */ + sequences[num_sequences].low_pc = sequences[n].low_pc; + sequences[num_sequences].last_line = sequences[n].last_line; + } num_sequences++; } @@ -1423,7 +1663,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) bfd_size_type amt; if (! read_section (abfd, &stash->debug_sections[debug_line], - stash->syms, unit->line_offset, + stash->syms, unit->line_offset, &stash->dwarf_line_buffer, &stash->dwarf_line_size)) return NULL; @@ -1445,27 +1685,47 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) table->lcl_head = NULL; + if (stash->dwarf_line_size < 16) + { + (*_bfd_error_handler) + (_("Dwarf Error: Line info section is too small (%ld)"), + (long) stash->dwarf_line_size); + bfd_set_error (bfd_error_bad_value); + return NULL; + } line_ptr = stash->dwarf_line_buffer + unit->line_offset; + line_end = stash->dwarf_line_buffer + stash->dwarf_line_size; /* Read in the prologue. */ - lh.total_length = read_4_bytes (abfd, line_ptr); + lh.total_length = read_4_bytes (abfd, line_ptr, line_end); line_ptr += 4; offset_size = 4; if (lh.total_length == 0xffffffff) { - lh.total_length = read_8_bytes (abfd, line_ptr); + lh.total_length = read_8_bytes (abfd, line_ptr, line_end); line_ptr += 8; offset_size = 8; } else if (lh.total_length == 0 && unit->addr_size == 8) { /* Handle (non-standard) 64-bit DWARF2 formats. */ - lh.total_length = read_4_bytes (abfd, line_ptr); + lh.total_length = read_4_bytes (abfd, line_ptr, line_end); line_ptr += 4; offset_size = 8; } + + if (lh.total_length > stash->dwarf_line_size) + { + (*_bfd_error_handler) + (_("Dwarf Error: Line info data is bigger (0x%lx) than the section (0x%lx)"), + (long) lh.total_length, (long) stash->dwarf_line_size); + bfd_set_error (bfd_error_bad_value); + return NULL; + } + line_end = line_ptr + lh.total_length; - lh.version = read_2_bytes (abfd, line_ptr); + + lh.version = read_2_bytes (abfd, line_ptr, line_end); if (lh.version < 2 || lh.version > 4) { (*_bfd_error_handler) @@ -1474,20 +1734,32 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) return NULL; } line_ptr += 2; + + if (line_ptr + offset_size + (lh.version >=4 ? 6 : 5) >= line_end) + { + (*_bfd_error_handler) + (_("Dwarf Error: Ran out of room reading prologue")); + bfd_set_error (bfd_error_bad_value); + return NULL; + } + if (offset_size == 4) - lh.prologue_length = read_4_bytes (abfd, line_ptr); + lh.prologue_length = read_4_bytes (abfd, line_ptr, line_end); else - lh.prologue_length = read_8_bytes (abfd, line_ptr); + lh.prologue_length = read_8_bytes (abfd, line_ptr, line_end); line_ptr += offset_size; - lh.minimum_instruction_length = read_1_byte (abfd, line_ptr); + + lh.minimum_instruction_length = read_1_byte (abfd, line_ptr, line_end); line_ptr += 1; + if (lh.version >= 4) { - lh.maximum_ops_per_insn = read_1_byte (abfd, line_ptr); + lh.maximum_ops_per_insn = read_1_byte (abfd, line_ptr, line_end); line_ptr += 1; } else lh.maximum_ops_per_insn = 1; + if (lh.maximum_ops_per_insn == 0) { (*_bfd_error_handler) @@ -1495,14 +1767,26 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) bfd_set_error (bfd_error_bad_value); return NULL; } - lh.default_is_stmt = read_1_byte (abfd, line_ptr); + + lh.default_is_stmt = read_1_byte (abfd, line_ptr, line_end); line_ptr += 1; - lh.line_base = read_1_signed_byte (abfd, line_ptr); + + lh.line_base = read_1_signed_byte (abfd, line_ptr, line_end); line_ptr += 1; - lh.line_range = read_1_byte (abfd, line_ptr); + + lh.line_range = read_1_byte (abfd, line_ptr, line_end); line_ptr += 1; - lh.opcode_base = read_1_byte (abfd, line_ptr); + + lh.opcode_base = read_1_byte (abfd, line_ptr, line_end); line_ptr += 1; + + if (line_ptr + (lh.opcode_base - 1) >= line_end) + { + (*_bfd_error_handler) (_("Dwarf Error: Ran out of room reading opcodes")); + bfd_set_error (bfd_error_bad_value); + return NULL; + } + amt = lh.opcode_base * sizeof (unsigned char); lh.standard_opcode_lengths = (unsigned char *) bfd_alloc (abfd, amt); @@ -1510,12 +1794,12 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) for (i = 1; i < lh.opcode_base; ++i) { - lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr); + lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr, line_end); line_ptr += 1; } /* Read directory table. */ - while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL) + while ((cur_dir = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL) { line_ptr += bytes_read; @@ -1538,7 +1822,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) line_ptr += bytes_read; /* Read file name table. */ - while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL) + while ((cur_file = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL) { line_ptr += bytes_read; @@ -1557,13 +1841,11 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) table->files[table->num_files].name = cur_file; table->files[table->num_files].dir = - read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); line_ptr += bytes_read; - table->files[table->num_files].time = - read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + table->files[table->num_files].time = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); line_ptr += bytes_read; - table->files[table->num_files].size = - read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + table->files[table->num_files].size = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); line_ptr += bytes_read; table->num_files++; } @@ -1593,13 +1875,15 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) /* Decode the table. */ while (! end_sequence) { - op_code = read_1_byte (abfd, line_ptr); + op_code = read_1_byte (abfd, line_ptr, line_end); line_ptr += 1; if (op_code >= lh.opcode_base) { /* Special operand. */ adj_opcode = op_code - lh.opcode_base; + if (lh.line_range == 0) + goto line_fail; if (lh.maximum_ops_per_insn == 1) address += (adj_opcode / lh.line_range * lh.minimum_instruction_length); @@ -1616,7 +1900,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) if (!add_line_info (table, address, op_index, filename, line, column, discriminator, 0)) goto line_fail; - discriminator = 0; + discriminator = 0; if (address < low_pc) low_pc = address; if (address > high_pc) @@ -1625,9 +1909,9 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) else switch (op_code) { case DW_LNS_extended_op: - exop_len = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + exop_len = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); line_ptr += bytes_read; - extended_op = read_1_byte (abfd, line_ptr); + extended_op = read_1_byte (abfd, line_ptr, line_end); line_ptr += 1; switch (extended_op) @@ -1637,7 +1921,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) if (!add_line_info (table, address, op_index, filename, line, column, discriminator, end_sequence)) goto line_fail; - discriminator = 0; + discriminator = 0; if (address < low_pc) low_pc = address; if (address > high_pc) @@ -1646,12 +1930,12 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) goto line_fail; break; case DW_LNE_set_address: - address = read_address (unit, line_ptr); + address = read_address (unit, line_ptr, line_end); op_index = 0; line_ptr += unit->addr_size; break; case DW_LNE_define_file: - cur_file = read_string (abfd, line_ptr, &bytes_read); + cur_file = read_string (abfd, line_ptr, line_end, &bytes_read); line_ptr += bytes_read; if ((table->num_files % FILE_ALLOC_CHUNK) == 0) { @@ -1666,19 +1950,19 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) } table->files[table->num_files].name = cur_file; table->files[table->num_files].dir = - read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); line_ptr += bytes_read; table->files[table->num_files].time = - read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); line_ptr += bytes_read; table->files[table->num_files].size = - read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); line_ptr += bytes_read; table->num_files++; break; case DW_LNE_set_discriminator: discriminator = - read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); line_ptr += bytes_read; break; case DW_LNE_HP_source_file_correlation: @@ -1698,7 +1982,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) if (!add_line_info (table, address, op_index, filename, line, column, discriminator, 0)) goto line_fail; - discriminator = 0; + discriminator = 0; if (address < low_pc) low_pc = address; if (address > high_pc) @@ -1707,12 +1991,12 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) case DW_LNS_advance_pc: if (lh.maximum_ops_per_insn == 1) address += (lh.minimum_instruction_length - * read_unsigned_leb128 (abfd, line_ptr, - &bytes_read)); + * safe_read_leb128 (abfd, line_ptr, &bytes_read, + FALSE, line_end)); else { - bfd_vma adjust = read_unsigned_leb128 (abfd, line_ptr, - &bytes_read); + bfd_vma adjust = safe_read_leb128 (abfd, line_ptr, &bytes_read, + FALSE, line_end); address = ((op_index + adjust) / lh.maximum_ops_per_insn * lh.minimum_instruction_length); op_index = (op_index + adjust) % lh.maximum_ops_per_insn; @@ -1720,7 +2004,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) line_ptr += bytes_read; break; case DW_LNS_advance_line: - line += read_signed_leb128 (abfd, line_ptr, &bytes_read); + line += safe_read_leb128 (abfd, line_ptr, &bytes_read, TRUE, line_end); line_ptr += bytes_read; break; case DW_LNS_set_file: @@ -1729,7 +2013,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) /* The file and directory tables are 0 based, the references are 1 based. */ - file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + file = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); line_ptr += bytes_read; if (filename) free (filename); @@ -1737,7 +2021,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) break; } case DW_LNS_set_column: - column = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + column = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); line_ptr += bytes_read; break; case DW_LNS_negate_stmt: @@ -1759,7 +2043,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) } break; case DW_LNS_fixed_advance_pc: - address += read_2_bytes (abfd, line_ptr); + address += read_2_bytes (abfd, line_ptr, line_end); op_index = 0; line_ptr += 2; break; @@ -1767,7 +2051,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) /* Unknown standard opcode, ignore it. */ for (i = 0; i < lh.standard_opcode_lengths[op_code]; i++) { - (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + (void) safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); line_ptr += bytes_read; } break; @@ -1791,11 +2075,13 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) return NULL; } -/* If ADDR is within TABLE set the output parameters and return TRUE, - otherwise return FALSE. The output parameters, FILENAME_PTR and - LINENUMBER_PTR, are pointers to the objects to be filled in. */ +/* If ADDR is within TABLE set the output parameters and return the + range of addresses covered by the entry used to fill them out. + Otherwise set * FILENAME_PTR to NULL and return 0. + The parameters FILENAME_PTR, LINENUMBER_PTR and DISCRIMINATOR_PTR + are pointers to the objects to be filled in. */ -static bfd_boolean +static bfd_vma lookup_address_in_line_info_table (struct line_info_table *table, bfd_vma addr, const char **filename_ptr, @@ -1825,24 +2111,24 @@ lookup_address_in_line_info_table (struct line_info_table *table, { /* Note: seq->last_line should be a descendingly sorted list. */ for (each_line = seq->last_line; - each_line; - each_line = each_line->prev_line) - if (addr >= each_line->address) - break; + each_line; + each_line = each_line->prev_line) + if (addr >= each_line->address) + break; if (each_line - && !(each_line->end_sequence || each_line == seq->last_line)) - { - *filename_ptr = each_line->filename; - *linenumber_ptr = each_line->line; - if (discriminator_ptr) - *discriminator_ptr = each_line->discriminator; - return TRUE; - } + && !(each_line->end_sequence || each_line == seq->last_line)) + { + *filename_ptr = each_line->filename; + *linenumber_ptr = each_line->line; + if (discriminator_ptr) + *discriminator_ptr = each_line->discriminator; + return seq->last_line->address - seq->low_pc; + } } *filename_ptr = NULL; - return FALSE; + return 0; } /* Read in the .debug_ranges section for future reference. */ @@ -1852,25 +2138,25 @@ read_debug_ranges (struct comp_unit *unit) { struct dwarf2_debug *stash = unit->stash; return read_section (unit->abfd, &stash->debug_sections[debug_ranges], - stash->syms, 0, + stash->syms, 0, &stash->dwarf_ranges_buffer, &stash->dwarf_ranges_size); } /* Function table functions. */ -/* If ADDR is within TABLE, set FUNCTIONNAME_PTR, and return TRUE. - Note that we need to find the function that has the smallest - range that contains ADDR, to handle inlined functions without - depending upon them being ordered in TABLE by increasing range. */ +/* If ADDR is within UNIT's function tables, set FUNCTION_PTR, and return + TRUE. Note that we need to find the function that has the smallest range + that contains ADDR, to handle inlined functions without depending upon + them being ordered in TABLE by increasing range. */ static bfd_boolean lookup_address_in_function_table (struct comp_unit *unit, bfd_vma addr, - struct funcinfo **function_ptr, - const char **functionname_ptr) + struct funcinfo **function_ptr) { struct funcinfo* each_func; struct funcinfo* best_fit = NULL; + bfd_vma best_fit_len = 0; struct arange *arange; for (each_func = unit->function_table; @@ -1884,23 +2170,21 @@ lookup_address_in_function_table (struct comp_unit *unit, if (addr >= arange->low && addr < arange->high) { if (!best_fit - || (arange->high - arange->low - < best_fit->arange.high - best_fit->arange.low)) - best_fit = each_func; + || arange->high - arange->low < best_fit_len) + { + best_fit = each_func; + best_fit_len = arange->high - arange->low; + } } } } if (best_fit) { - *functionname_ptr = best_fit->name; *function_ptr = best_fit; return TRUE; } - else - { - return FALSE; - } + return FALSE; } /* If SYM at ADDR is within function table of UNIT, set FILENAME_PTR @@ -1915,6 +2199,7 @@ lookup_symbol_in_function_table (struct comp_unit *unit, { struct funcinfo* each_func; struct funcinfo* best_fit = NULL; + bfd_vma best_fit_len = 0; struct arange *arange; const char *name = bfd_asymbol_name (sym); asection *sec = bfd_get_section (sym); @@ -1933,9 +2218,11 @@ lookup_symbol_in_function_table (struct comp_unit *unit, && each_func->name && strcmp (name, each_func->name) == 0 && (!best_fit - || (arange->high - arange->low - < best_fit->arange.high - best_fit->arange.low))) - best_fit = each_func; + || arange->high - arange->low < best_fit_len)) + { + best_fit = each_func; + best_fit_len = arange->high - arange->low; + } } } @@ -1988,15 +2275,17 @@ lookup_symbol_in_variable_table (struct comp_unit *unit, static char * find_abstract_instance_name (struct comp_unit *unit, - struct attribute *attr_ptr) + struct attribute *attr_ptr, + bfd_boolean *is_linkage) { bfd *abfd = unit->abfd; bfd_byte *info_ptr; + bfd_byte *info_ptr_end; unsigned int abbrev_number, bytes_read, i; struct abbrev_info *abbrev; bfd_uint64_t die_ref = attr_ptr->u.val; struct attribute attr; - char *name = 0; + char *name = NULL; /* DW_FORM_ref_addr can reference an entry in a different CU. It is an offset from the .debug_info section, not the current CU. */ @@ -2008,10 +2297,52 @@ find_abstract_instance_name (struct comp_unit *unit, abort (); info_ptr = unit->sec_info_ptr + die_ref; + info_ptr_end = unit->end_ptr; + + /* Now find the CU containing this pointer. */ + if (info_ptr >= unit->info_ptr_unit && info_ptr < unit->end_ptr) + ; + else + { + /* Check other CUs to see if they contain the abbrev. */ + struct comp_unit * u; + + for (u = unit->prev_unit; u != NULL; u = u->prev_unit) + if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr) + break; + + if (u == NULL) + for (u = unit->next_unit; u != NULL; u = u->next_unit) + if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr) + break; + + if (u) + unit = u; + /* else FIXME: What do we do now ? */ + } + } + else if (attr_ptr->form == DW_FORM_GNU_ref_alt) + { + info_ptr = read_alt_indirect_ref (unit, die_ref); + if (info_ptr == NULL) + { + (*_bfd_error_handler) + (_("Dwarf Error: Unable to read alt ref %u."), die_ref); + bfd_set_error (bfd_error_bad_value); + return NULL; + } + info_ptr_end = unit->stash->alt_dwarf_info_buffer + unit->stash->alt_dwarf_info_size; + + /* FIXME: Do we need to locate the correct CU, in a similar + fashion to the code in the DW_FORM_ref_addr case above ? */ } else - info_ptr = unit->info_ptr_unit + die_ref; - abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + { + info_ptr = unit->info_ptr_unit + die_ref; + info_ptr_end = unit->end_ptr; + } + + abbrev_number = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end); info_ptr += bytes_read; if (abbrev_number) @@ -2028,7 +2359,7 @@ find_abstract_instance_name (struct comp_unit *unit, for (i = 0; i < abbrev->num_attrs; ++i) { info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, - info_ptr); + info_ptr, info_ptr_end); if (info_ptr == NULL) break; switch (attr.name) @@ -2036,15 +2367,25 @@ find_abstract_instance_name (struct comp_unit *unit, case DW_AT_name: /* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name over DW_AT_name. */ - if (name == NULL) - name = attr.u.str; + if (name == NULL && is_str_attr (attr.form)) + { + name = attr.u.str; + if (non_mangled (unit->lang)) + *is_linkage = TRUE; + } break; case DW_AT_specification: - name = find_abstract_instance_name (unit, &attr); + name = find_abstract_instance_name (unit, &attr, is_linkage); break; case DW_AT_linkage_name: case DW_AT_MIPS_linkage_name: - name = attr.u.str; + /* PR 16949: Corrupt debug info can place + non-string forms into these attributes. */ + if (is_str_attr (attr.form)) + { + name = attr.u.str; + *is_linkage = TRUE; + } break; default: break; @@ -2060,6 +2401,7 @@ read_rangelist (struct comp_unit *unit, struct arange *arange, bfd_uint64_t offset) { bfd_byte *ranges_ptr; + bfd_byte *ranges_end; bfd_vma base_address = unit->base_address; if (! unit->stash->dwarf_ranges_buffer) @@ -2067,16 +2409,24 @@ read_rangelist (struct comp_unit *unit, struct arange *arange, if (! read_debug_ranges (unit)) return FALSE; } + ranges_ptr = unit->stash->dwarf_ranges_buffer + offset; + if (ranges_ptr < unit->stash->dwarf_ranges_buffer) + return FALSE; + ranges_end = unit->stash->dwarf_ranges_buffer + unit->stash->dwarf_ranges_size; for (;;) { bfd_vma low_pc; bfd_vma high_pc; - low_pc = read_address (unit, ranges_ptr); + /* PR 17512: file: 62cada7d. */ + if (ranges_ptr + 2 * unit->addr_size > ranges_end) + return FALSE; + + low_pc = read_address (unit, ranges_ptr, ranges_end); ranges_ptr += unit->addr_size; - high_pc = read_address (unit, ranges_ptr); + high_pc = read_address (unit, ranges_ptr, ranges_end); ranges_ptr += unit->addr_size; if (low_pc == 0 && high_pc == 0) @@ -2103,6 +2453,7 @@ scan_unit_for_symbols (struct comp_unit *unit) { bfd *abfd = unit->abfd; bfd_byte *info_ptr = unit->first_child_die_ptr; + bfd_byte *info_ptr_end = unit->stash->info_ptr_end; int nesting_level = 1; struct funcinfo **nested_funcs; int nested_funcs_size; @@ -2127,7 +2478,11 @@ scan_unit_for_symbols (struct comp_unit *unit) bfd_vma high_pc = 0; bfd_boolean high_pc_relative = FALSE; - abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + /* PR 17512: file: 9f405d9d. */ + if (info_ptr >= info_ptr_end) + goto fail; + + abbrev_number = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end); info_ptr += bytes_read; if (! abbrev_number) @@ -2191,7 +2546,7 @@ scan_unit_for_symbols (struct comp_unit *unit) for (i = 0; i < abbrev->num_attrs; ++i) { - info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr); + info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr, info_ptr_end); if (info_ptr == NULL) goto fail; @@ -2210,19 +2565,30 @@ scan_unit_for_symbols (struct comp_unit *unit) case DW_AT_abstract_origin: case DW_AT_specification: - func->name = find_abstract_instance_name (unit, &attr); + func->name = find_abstract_instance_name (unit, &attr, + &func->is_linkage); break; case DW_AT_name: /* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name over DW_AT_name. */ - if (func->name == NULL) - func->name = attr.u.str; + if (func->name == NULL && is_str_attr (attr.form)) + { + func->name = attr.u.str; + if (non_mangled (unit->lang)) + func->is_linkage = TRUE; + } break; case DW_AT_linkage_name: case DW_AT_MIPS_linkage_name: - func->name = attr.u.str; + /* PR 16949: Corrupt debug info can place + non-string forms into these attributes. */ + if (is_str_attr (attr.form)) + { + func->name = attr.u.str; + func->is_linkage = TRUE; + } break; case DW_AT_low_pc: @@ -2378,15 +2744,15 @@ parse_comp_unit (struct dwarf2_debug *stash, bfd *abfd = stash->bfd_ptr; bfd_boolean high_pc_relative = FALSE; - version = read_2_bytes (abfd, info_ptr); + version = read_2_bytes (abfd, info_ptr, end_ptr); info_ptr += 2; BFD_ASSERT (offset_size == 4 || offset_size == 8); if (offset_size == 4) - abbrev_offset = read_4_bytes (abfd, info_ptr); + abbrev_offset = read_4_bytes (abfd, info_ptr, end_ptr); else - abbrev_offset = read_8_bytes (abfd, info_ptr); + abbrev_offset = read_8_bytes (abfd, info_ptr, end_ptr); info_ptr += offset_size; - addr_size = read_1_byte (abfd, info_ptr); + addr_size = read_1_byte (abfd, info_ptr, end_ptr); info_ptr += 1; if (version != 2 && version != 3 && version != 4) @@ -2423,7 +2789,7 @@ parse_comp_unit (struct dwarf2_debug *stash, if (! abbrevs) return 0; - abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + abbrev_number = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, end_ptr); info_ptr += bytes_read; if (! abbrev_number) { @@ -2458,7 +2824,7 @@ parse_comp_unit (struct dwarf2_debug *stash, for (i = 0; i < abbrev->num_attrs; ++i) { - info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr); + info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr, end_ptr); if (info_ptr == NULL) return NULL; @@ -2497,6 +2863,15 @@ parse_comp_unit (struct dwarf2_debug *stash, case DW_AT_comp_dir: { char *comp_dir = attr.u.str; + + /* PR 17512: file: 1fe726be. */ + if (! is_str_attr (attr.form)) + { + (*_bfd_error_handler) + (_("Dwarf Error: DW_AT_comp_dir attribute encountered with a non-string form.")); + comp_dir = NULL; + } + if (comp_dir) { /* Irix 6.2 native cc prepends .: to the compilation @@ -2510,6 +2885,10 @@ parse_comp_unit (struct dwarf2_debug *stash, break; } + case DW_AT_language: + unit->lang = attr.u.val; + break; + default: break; } @@ -2554,24 +2933,22 @@ comp_unit_contains_address (struct comp_unit *unit, bfd_vma addr) /* If UNIT contains ADDR, set the output parameters to the values for the line containing ADDR. The output parameters, FILENAME_PTR, - FUNCTIONNAME_PTR, and LINENUMBER_PTR, are pointers to the objects + FUNCTION_PTR, and LINENUMBER_PTR, are pointers to the objects to be filled in. - Return TRUE if UNIT contains ADDR, and no errors were encountered; - FALSE otherwise. */ + Returns the range of addresses covered by the entry that was used + to fill in *LINENUMBER_PTR or 0 if it was not filled in. */ -static bfd_boolean +static bfd_vma comp_unit_find_nearest_line (struct comp_unit *unit, bfd_vma addr, const char **filename_ptr, - const char **functionname_ptr, + struct funcinfo **function_ptr, unsigned int *linenumber_ptr, unsigned int *discriminator_ptr, struct dwarf2_debug *stash) { - bfd_boolean line_p; bfd_boolean func_p; - struct funcinfo *function; if (unit->error) return FALSE; @@ -2600,16 +2977,15 @@ comp_unit_find_nearest_line (struct comp_unit *unit, } } - function = NULL; - func_p = lookup_address_in_function_table (unit, addr, - &function, functionname_ptr); - if (func_p && (function->tag == DW_TAG_inlined_subroutine)) - stash->inliner_chain = function; - line_p = lookup_address_in_line_info_table (unit->line_table, addr, - filename_ptr, - linenumber_ptr, - discriminator_ptr); - return line_p || func_p; + *function_ptr = NULL; + func_p = lookup_address_in_function_table (unit, addr, function_ptr); + if (func_p && (*function_ptr)->tag == DW_TAG_inlined_subroutine) + stash->inliner_chain = *function_ptr; + + return lookup_address_in_line_info_table (unit->line_table, addr, + filename_ptr, + linenumber_ptr, + discriminator_ptr); } /* Check to see if line info is already decoded in a comp_unit. @@ -2788,7 +3164,7 @@ comp_unit_hash_info (struct dwarf2_debug *stash, static asection * find_debug_info (bfd *abfd, const struct dwarf_debug_section *debug_sections, - asection *after_sec) + asection *after_sec) { asection *msec; const char *look; @@ -2832,12 +3208,36 @@ find_debug_info (bfd *abfd, const struct dwarf_debug_section *debug_sections, return NULL; } +/* Transfer VMAs from object file to separate debug file. */ + +static void +set_debug_vma (bfd *orig_bfd, bfd *debug_bfd) +{ + asection *s, *d; + + for (s = orig_bfd->sections, d = debug_bfd->sections; + s != NULL && d != NULL; + s = s->next, d = d->next) + { + if ((d->flags & SEC_DEBUGGING) != 0) + break; + /* ??? Assumes 1-1 correspondence between sections in the + two files. */ + if (strcmp (s->name, d->name) == 0) + { + d->output_section = s->output_section; + d->output_offset = s->output_offset; + d->vma = s->vma; + } + } +} + /* Unset vmas for adjusted sections in STASH. */ static void unset_sections (struct dwarf2_debug *stash) { - unsigned int i; + int i; struct adjusted_section *p; i = stash->adjusted_section_count; @@ -2846,14 +3246,23 @@ unset_sections (struct dwarf2_debug *stash) p->section->vma = 0; } -/* Set unique VMAs for loadable and DWARF sections in ABFD and save - VMAs in STASH for unset_sections. */ +/* Set VMAs for allocated and .debug_info sections in ORIG_BFD, a + relocatable object file. VMAs are normally all zero in relocatable + object files, so if we want to distinguish locations in sections by + address we need to set VMAs so the sections do not overlap. We + also set VMA on .debug_info so that when we have multiple + .debug_info sections (or the linkonce variant) they also do not + overlap. The multiple .debug_info sections make up a single + logical section. ??? We should probably do the same for other + debug sections. */ static bfd_boolean -place_sections (bfd *abfd, struct dwarf2_debug *stash) +place_sections (bfd *orig_bfd, struct dwarf2_debug *stash) { + bfd *abfd; struct adjusted_section *p; - unsigned int i; + int i; + const char *debug_info_name; if (stash->adjusted_section_count != 0) { @@ -2861,103 +3270,109 @@ place_sections (bfd *abfd, struct dwarf2_debug *stash) p = stash->adjusted_sections; for (; i > 0; i--, p++) p->section->vma = p->adj_vma; + return TRUE; } - else + + debug_info_name = stash->debug_sections[debug_info].uncompressed_name; + i = 0; + abfd = orig_bfd; + while (1) { asection *sect; - bfd_vma last_vma = 0, last_dwarf = 0; - bfd_size_type amt; - const char *debug_info_name; - debug_info_name = stash->debug_sections[debug_info].uncompressed_name; - i = 0; for (sect = abfd->sections; sect != NULL; sect = sect->next) { - bfd_size_type sz; int is_debug_info; - if (sect->vma != 0) + if ((sect->output_section != NULL + && sect->output_section != sect + && (sect->flags & SEC_DEBUGGING) == 0) + || sect->vma != 0) continue; - /* We need to adjust the VMAs of any .debug_info sections. - Skip compressed ones, since no relocations could target - them - they should not appear in object files anyway. */ - if (strcmp (sect->name, debug_info_name) == 0) - is_debug_info = 1; - else if (CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO)) - is_debug_info = 1; - else - is_debug_info = 0; + is_debug_info = (strcmp (sect->name, debug_info_name) == 0 + || CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO)); - if (!is_debug_info && (sect->flags & SEC_LOAD) == 0) - continue; - - sz = sect->rawsize ? sect->rawsize : sect->size; - if (sz == 0) + if (!((sect->flags & SEC_ALLOC) != 0 && abfd == orig_bfd) + && !is_debug_info) continue; i++; } + if (abfd == stash->bfd_ptr) + break; + abfd = stash->bfd_ptr; + } - amt = i * sizeof (struct adjusted_section); - p = (struct adjusted_section *) bfd_alloc (abfd, amt); - if (! p) + if (i <= 1) + stash->adjusted_section_count = -1; + else + { + bfd_vma last_vma = 0, last_dwarf = 0; + bfd_size_type amt = i * sizeof (struct adjusted_section); + + p = (struct adjusted_section *) bfd_malloc (amt); + if (p == NULL) return FALSE; stash->adjusted_sections = p; stash->adjusted_section_count = i; - for (sect = abfd->sections; sect != NULL; sect = sect->next) + abfd = orig_bfd; + while (1) { - bfd_size_type sz; - int is_debug_info; + asection *sect; - if (sect->vma != 0) - continue; + for (sect = abfd->sections; sect != NULL; sect = sect->next) + { + bfd_size_type sz; + int is_debug_info; - /* We need to adjust the VMAs of any .debug_info sections. - Skip compressed ones, since no relocations could target - them - they should not appear in object files anyway. */ - if (strcmp (sect->name, debug_info_name) == 0) - is_debug_info = 1; - else if (CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO)) - is_debug_info = 1; - else - is_debug_info = 0; + if ((sect->output_section != NULL + && sect->output_section != sect + && (sect->flags & SEC_DEBUGGING) == 0) + || sect->vma != 0) + continue; - if (!is_debug_info && (sect->flags & SEC_LOAD) == 0) - continue; + is_debug_info = (strcmp (sect->name, debug_info_name) == 0 + || CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO)); - sz = sect->rawsize ? sect->rawsize : sect->size; - if (sz == 0) - continue; + if (!((sect->flags & SEC_ALLOC) != 0 && abfd == orig_bfd) + && !is_debug_info) + continue; - p->section = sect; - if (is_debug_info) - { - BFD_ASSERT (sect->alignment_power == 0); - sect->vma = last_dwarf; - last_dwarf += sz; - } - else if (last_vma != 0) - { - /* Align the new address to the current section - alignment. */ - last_vma = ((last_vma - + ~((bfd_vma) -1 << sect->alignment_power)) - & ((bfd_vma) -1 << sect->alignment_power)); - sect->vma = last_vma; - last_vma += sect->vma + sz; - } - else - last_vma += sect->vma + sz; + sz = sect->rawsize ? sect->rawsize : sect->size; - p->adj_vma = sect->vma; + if (is_debug_info) + { + BFD_ASSERT (sect->alignment_power == 0); + sect->vma = last_dwarf; + last_dwarf += sz; + } + else + { + /* Align the new address to the current section + alignment. */ + last_vma = ((last_vma + + ~((bfd_vma) -1 << sect->alignment_power)) + & ((bfd_vma) -1 << sect->alignment_power)); + sect->vma = last_vma; + last_vma += sz; + } - p++; + p->section = sect; + p->adj_vma = sect->vma; + p++; + } + if (abfd == stash->bfd_ptr) + break; + abfd = stash->bfd_ptr; } } + if (orig_bfd != stash->bfd_ptr) + set_debug_vma (orig_bfd, stash->bfd_ptr); + return TRUE; } @@ -2976,6 +3391,7 @@ info_hash_lookup_funcinfo (struct info_hash_table *hash_table, { struct funcinfo* each_func; struct funcinfo* best_fit = NULL; + bfd_vma best_fit_len = 0; struct info_list_node *node; struct arange *arange; const char *name = bfd_asymbol_name (sym); @@ -2994,9 +3410,11 @@ info_hash_lookup_funcinfo (struct info_hash_table *hash_table, && addr >= arange->low && addr < arange->high && (!best_fit - || (arange->high - arange->low - < best_fit->arange.high - best_fit->arange.low))) - best_fit = each_func; + || arange->high - arange->low < best_fit_len)) + { + best_fit = each_func; + best_fit_len = arange->high - arange->low; + } } } @@ -3186,6 +3604,56 @@ stash_find_line_fast (struct dwarf2_debug *stash, filename_ptr, linenumber_ptr); } +/* Save current section VMAs. */ + +static bfd_boolean +save_section_vma (const bfd *abfd, struct dwarf2_debug *stash) +{ + asection *s; + unsigned int i; + + if (abfd->section_count == 0) + return TRUE; + stash->sec_vma = bfd_malloc (sizeof (*stash->sec_vma) * abfd->section_count); + if (stash->sec_vma == NULL) + return FALSE; + for (i = 0, s = abfd->sections; i < abfd->section_count; i++, s = s->next) + { + if (s->output_section != NULL) + stash->sec_vma[i] = s->output_section->vma + s->output_offset; + else + stash->sec_vma[i] = s->vma; + } + return TRUE; +} + +/* Compare current section VMAs against those at the time the stash + was created. If find_nearest_line is used in linker warnings or + errors early in the link process, the debug info stash will be + invalid for later calls. This is because we relocate debug info + sections, so the stashed section contents depend on symbol values, + which in turn depend on section VMAs. */ + +static bfd_boolean +section_vma_same (const bfd *abfd, const struct dwarf2_debug *stash) +{ + asection *s; + unsigned int i; + + for (i = 0, s = abfd->sections; i < abfd->section_count; i++, s = s->next) + { + bfd_vma vma; + + if (s->output_section != NULL) + vma = s->output_section->vma + s->output_offset; + else + vma = s->vma; + if (vma != stash->sec_vma[i]) + return FALSE; + } + return TRUE; +} + /* Read debug information from DEBUG_BFD when DEBUG_BFD is specified. If DEBUG_BFD is not specified, we read debug information from ABFD or its gnu_debuglink. The results will be stored in PINFO. @@ -3193,9 +3661,10 @@ stash_find_line_fast (struct dwarf2_debug *stash, bfd_boolean _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, - const struct dwarf_debug_section *debug_sections, - asymbol **symbols, - void **pinfo) + const struct dwarf_debug_section *debug_sections, + asymbol **symbols, + void **pinfo, + bfd_boolean do_place) { bfd_size_type amt = sizeof (struct dwarf2_debug); bfd_size_type total_size; @@ -3203,13 +3672,22 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo; if (stash != NULL) - return TRUE; - - stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt); - if (! stash) - return FALSE; + { + if (section_vma_same (abfd, stash)) + return TRUE; + _bfd_dwarf2_cleanup_debug_info (abfd, pinfo); + memset (stash, 0, amt); + } + else + { + stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt); + if (! stash) + return FALSE; + } stash->debug_sections = debug_sections; stash->syms = symbols; + if (!save_section_vma (abfd, stash)) + return FALSE; *pinfo = stash; @@ -3231,7 +3709,8 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL || ! bfd_check_format (debug_bfd, bfd_object) || (msec = find_debug_info (debug_bfd, - debug_sections, NULL)) == NULL) + debug_sections, NULL)) == NULL + || !bfd_generic_link_read_symbols (debug_bfd)) { if (debug_bfd) bfd_close (debug_bfd); @@ -3239,10 +3718,17 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, free (debug_filename); return FALSE; } + + symbols = bfd_get_outsymbols (debug_bfd); + stash->syms = symbols; stash->close_on_cleanup = TRUE; } stash->bfd_ptr = debug_bfd; + if (do_place + && !place_sections (abfd, stash)) + return FALSE; + /* There can be more than one DWARF2 info section in a BFD these days. First handle the easy case when there's only one. If there's more than one, try case two: none of the sections is @@ -3302,6 +3788,57 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, return TRUE; } +/* Scan the debug information in PINFO looking for a DW_TAG_subprogram + abbrev with a DW_AT_low_pc attached to it. Then lookup that same + symbol in SYMBOLS and return the difference between the low_pc and + the symbol's address. Returns 0 if no suitable symbol could be found. */ + +bfd_signed_vma +_bfd_dwarf2_find_symbol_bias (asymbol ** symbols, void ** pinfo) +{ + struct dwarf2_debug *stash; + struct comp_unit * unit; + + stash = (struct dwarf2_debug *) *pinfo; + + if (stash == NULL) + return 0; + + for (unit = stash->all_comp_units; unit; unit = unit->next_unit) + { + struct funcinfo * func; + + if (unit->function_table == NULL) + { + if (unit->line_table == NULL) + unit->line_table = decode_line_info (unit, stash); + if (unit->line_table != NULL) + scan_unit_for_symbols (unit); + } + + for (func = unit->function_table; func != NULL; func = func->prev_func) + if (func->name && func->arange.low) + { + asymbol ** psym; + + /* FIXME: Do we need to scan the aranges looking for the lowest pc value ? */ + + for (psym = symbols; * psym != NULL; psym++) + { + asymbol * sym = * psym; + + if (sym->flags & BSF_FUNCTION + && sym->section != NULL + && strcmp (sym->name, func->name) == 0) + return ((bfd_signed_vma) func->arange.low) - + ((bfd_signed_vma) (sym->value + sym->section->vma)); + } + } + } + + return 0; +} + /* Find the source code location of SYMBOL. If SYMBOL is NULL then find the nearest source code location corresponding to the address SECTION + OFFSET. @@ -3314,19 +3851,19 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, field and in the abbreviation offset, or zero to indicate that the default value should be used. */ -static bfd_boolean -find_line (bfd *abfd, - const struct dwarf_debug_section *debug_sections, - asection *section, - bfd_vma offset, - asymbol *symbol, - asymbol **symbols, - const char **filename_ptr, - const char **functionname_ptr, - unsigned int *linenumber_ptr, - unsigned int *discriminator_ptr, - unsigned int addr_size, - void **pinfo) +bfd_boolean +_bfd_dwarf2_find_nearest_line (bfd *abfd, + asymbol **symbols, + asymbol *symbol, + asection *section, + bfd_vma offset, + const char **filename_ptr, + const char **functionname_ptr, + unsigned int *linenumber_ptr, + unsigned int *discriminator_ptr, + const struct dwarf_debug_section *debug_sections, + unsigned int addr_size, + void **pinfo) { /* Read each compilation unit from the section .debug_info, and check to see if it contains the address we are searching for. If yes, @@ -3340,7 +3877,8 @@ find_line (bfd *abfd, /* What address are we looking for? */ bfd_vma addr; struct comp_unit* each; - bfd_vma found = FALSE; + struct funcinfo *function = NULL; + bfd_boolean found = FALSE; bfd_boolean do_line; *filename_ptr = NULL; @@ -3350,35 +3888,25 @@ find_line (bfd *abfd, if (discriminator_ptr) *discriminator_ptr = 0; - if (! _bfd_dwarf2_slurp_debug_info (abfd, NULL, - debug_sections, symbols, pinfo)) + if (! _bfd_dwarf2_slurp_debug_info (abfd, NULL, debug_sections, + symbols, pinfo, + (abfd->flags & (EXEC_P | DYNAMIC)) == 0)) return FALSE; stash = (struct dwarf2_debug *) *pinfo; - /* In a relocatable file, 2 functions may have the same address. - We change the section vma so that they won't overlap. */ - if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) - { - if (! place_sections (abfd, stash)) - return FALSE; - } - - do_line = (section == NULL - && offset == 0 - && functionname_ptr == NULL - && symbol != NULL); + do_line = symbol != NULL; if (do_line) { - addr = symbol->value; + BFD_ASSERT (section == NULL && offset == 0 && functionname_ptr == NULL); section = bfd_get_section (symbol); + addr = symbol->value; } - else if (section != NULL - && functionname_ptr != NULL - && symbol == NULL) - addr = offset; else - abort (); + { + BFD_ASSERT (section != NULL && functionname_ptr != NULL); + addr = offset; + } if (section->output_section) addr += section->output_section->vma + section->output_offset; @@ -3430,18 +3958,56 @@ find_line (bfd *abfd, } else { + bfd_vma min_range = (bfd_vma) -1; + const char * local_filename = NULL; + struct funcinfo *local_function = NULL; + unsigned int local_linenumber = 0; + unsigned int local_discriminator = 0; + for (each = stash->all_comp_units; each; each = each->next_unit) { + bfd_vma range = (bfd_vma) -1; + found = ((each->arange.high == 0 || comp_unit_contains_address (each, addr)) - && comp_unit_find_nearest_line (each, addr, - filename_ptr, - functionname_ptr, - linenumber_ptr, - discriminator_ptr, - stash)); + && (range = comp_unit_find_nearest_line (each, addr, + & local_filename, + & local_function, + & local_linenumber, + & local_discriminator, + stash)) != 0); if (found) - goto done; + { + /* PRs 15935 15994: Bogus debug information may have provided us + with an erroneous match. We attempt to counter this by + selecting the match that has the smallest address range + associated with it. (We are assuming that corrupt debug info + will tend to result in extra large address ranges rather than + extra small ranges). + + This does mean that we scan through all of the CUs associated + with the bfd each time this function is called. But this does + have the benefit of producing consistent results every time the + function is called. */ + if (range <= min_range) + { + if (filename_ptr && local_filename) + * filename_ptr = local_filename; + if (local_function) + function = local_function; + if (discriminator_ptr && local_discriminator) + * discriminator_ptr = local_discriminator; + if (local_linenumber) + * linenumber_ptr = local_linenumber; + min_range = range; + } + } + } + + if (* linenumber_ptr) + { + found = TRUE; + goto done; } } @@ -3459,13 +4025,13 @@ find_line (bfd *abfd, unsigned int offset_size = addr_size; bfd_byte *info_ptr_unit = stash->info_ptr; - length = read_4_bytes (stash->bfd_ptr, stash->info_ptr); + length = read_4_bytes (stash->bfd_ptr, stash->info_ptr, stash->info_ptr_end); /* A 0xffffff length is the DWARF3 way of indicating we use 64-bit offsets, instead of 32-bit offsets. */ if (length == 0xffffffff) { offset_size = 8; - length = read_8_bytes (stash->bfd_ptr, stash->info_ptr + 4); + length = read_8_bytes (stash->bfd_ptr, stash->info_ptr + 4, stash->info_ptr_end); stash->info_ptr += 12; } /* A zero length is the IRIX way of indicating 64-bit offsets, @@ -3474,7 +4040,7 @@ find_line (bfd *abfd, else if (length == 0) { offset_size = 8; - length = read_4_bytes (stash->bfd_ptr, stash->info_ptr + 4); + length = read_4_bytes (stash->bfd_ptr, stash->info_ptr + 4, stash->info_ptr_end); stash->info_ptr += 8; } /* In the absence of the hints above, we assume 32-bit DWARF2 @@ -3496,13 +4062,25 @@ find_line (bfd *abfd, if (length > 0) { + bfd_byte * new_ptr; + each = parse_comp_unit (stash, length, info_ptr_unit, offset_size); if (!each) /* The dwarf information is damaged, don't trust it any more. */ break; - stash->info_ptr += length; + + new_ptr = stash->info_ptr + length; + /* PR 17512: file: 1500698c. */ + if (new_ptr < stash->info_ptr) + { + /* A corrupt length value - do not trust the info any more. */ + found = FALSE; + break; + } + else + stash->info_ptr = new_ptr; if (stash->all_comp_units) stash->all_comp_units->prev_unit = each; @@ -3530,16 +4108,16 @@ find_line (bfd *abfd, || comp_unit_contains_address (each, addr)) && comp_unit_find_nearest_line (each, addr, filename_ptr, - functionname_ptr, + &function, linenumber_ptr, discriminator_ptr, - stash)); + stash) != 0); if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr) == stash->sec->size) { stash->sec = find_debug_info (stash->bfd_ptr, debug_sections, - stash->sec); + stash->sec); stash->sec_info_ptr = stash->info_ptr; } @@ -3549,51 +4127,25 @@ find_line (bfd *abfd, } done: + if (function) + { + if (!function->is_linkage + && _bfd_elf_find_function (abfd, symbols, section, offset, + *filename_ptr ? NULL : filename_ptr, + functionname_ptr)) + { + function->name = *functionname_ptr; + function->is_linkage = TRUE; + } + else + *functionname_ptr = function->name; + } if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) unset_sections (stash); return found; } -/* The DWARF2 version of find_nearest_line. - Return TRUE if the line is found without error. */ - -bfd_boolean -_bfd_dwarf2_find_nearest_line (bfd *abfd, - const struct dwarf_debug_section *debug_sections, - asection *section, - asymbol **symbols, - bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr, - unsigned int *linenumber_ptr, - unsigned int *discriminator_ptr, - unsigned int addr_size, - void **pinfo) -{ - return find_line (abfd, debug_sections, section, offset, NULL, symbols, - filename_ptr, functionname_ptr, linenumber_ptr, - discriminator_ptr, addr_size, pinfo); -} - -/* The DWARF2 version of find_line. - Return TRUE if the line is found without error. */ - -bfd_boolean -_bfd_dwarf2_find_line (bfd *abfd, - asymbol **symbols, - asymbol *symbol, - const char **filename_ptr, - unsigned int *linenumber_ptr, - unsigned int *discriminator_ptr, - unsigned int addr_size, - void **pinfo) -{ - return find_line (abfd, dwarf_debug_sections, NULL, 0, symbol, symbols, - filename_ptr, NULL, linenumber_ptr, discriminator_ptr, - addr_size, pinfo); -} - bfd_boolean _bfd_dwarf2_find_inliner_info (bfd *abfd ATTRIBUTE_UNUSED, const char **filename_ptr, @@ -3694,4 +4246,120 @@ _bfd_dwarf2_cleanup_debug_info (bfd *abfd, void **pinfo) free (stash->info_ptr_memory); if (stash->close_on_cleanup) bfd_close (stash->bfd_ptr); + if (stash->alt_dwarf_str_buffer) + free (stash->alt_dwarf_str_buffer); + if (stash->alt_dwarf_info_buffer) + free (stash->alt_dwarf_info_buffer); + if (stash->sec_vma) + free (stash->sec_vma); + if (stash->adjusted_sections) + free (stash->adjusted_sections); + if (stash->alt_bfd_ptr) + bfd_close (stash->alt_bfd_ptr); +} + +/* Find the function to a particular section and offset, + for error reporting. */ + +bfd_boolean +_bfd_elf_find_function (bfd *abfd, + asymbol **symbols, + asection *section, + bfd_vma offset, + const char **filename_ptr, + const char **functionname_ptr) +{ + struct elf_find_function_cache + { + asection *last_section; + asymbol *func; + const char *filename; + bfd_size_type func_size; + } *cache; + + if (symbols == NULL) + return FALSE; + + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) + return FALSE; + + cache = elf_tdata (abfd)->elf_find_function_cache; + if (cache == NULL) + { + cache = bfd_zalloc (abfd, sizeof (*cache)); + elf_tdata (abfd)->elf_find_function_cache = cache; + if (cache == NULL) + return FALSE; + } + if (cache->last_section != section + || cache->func == NULL + || offset < cache->func->value + || offset >= cache->func->value + cache->func_size) + { + asymbol *file; + bfd_vma low_func; + asymbol **p; + /* ??? Given multiple file symbols, it is impossible to reliably + choose the right file name for global symbols. File symbols are + local symbols, and thus all file symbols must sort before any + global symbols. The ELF spec may be interpreted to say that a + file symbol must sort before other local symbols, but currently + ld -r doesn't do this. So, for ld -r output, it is possible to + make a better choice of file name for local symbols by ignoring + file symbols appearing after a given local symbol. */ + enum { nothing_seen, symbol_seen, file_after_symbol_seen } state; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + + file = NULL; + low_func = 0; + state = nothing_seen; + cache->filename = NULL; + cache->func = NULL; + cache->func_size = 0; + cache->last_section = section; + + for (p = symbols; *p != NULL; p++) + { + asymbol *sym = *p; + bfd_vma code_off; + bfd_size_type size; + + if ((sym->flags & BSF_FILE) != 0) + { + file = sym; + if (state == symbol_seen) + state = file_after_symbol_seen; + continue; + } + + size = bed->maybe_function_sym (sym, section, &code_off); + if (size != 0 + && code_off <= offset + && (code_off > low_func + || (code_off == low_func + && size > cache->func_size))) + { + cache->func = sym; + cache->func_size = size; + cache->filename = NULL; + low_func = code_off; + if (file != NULL + && ((sym->flags & BSF_LOCAL) != 0 + || state != file_after_symbol_seen)) + cache->filename = bfd_asymbol_name (file); + } + if (state == nothing_seen) + state = symbol_seen; + } + } + + if (cache->func == NULL) + return FALSE; + + if (filename_ptr) + *filename_ptr = cache->filename; + if (functionname_ptr) + *functionname_ptr = bfd_asymbol_name (cache->func); + + return TRUE; } diff --git a/contrib/gdb-7/bfd/elf-attrs.c b/contrib/gdb-7/bfd/elf-attrs.c index 9a6ff6f910..ceafd44d45 100644 --- a/contrib/gdb-7/bfd/elf-attrs.c +++ b/contrib/gdb-7/bfd/elf-attrs.c @@ -1,6 +1,5 @@ /* ELF attributes support (based on ARM EABI attributes). - Copyright 2005, 2006, 2007, 2009, 2010, 2012 - Free Software Foundation, Inc. + Copyright (C) 2005-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -55,7 +54,7 @@ is_default_attr (obj_attribute *attr) /* Return the size of a single attribute. */ static bfd_vma -obj_attr_size (int tag, obj_attribute *attr) +obj_attr_size (unsigned int tag, obj_attribute *attr) { bfd_vma size; @@ -144,7 +143,7 @@ write_uleb128 (bfd_byte *p, unsigned int val) /* Write attribute ATTR to butter P, and return a pointer to the following byte. */ static bfd_byte * -write_obj_attribute (bfd_byte *p, int tag, obj_attribute *attr) +write_obj_attribute (bfd_byte *p, unsigned int tag, obj_attribute *attr) { /* Suppress default entries. */ if (is_default_attr (attr)) @@ -190,7 +189,7 @@ vendor_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size, attr = elf_known_obj_attributes (abfd)[vendor]; for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) { - int tag = i; + unsigned int tag = i; if (get_elf_backend_data (abfd)->obj_attrs_order) tag = get_elf_backend_data (abfd)->obj_attrs_order (i); p = write_obj_attribute (p, tag, &attr[tag]); @@ -228,7 +227,7 @@ bfd_elf_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size) /* Allocate/find an object attribute. */ static obj_attribute * -elf_new_obj_attr (bfd *abfd, int vendor, int tag) +elf_new_obj_attr (bfd *abfd, int vendor, unsigned int tag) { obj_attribute *attr; obj_attribute_list *list; @@ -266,7 +265,7 @@ elf_new_obj_attr (bfd *abfd, int vendor, int tag) /* Return the value of an integer object attribute. */ int -bfd_elf_get_obj_attr_int (bfd *abfd, int vendor, int tag) +bfd_elf_get_obj_attr_int (bfd *abfd, int vendor, unsigned int tag) { obj_attribute_list *p; @@ -292,7 +291,7 @@ bfd_elf_get_obj_attr_int (bfd *abfd, int vendor, int tag) /* Add an integer object attribute. */ void -bfd_elf_add_obj_attr_int (bfd *abfd, int vendor, int tag, unsigned int i) +bfd_elf_add_obj_attr_int (bfd *abfd, int vendor, unsigned int tag, unsigned int i) { obj_attribute *attr; @@ -315,7 +314,7 @@ _bfd_elf_attr_strdup (bfd *abfd, const char * s) /* Add a string object attribute. */ void -bfd_elf_add_obj_attr_string (bfd *abfd, int vendor, int tag, const char *s) +bfd_elf_add_obj_attr_string (bfd *abfd, int vendor, unsigned int tag, const char *s) { obj_attribute *attr; @@ -326,7 +325,8 @@ bfd_elf_add_obj_attr_string (bfd *abfd, int vendor, int tag, const char *s) /* Add a int+string object attribute. */ void -bfd_elf_add_obj_attr_int_string (bfd *abfd, int vendor, int tag, +bfd_elf_add_obj_attr_int_string (bfd *abfd, int vendor, + unsigned int tag, unsigned int i, const char *s) { obj_attribute *attr; @@ -395,7 +395,7 @@ _bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd) /* Determine whether a GNU object attribute tag takes an integer, a string or both. */ static int -gnu_obj_attrs_arg_type (int tag) +gnu_obj_attrs_arg_type (unsigned int tag) { /* Except for Tag_compatibility, for GNU attributes we follow the same rule ARM ones > 32 follow: odd-numbered tags take strings @@ -410,7 +410,7 @@ gnu_obj_attrs_arg_type (int tag) /* Determine what arguments an attribute tag takes. */ int -_bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, int tag) +_bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, unsigned int tag) { switch (vendor) { @@ -431,9 +431,13 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) { bfd_byte *contents; bfd_byte *p; + bfd_byte *p_end; bfd_vma len; const char *std_sec; + /* PR 17512: file: 2844a11d. */ + if (hdr->sh_size == 0) + return; contents = (bfd_byte *) bfd_malloc (hdr->sh_size); if (!contents) return; @@ -444,23 +448,31 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) return; } p = contents; + p_end = p + hdr->sh_size; std_sec = get_elf_backend_data (abfd)->obj_attrs_vendor; + if (*(p++) == 'A') { len = hdr->sh_size - 1; - while (len > 0) + + while (len > 0 && p < p_end - 4) { - int namelen; + unsigned namelen; bfd_vma section_len; int vendor; section_len = bfd_get_32 (abfd, p); p += 4; + if (section_len == 0) + break; if (section_len > len) section_len = len; len -= section_len; - namelen = strlen ((char *) p) + 1; - section_len -= namelen + 4; + section_len -= 4; + namelen = strnlen ((char *) p, section_len) + 1; + if (namelen == 0 || namelen >= section_len) + break; + section_len -= namelen; if (std_sec && strcmp ((char *) p, std_sec) == 0) vendor = OBJ_ATTR_PROC; else if (strcmp ((char *) p, "gnu") == 0) @@ -473,23 +485,31 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) } p += namelen; - while (section_len > 0) + while (section_len > 0 && p < p_end) { - int tag; + unsigned int tag; unsigned int n; unsigned int val; bfd_vma subsection_len; bfd_byte *end; - tag = read_unsigned_leb128 (abfd, p, &n); + tag = safe_read_leb128 (abfd, p, &n, FALSE, p_end); p += n; - subsection_len = bfd_get_32 (abfd, p); + if (p < p_end - 4) + subsection_len = bfd_get_32 (abfd, p); + else + subsection_len = 0; p += 4; + if (subsection_len == 0) + break; if (subsection_len > section_len) subsection_len = section_len; section_len -= subsection_len; subsection_len -= n + 4; end = p + subsection_len; + /* PR 17512: file: 0e8c0c90. */ + if (end > p_end) + end = p_end; switch (tag) { case Tag_File: @@ -497,25 +517,25 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) { int type; - tag = read_unsigned_leb128 (abfd, p, &n); + tag = safe_read_leb128 (abfd, p, &n, FALSE, end); p += n; type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); switch (type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL)) { case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL: - val = read_unsigned_leb128 (abfd, p, &n); + val = safe_read_leb128 (abfd, p, &n, FALSE, end); p += n; bfd_elf_add_obj_attr_int_string (abfd, vendor, tag, - val, (char *)p); + val, (char *) p); p += strlen ((char *)p) + 1; break; case ATTR_TYPE_FLAG_STR_VAL: bfd_elf_add_obj_attr_string (abfd, vendor, tag, - (char *)p); + (char *) p); p += strlen ((char *)p) + 1; break; case ATTR_TYPE_FLAG_INT_VAL: - val = read_unsigned_leb128 (abfd, p, &n); + val = safe_read_leb128 (abfd, p, &n, FALSE, end); p += n; bfd_elf_add_obj_attr_int (abfd, vendor, tag, val); break; @@ -647,7 +667,7 @@ _bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd) for (; in_list || out_list; ) { bfd *err_bfd = NULL; - int err_tag = 0; + unsigned int err_tag = 0; /* The tags for each list are in numerical order. */ /* If the tags are equal, then merge. */ diff --git a/contrib/gdb-7/bfd/elf-bfd.h b/contrib/gdb-7/bfd/elf-bfd.h index 3f068bb95e..e08b2d6ed4 100644 --- a/contrib/gdb-7/bfd/elf-bfd.h +++ b/contrib/gdb-7/bfd/elf-bfd.h @@ -1,5 +1,5 @@ /* BFD back-end data structures for ELF files. - Copyright 1992-2013 Free Software Foundation, Inc. + Copyright (C) 1992-2015 Free Software Foundation, Inc. Written by Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -27,6 +27,10 @@ #include "elf/internal.h" #include "bfdlink.h" +#ifdef __cplusplus +extern "C" { +#endif + /* The number of entries in a section is its size divided by the size of a single entry. This is normally only applicable to reloc and symbol table sections. @@ -196,6 +200,9 @@ struct elf_link_hash_entry unsigned int pointer_equality_needed : 1; /* Symbol is a unique global symbol. */ unsigned int unique_global : 1; + /* Symbol is defined by a shared library with non-default visibility + in a read/write section. */ + unsigned int protected_def : 1; /* String table index in .dynstr if this is a dynamic symbol. */ unsigned long dynstr_index; @@ -239,7 +246,8 @@ struct elf_link_hash_entry _bfd_elf_symbol_refs_local_p (H, INFO, 1) /* Common symbols that are turned into definitions don't have the - DEF_REGULAR flag set, so they might appear to be undefined. */ + DEF_REGULAR flag set, so they might appear to be undefined. + Symbols defined in linker scripts also don't have DEF_REGULAR set. */ #define ELF_COMMON_DEF_P(H) \ (!(H)->def_regular \ && !(H)->def_dynamic \ @@ -280,7 +288,9 @@ struct eh_cie_fde If REMOVED == 0, this is the CIE that we have chosen to use for the output FDE. The CIE's REMOVED field is also 0, but the CIE - might belong to a different .eh_frame input section from the FDE. */ + might belong to a different .eh_frame input section from the FDE. + + May be NULL to signify that the FDE should be discarded. */ struct eh_cie_fde *cie_inf; struct eh_cie_fde *next_for_section; } fde; @@ -372,25 +382,47 @@ struct eh_frame_sec_info struct eh_frame_array_ent { bfd_vma initial_loc; + bfd_size_type range; bfd_vma fde; }; struct htab; -struct eh_frame_hdr_info +#define DWARF2_EH_HDR 1 +#define COMPACT_EH_HDR 2 + +/* Endian-neutral code indicating that a function cannot be unwound. */ +#define COMPACT_EH_CANT_UNWIND_OPCODE 0x015d5d01 + +struct dwarf_eh_frame_hdr_info { struct htab *cies; - asection *hdr_sec; - unsigned int fde_count, array_count; - struct eh_frame_array_ent *array; - /* TRUE if we should try to merge CIEs between input sections. */ - bfd_boolean merge_cies; - /* TRUE if all .eh_frames have been parsd. */ - bfd_boolean parsed_eh_frames; + unsigned int fde_count; /* TRUE if .eh_frame_hdr should contain the sorted search table. We build it if we successfully read all .eh_frame input sections and recognize them. */ bfd_boolean table; + struct eh_frame_array_ent *array; +}; + +struct compact_eh_frame_hdr_info +{ + unsigned int allocated_entries; + /* eh_frame_entry fragments. */ + asection **entries; +}; + +struct eh_frame_hdr_info +{ + asection *hdr_sec; + unsigned int array_count; + bfd_boolean frame_hdr_is_compact; + union + { + struct dwarf_eh_frame_hdr_info dwarf; + struct compact_eh_frame_hdr_info compact; + } + u; }; /* Enum used to identify target specific extensions to the elf_obj_tdata @@ -419,7 +451,9 @@ enum elf_target_id MICROBLAZE_ELF_DATA, MIPS_ELF_DATA, MN10300_ELF_DATA, + NDS32_ELF_DATA, NIOS2_ELF_DATA, + OR1K_ELF_DATA, PPC32_ELF_DATA, PPC64_ELF_DATA, S390_ELF_DATA, @@ -435,6 +469,13 @@ enum elf_target_id GENERIC_ELF_DATA }; +struct elf_sym_strtab +{ + Elf_Internal_Sym sym; + unsigned long dest_index; + unsigned long destshndx_index; +}; + /* ELF linker hash table. */ struct elf_link_hash_table @@ -478,6 +519,17 @@ struct elf_link_hash_table section. */ struct elf_strtab_hash *dynstr; + /* The number of symbol strings found in the link which must be put + into the .strtab section. */ + bfd_size_type strtabcount; + + /* The array size of the symbol string table, which becomes the + .strtab section. */ + bfd_size_type strtabsize; + + /* The array of strings, which becomes the .strtab section. */ + struct elf_sym_strtab *strtab; + /* The number of buckets in the hash table in the .hash section. This is based on the number of dynamic symbols. */ bfd_size_type bucketcount; @@ -641,7 +693,8 @@ enum elf_reloc_type_class { reloc_class_normal, reloc_class_relative, reloc_class_plt, - reloc_class_copy + reloc_class_copy, + reloc_class_ifunc }; struct elf_reloc_cookie @@ -880,12 +933,12 @@ struct elf_backend_data bfd_boolean (*check_directives) (bfd *abfd, struct bfd_link_info *info); - /* The AS_NEEDED_CLEANUP function is called once per --as-needed - input file that was not needed by the add_symbols phase of the - ELF backend linker. The function must undo any target specific - changes in the symbol hash table. */ - bfd_boolean (*as_needed_cleanup) - (bfd *abfd, struct bfd_link_info *info); + /* The NOTICE_AS_NEEDED function is called as the linker is about to + handle an as-needed lib (ACT = notice_as_needed), and after the + linker has decided to keep the lib (ACT = notice_needed) or when + the lib is not needed (ACT = notice_not_needed). */ + bfd_boolean (*notice_as_needed) + (bfd *abfd, struct bfd_link_info *info, enum notice_asneeded_action act); /* The ADJUST_DYNAMIC_SYMBOL function is called by the ELF backend linker for every symbol which is defined by a dynamic object and @@ -1107,6 +1160,11 @@ struct elf_backend_data unsigned int (*elf_backend_count_relocs) (struct bfd_link_info *, asection *); + /* Say whether to sort relocs output by ld -r and ld --emit-relocs, + by r_offset. If NULL, default to true. */ + bfd_boolean (*sort_relocs_p) + (asection *); + /* This function, if defined, is called when an NT_PRSTATUS note is found in a core file. */ bfd_boolean (*elf_backend_grok_prstatus) @@ -1128,7 +1186,7 @@ struct elf_backend_data /* This function returns class of a reloc type. */ enum elf_reloc_type_class (*elf_backend_reloc_type_class) - (const Elf_Internal_Rela *); + (const struct bfd_link_info *, const asection *, const Elf_Internal_Rela *); /* This function, if defined, removes information about discarded functions from other sections which mention them. */ @@ -1189,9 +1247,9 @@ struct elf_backend_data /* This function implements `bfd_elf_bfd_from_remote_memory'; see elf.c, elfcode.h. */ bfd *(*elf_backend_bfd_from_remote_memory) - (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, - int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, - bfd_size_type len)); + (bfd *templ, bfd_vma ehdr_vma, bfd_size_type size, bfd_vma *loadbasep, + int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, + bfd_size_type len)); /* This function is used by `_bfd_elf_get_synthetic_symtab'; see elf.c. */ @@ -1207,19 +1265,10 @@ struct elf_backend_data asection *(*common_section) (asection *); /* Return TRUE if we can merge 2 definitions. */ - bfd_boolean (*merge_symbol) (struct bfd_link_info *, - struct elf_link_hash_entry **, - struct elf_link_hash_entry *, - Elf_Internal_Sym *, asection **, - bfd_vma *, unsigned int *, - bfd_boolean *, bfd_boolean *, - bfd_boolean *, bfd_boolean *, - bfd_boolean *, bfd_boolean *, - bfd_boolean *, bfd_boolean *, - bfd *, asection **, - bfd_boolean *, bfd_boolean *, - bfd_boolean *, bfd_boolean *, - bfd *, asection **); + bfd_boolean (*merge_symbol) (struct elf_link_hash_entry *, + const Elf_Internal_Sym *, asection **, + bfd_boolean, bfd_boolean, + bfd *, const asection *); /* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ bfd_boolean (*elf_hash_symbol) (struct elf_link_hash_entry *); @@ -1233,6 +1282,9 @@ struct elf_backend_data bfd_size_type (*maybe_function_sym) (const asymbol *sym, asection *sec, bfd_vma *code_off); + /* Return the section which RELOC_SEC applies to. */ + asection *(*get_reloc_section) (asection *reloc_sec); + /* Used to handle bad SHF_LINK_ORDER input. */ bfd_error_handler_type link_order_error_handler; @@ -1282,6 +1334,12 @@ struct elf_backend_data or give an error and return FALSE. */ bfd_boolean (*obj_attrs_handle_unknown) (bfd *, int); + /* Encoding used for compact EH tables. */ + int (*compact_eh_encoding) (struct bfd_link_info *); + + /* Opcode representing no unwind. */ + int (*cant_unwind_opcode) (struct bfd_link_info *); + /* This is non-zero if static TLS segments require a special alignment. */ unsigned static_tls_alignment; @@ -1349,6 +1407,15 @@ struct elf_backend_data other file in the link needs to have a .note.GNU-stack section for a PT_GNU_STACK segment to be created. */ unsigned default_execstack : 1; + + /* True if elf_section_data(sec)->this_hdr.contents is sec->rawsize + in length rather than sec->size in length, if sec->rawsize is + non-zero and smaller than sec->size. */ + unsigned caches_rawsize : 1; + + /* Address of protected data defined in the shared library may be + external, i.e., due to copy relocation. */ + unsigned extern_protected_data : 1; }; /* Information about reloc sections associated with a bfd_elf_section_data @@ -1427,6 +1494,9 @@ struct bfd_elf_section_data field acts as a chain pointer. */ struct eh_cie_fde *fde_list; + /* Link from a text section to its .eh_frame_entry section. */ + asection *eh_frame_entry; + /* A pointer used for various section optimizations. */ void *sec_info; }; @@ -1440,6 +1510,7 @@ struct bfd_elf_section_data #define elf_next_in_group(sec) (elf_section_data(sec)->next_in_group) #define elf_fde_list(sec) (elf_section_data(sec)->fde_list) #define elf_sec_group(sec) (elf_section_data(sec)->sec_group) +#define elf_section_eh_frame_entry(sec) (elf_section_data(sec)->eh_frame_entry) #define xvec_get_elf_backend_data(xvec) \ ((const struct elf_backend_data *) (xvec)->backend_data) @@ -1478,7 +1549,7 @@ typedef struct obj_attribute typedef struct obj_attribute_list { struct obj_attribute_list *next; - int tag; + unsigned int tag; obj_attribute attr; } obj_attribute_list; @@ -1510,13 +1581,6 @@ struct sdt_note bfd_byte data[1]; }; -/* NT_GNU_BUILD_ID note type info for input BFDs. */ -struct elf_build_id -{ - size_t size; - bfd_byte data[1]; -}; - /* tdata information grabbed from an elf core file. */ struct core_elf_obj_tdata { @@ -1651,9 +1715,6 @@ struct elf_obj_tdata obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES]; obj_attribute_list *other_obj_attributes[2]; - /* NT_GNU_BUILD_ID note type. */ - struct elf_build_id *build_id; - /* Linked-list containing information about every Systemtap section found in the object file. Each section corresponds to one entry in the list. */ @@ -1774,6 +1835,8 @@ extern bfd_boolean _bfd_elf_copy_private_bfd_data (bfd *, bfd *); extern bfd_boolean _bfd_elf_print_private_bfd_data (bfd *, void *); +const char * _bfd_elf_get_symbol_version_string + (bfd *, asymbol *, bfd_boolean *); extern void bfd_elf_print_symbol (bfd *, void *, asymbol *, bfd_print_symbol_type); @@ -1786,7 +1849,8 @@ extern bfd_boolean _bfd_elf_can_make_relative (bfd *input_bfd, struct bfd_link_info *info, asection *eh_frame_section); extern enum elf_reloc_type_class _bfd_elf_reloc_type_class - (const Elf_Internal_Rela *); + (const struct bfd_link_info *, const asection *, + const Elf_Internal_Rela *); extern bfd_vma _bfd_elf_rela_local_sym (bfd *, Elf_Internal_Sym *, asection **, Elf_Internal_Rela *); extern bfd_vma _bfd_elf_rel_local_sym @@ -1816,7 +1880,7 @@ extern struct bfd_hash_entry *_bfd_elf_link_hash_newfunc extern struct bfd_link_hash_table *_bfd_elf_link_hash_table_create (bfd *); extern void _bfd_elf_link_hash_table_free - (struct bfd_link_hash_table *); + (bfd *); extern void _bfd_elf_link_hash_copy_indirect (struct bfd_link_info *, struct elf_link_hash_entry *, struct elf_link_hash_entry *); @@ -1899,28 +1963,20 @@ extern alent *_bfd_elf_get_lineno extern bfd_boolean _bfd_elf_set_arch_mach (bfd *, enum bfd_architecture, unsigned long); extern bfd_boolean _bfd_elf_find_nearest_line - (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, - unsigned int *); -extern bfd_boolean _bfd_elf_find_nearest_line_discriminator - (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, - unsigned int *, unsigned int *); + (bfd *, asymbol **, asection *, bfd_vma, + const char **, const char **, unsigned int *, unsigned int *); extern bfd_boolean _bfd_elf_find_line (bfd *, asymbol **, asymbol *, const char **, unsigned int *); -extern bfd_boolean _bfd_elf_find_line_discriminator - (bfd *, asymbol **, asymbol *, const char **, unsigned int *, unsigned int *); -#define _bfd_generic_find_line _bfd_elf_find_line -#define _bfd_generic_find_nearest_line_discriminator \ - _bfd_elf_find_nearest_line_discriminator extern bfd_boolean _bfd_elf_find_inliner_info (bfd *, const char **, const char **, unsigned int *); +extern bfd_boolean _bfd_elf_find_function + (bfd *, asymbol **, asection *, bfd_vma, const char **, const char **); #define _bfd_elf_read_minisymbols _bfd_generic_read_minisymbols #define _bfd_elf_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol extern int _bfd_elf_sizeof_headers (bfd *, struct bfd_link_info *); extern bfd_boolean _bfd_elf_new_section_hook (bfd *, asection *); -extern bfd_boolean _bfd_elf_init_reloc_shdr - (bfd *, struct bfd_elf_section_reloc_data *, asection *, bfd_boolean); extern const struct bfd_elf_special_section *_bfd_elf_get_special_section (const char *, const struct bfd_elf_special_section *, unsigned int); extern const struct bfd_elf_special_section *_bfd_elf_get_sec_type_attr @@ -1942,8 +1998,6 @@ extern Elf_Internal_Sym *bfd_sym_from_r_symndx (struct sym_cache *, bfd *, unsigned long); extern asection *bfd_section_from_elf_index (bfd *, unsigned int); -extern struct bfd_strtab_hash *_bfd_elf_stringtab_init - (void); extern struct elf_strtab_hash * _bfd_elf_strtab_init (void); @@ -1970,11 +2024,13 @@ extern bfd_boolean _bfd_elf_strtab_emit extern void _bfd_elf_strtab_finalize (struct elf_strtab_hash *); -extern void _bfd_elf_begin_eh_frame_parsing - (struct bfd_link_info *info); +extern bfd_boolean bfd_elf_parse_eh_frame_entries + (bfd *, struct bfd_link_info *); +extern bfd_boolean _bfd_elf_parse_eh_frame_entry + (struct bfd_link_info *, asection *, struct elf_reloc_cookie *); extern void _bfd_elf_parse_eh_frame (bfd *, struct bfd_link_info *, asection *, struct elf_reloc_cookie *); -extern void _bfd_elf_end_eh_frame_parsing +extern bfd_boolean _bfd_elf_end_eh_frame_parsing (struct bfd_link_info *info); extern bfd_boolean _bfd_elf_discard_section_eh_frame @@ -1986,27 +2042,24 @@ extern bfd_vma _bfd_elf_eh_frame_section_offset (bfd *, struct bfd_link_info *, asection *, bfd_vma); extern bfd_boolean _bfd_elf_write_section_eh_frame (bfd *, struct bfd_link_info *, asection *, bfd_byte *); +bfd_boolean _bfd_elf_write_section_eh_frame_entry + (bfd *, struct bfd_link_info *, asection *, bfd_byte *); +extern bfd_boolean _bfd_elf_fixup_eh_frame_hdr (struct bfd_link_info *); extern bfd_boolean _bfd_elf_write_section_eh_frame_hdr (bfd *, struct bfd_link_info *); extern bfd_boolean _bfd_elf_eh_frame_present (struct bfd_link_info *); +extern bfd_boolean _bfd_elf_eh_frame_entry_present + (struct bfd_link_info *); extern bfd_boolean _bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *); -extern bfd_boolean _bfd_elf_merge_symbol - (bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *, - asection **, bfd_vma *, bfd_boolean *, unsigned int *, - struct elf_link_hash_entry **, bfd_boolean *, - bfd_boolean *, bfd_boolean *, bfd_boolean *); - extern bfd_boolean _bfd_elf_hash_symbol (struct elf_link_hash_entry *); extern long _bfd_elf_link_lookup_local_dynindx (struct bfd_link_info *, bfd *, long); extern bfd_boolean _bfd_elf_compute_section_file_positions (bfd *, struct bfd_link_info *); -extern void _bfd_elf_assign_file_positions_for_relocs - (bfd *); extern file_ptr _bfd_elf_assign_file_position_for_section (Elf_Internal_Shdr *, file_ptr, bfd_boolean); @@ -2021,6 +2074,8 @@ extern bfd_boolean _bfd_elf_create_dynamic_sections (bfd *, struct bfd_link_info *); extern bfd_boolean _bfd_elf_create_got_section (bfd *, struct bfd_link_info *); +extern asection *_bfd_elf_section_for_symbol + (struct elf_reloc_cookie *, unsigned long, bfd_boolean); extern struct elf_link_hash_entry *_bfd_elf_define_linkage_sym (bfd *, struct bfd_link_info *, asection *, const char *); extern void _bfd_elf_init_1_index_section @@ -2041,7 +2096,7 @@ extern bfd_boolean _bfd_elf_link_output_relocs struct elf_link_hash_entry **); extern bfd_boolean _bfd_elf_adjust_dynamic_copy - (struct elf_link_hash_entry *, asection *); + (struct bfd_link_info *, struct elf_link_hash_entry *, asection *); extern bfd_boolean _bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *, struct bfd_link_info *, bfd_boolean); @@ -2055,7 +2110,7 @@ extern bfd_reloc_status_type bfd_elf_perform_complex_relocation extern bfd_boolean _bfd_elf_setup_sections (bfd *); -extern void _bfd_elf_set_osabi (bfd * , struct bfd_link_info *); +extern void _bfd_elf_post_process_headers (bfd * , struct bfd_link_info *); extern const bfd_target *bfd_elf32_object_p (bfd *); @@ -2154,6 +2209,8 @@ extern bfd_boolean _bfd_elf_default_relocs_compatible extern bfd_boolean _bfd_elf_relocs_compatible (const bfd_target *, const bfd_target *); +extern bfd_boolean _bfd_elf_notice_as_needed + (bfd *, struct bfd_link_info *, enum notice_asneeded_action); extern struct elf_link_hash_entry *_bfd_elf_archive_symbol_lookup (bfd *, struct bfd_link_info *, const char *); @@ -2248,6 +2305,8 @@ extern bfd_boolean _bfd_elf_is_function_type (unsigned int); extern bfd_size_type _bfd_elf_maybe_function_sym (const asymbol *, asection *, bfd_vma *); +extern asection *_bfd_elf_get_reloc_section (asection *); + extern int bfd_elf_get_default_section_type (flagword); extern bfd_boolean bfd_elf_lookup_section_flags @@ -2291,6 +2350,10 @@ extern char *elfcore_write_s390_system_call (bfd *, char *, int *, const void *, int); extern char *elfcore_write_s390_tdb (bfd *, char *, int *, const void *, int); +extern char *elfcore_write_s390_vxrs_low + (bfd *, char *, int *, const void *, int); +extern char *elfcore_write_s390_vxrs_high + (bfd *, char *, int *, const void *, int); extern char *elfcore_write_arm_vfp (bfd *, char *, int *, const void *, int); extern char *elfcore_write_aarch_tls @@ -2341,30 +2404,30 @@ extern char *elfcore_write_ppc_linux_prpsinfo32 (bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *); extern bfd *_bfd_elf32_bfd_from_remote_memory - (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, + (bfd *templ, bfd_vma ehdr_vma, bfd_size_type size, bfd_vma *loadbasep, int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type)); extern bfd *_bfd_elf64_bfd_from_remote_memory - (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, + (bfd *templ, bfd_vma ehdr_vma, bfd_size_type size, bfd_vma *loadbasep, int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type)); extern bfd_vma bfd_elf_obj_attr_size (bfd *); extern void bfd_elf_set_obj_attr_contents (bfd *, bfd_byte *, bfd_vma); -extern int bfd_elf_get_obj_attr_int (bfd *, int, int); -extern void bfd_elf_add_obj_attr_int (bfd *, int, int, unsigned int); +extern int bfd_elf_get_obj_attr_int (bfd *, int, unsigned int); +extern void bfd_elf_add_obj_attr_int (bfd *, int, unsigned int, unsigned int); #define bfd_elf_add_proc_attr_int(BFD, TAG, VALUE) \ bfd_elf_add_obj_attr_int ((BFD), OBJ_ATTR_PROC, (TAG), (VALUE)) -extern void bfd_elf_add_obj_attr_string (bfd *, int, int, const char *); +extern void bfd_elf_add_obj_attr_string (bfd *, int, unsigned int, const char *); #define bfd_elf_add_proc_attr_string(BFD, TAG, VALUE) \ bfd_elf_add_obj_attr_string ((BFD), OBJ_ATTR_PROC, (TAG), (VALUE)) -extern void bfd_elf_add_obj_attr_int_string (bfd *, int, int, unsigned int, - const char *); +extern void bfd_elf_add_obj_attr_int_string (bfd *, int, unsigned int, + unsigned int, const char *); #define bfd_elf_add_proc_attr_int_string(BFD, TAG, INTVAL, STRVAL) \ bfd_elf_add_obj_attr_int_string ((BFD), OBJ_ATTR_PROC, (TAG), \ (INTVAL), (STRVAL)) extern char *_bfd_elf_attr_strdup (bfd *, const char *); extern void _bfd_elf_copy_obj_attributes (bfd *, bfd *); -extern int _bfd_elf_obj_attrs_arg_type (bfd *, int, int); +extern int _bfd_elf_obj_attrs_arg_type (bfd *, int, unsigned int); extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *); extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *); extern bfd_boolean _bfd_elf_merge_unknown_attribute_low (bfd *, bfd *, int); @@ -2393,12 +2456,12 @@ struct elf_dyn_relocs extern bfd_boolean _bfd_elf_create_ifunc_sections (bfd *, struct bfd_link_info *); -extern asection * _bfd_elf_create_ifunc_dyn_reloc - (bfd *, struct bfd_link_info *, asection *sec, asection *sreloc, - struct elf_dyn_relocs **); extern bfd_boolean _bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *, struct elf_link_hash_entry *, - struct elf_dyn_relocs **, unsigned int, unsigned int); + struct elf_dyn_relocs **, unsigned int, unsigned int, unsigned int); +extern long _bfd_elf_ifunc_get_synthetic_symtab + (bfd *, long, asymbol **, long, asymbol **, asymbol **, asection *, + bfd_vma *(*) (bfd *, asymbol **, asection *, asection *)); extern void elf_append_rela (bfd *, asection *, Elf_Internal_Rela *); extern void elf_append_rel (bfd *, asection *, Elf_Internal_Rela *); @@ -2430,7 +2493,7 @@ extern asection _bfd_elf_large_com_section; #define RELOC_FOR_GLOBAL_SYMBOL(info, input_bfd, input_section, rel, \ r_symndx, symtab_hdr, sym_hashes, \ h, sec, relocation, \ - unresolved_reloc, warned) \ + unresolved_reloc, warned, ignored) \ do \ { \ /* It seems this can happen with erroneous or unsupported \ @@ -2440,11 +2503,17 @@ extern asection _bfd_elf_large_com_section; \ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; \ \ + if (info->wrap_hash != NULL \ + && (input_section->flags & SEC_DEBUGGING) != 0) \ + h = ((struct elf_link_hash_entry *) \ + unwrap_hash_lookup (info, input_bfd, &h->root)); \ + \ while (h->root.type == bfd_link_hash_indirect \ || h->root.type == bfd_link_hash_warning) \ h = (struct elf_link_hash_entry *) h->root.u.i.link; \ \ warned = FALSE; \ + ignored = FALSE; \ unresolved_reloc = FALSE; \ relocation = 0; \ if (h->root.type == bfd_link_hash_defined \ @@ -2467,7 +2536,7 @@ extern asection _bfd_elf_large_com_section; ; \ else if (info->unresolved_syms_in_objects == RM_IGNORE \ && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) \ - ; \ + ignored = TRUE; \ else if (!info->relocatable) \ { \ bfd_boolean err; \ @@ -2483,6 +2552,7 @@ extern asection _bfd_elf_large_com_section; } \ (void) unresolved_reloc; \ (void) warned; \ + (void) ignored; \ } \ while (0) @@ -2512,16 +2582,16 @@ extern asection _bfd_elf_large_com_section; rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section); \ \ /* Avoid empty output section. */ \ - if (rel_hdr->sh_size > count * rel_hdr->sh_entsize) \ + if (rel_hdr->sh_size > rel_hdr->sh_entsize) \ { \ - rel_hdr->sh_size -= count * rel_hdr->sh_entsize; \ + rel_hdr->sh_size -= rel_hdr->sh_entsize; \ rel_hdr = _bfd_elf_single_rel_hdr (input_section); \ - rel_hdr->sh_size -= count * rel_hdr->sh_entsize; \ + rel_hdr->sh_size -= rel_hdr->sh_entsize; \ \ memmove (rel, rel + count, \ (relend - rel - count) * sizeof (*rel)); \ \ - input_section->reloc_count -= count; \ + input_section->reloc_count--; \ relend -= count; \ rel--; \ continue; \ @@ -2543,4 +2613,7 @@ extern asection _bfd_elf_large_com_section; (!(H)->unique_global \ && ((INFO)->symbolic || ((INFO)->dynamic && !(H)->dynamic))) +#ifdef __cplusplus +} +#endif #endif /* _LIBELF_H_ */ diff --git a/contrib/gdb-7/bfd/elf-eh-frame.c b/contrib/gdb-7/bfd/elf-eh-frame.c index 832a99192d..22068ab3b9 100644 --- a/contrib/gdb-7/bfd/elf-eh-frame.c +++ b/contrib/gdb-7/bfd/elf-eh-frame.c @@ -1,6 +1,5 @@ /* .eh_frame section optimization. - Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, - 2012 Free Software Foundation, Inc. + Copyright (C) 2001-2015 Free Software Foundation, Inc. Written by Jakub Jelinek . This file is part of BFD, the Binary File Descriptor library. @@ -41,10 +40,12 @@ struct cie bfd_vma augmentation_size; union { struct elf_link_hash_entry *h; - bfd_vma val; + struct { + unsigned int bfd_id; + unsigned int index; + } sym; unsigned int reloc_index; } personality; - asection *output_sec; struct eh_cie_fde *cie_inf; unsigned char per_encoding; unsigned char lsda_encoding; @@ -230,11 +231,13 @@ cie_eq (const void *e1, const void *e2) && c1->augmentation_size == c2->augmentation_size && memcmp (&c1->personality, &c2->personality, sizeof (c1->personality)) == 0 - && c1->output_sec == c2->output_sec + && (c1->cie_inf->u.cie.u.sec->output_section + == c2->cie_inf->u.cie.u.sec->output_section) && c1->per_encoding == c2->per_encoding && c1->lsda_encoding == c2->lsda_encoding && c1->fde_encoding == c2->fde_encoding && c1->initial_insn_length == c2->initial_insn_length + && c1->initial_insn_length <= sizeof (c1->initial_instructions) && memcmp (c1->initial_instructions, c2->initial_instructions, c1->initial_insn_length) == 0) @@ -254,6 +257,7 @@ static hashval_t cie_compute_hash (struct cie *c) { hashval_t h = 0; + size_t len; h = iterative_hash_object (c->length, h); h = iterative_hash_object (c->version, h); h = iterative_hash (c->augmentation, strlen (c->augmentation) + 1, h); @@ -262,12 +266,15 @@ cie_compute_hash (struct cie *c) h = iterative_hash_object (c->ra_column, h); h = iterative_hash_object (c->augmentation_size, h); h = iterative_hash_object (c->personality, h); - h = iterative_hash_object (c->output_sec, h); + h = iterative_hash_object (c->cie_inf->u.cie.u.sec->output_section, h); h = iterative_hash_object (c->per_encoding, h); h = iterative_hash_object (c->lsda_encoding, h); h = iterative_hash_object (c->fde_encoding, h); h = iterative_hash_object (c->initial_insn_length, h); - h = iterative_hash (c->initial_instructions, c->initial_insn_length, h); + len = c->initial_insn_length; + if (len > sizeof (c->initial_instructions)) + len = sizeof (c->initial_instructions); + h = iterative_hash (c->initial_instructions, len, h); c->hash = h; return h; } @@ -445,16 +452,109 @@ make_pc_relative (unsigned char encoding, unsigned int ptr_size) return encoding | DW_EH_PE_pcrel; } -/* Called before calling _bfd_elf_parse_eh_frame on every input bfd's - .eh_frame section. */ +/* Examine each .eh_frame_entry section and discard those + those that are marked SEC_EXCLUDE. */ -void -_bfd_elf_begin_eh_frame_parsing (struct bfd_link_info *info) +static void +bfd_elf_discard_eh_frame_entry (struct eh_frame_hdr_info *hdr_info) +{ + unsigned int i; + for (i = 0; i < hdr_info->array_count; i++) + { + if (hdr_info->u.compact.entries[i]->flags & SEC_EXCLUDE) + { + unsigned int j; + for (j = i + 1; j < hdr_info->array_count; j++) + hdr_info->u.compact.entries[j-1] = hdr_info->u.compact.entries[j]; + + hdr_info->array_count--; + hdr_info->u.compact.entries[hdr_info->array_count] = NULL; + i--; + } + } +} + +/* Add a .eh_frame_entry section. */ + +static void +bfd_elf_record_eh_frame_entry (struct eh_frame_hdr_info *hdr_info, + asection *sec) +{ + if (hdr_info->array_count == hdr_info->u.compact.allocated_entries) + { + if (hdr_info->u.compact.allocated_entries == 0) + { + hdr_info->frame_hdr_is_compact = TRUE; + hdr_info->u.compact.allocated_entries = 2; + hdr_info->u.compact.entries = + bfd_malloc (hdr_info->u.compact.allocated_entries + * sizeof (hdr_info->u.compact.entries[0])); + } + else + { + hdr_info->u.compact.allocated_entries *= 2; + hdr_info->u.compact.entries = + bfd_realloc (hdr_info->u.compact.entries, + hdr_info->u.compact.allocated_entries + * sizeof (hdr_info->u.compact.entries[0])); + } + + BFD_ASSERT (hdr_info->u.compact.entries); + } + + hdr_info->u.compact.entries[hdr_info->array_count++] = sec; +} + +/* Parse a .eh_frame_entry section. Figure out which text section it + references. */ + +bfd_boolean +_bfd_elf_parse_eh_frame_entry (struct bfd_link_info *info, + asection *sec, struct elf_reloc_cookie *cookie) { + struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; + unsigned long r_symndx; + asection *text_sec; - hdr_info = &elf_hash_table (info)->eh_info; - hdr_info->merge_cies = !info->relocatable; + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; + + if (sec->size == 0 + || sec->sec_info_type != SEC_INFO_TYPE_NONE) + { + return TRUE; + } + + if (sec->output_section && bfd_is_abs_section (sec->output_section)) + { + /* At least one of the sections is being discarded from the + link, so we should just ignore them. */ + return TRUE; + } + + if (cookie->rel == cookie->relend) + return FALSE; + + /* The first relocation is the function start. */ + r_symndx = cookie->rel->r_info >> cookie->r_sym_shift; + if (r_symndx == STN_UNDEF) + return FALSE; + + text_sec = _bfd_elf_section_for_symbol (cookie, r_symndx, FALSE); + + if (text_sec == NULL) + return FALSE; + + elf_section_eh_frame_entry (text_sec) = sec; + if (text_sec->output_section + && bfd_is_abs_section (text_sec->output_section)) + sec->flags |= SEC_EXCLUDE; + + sec->sec_info_type = SEC_INFO_TYPE_EH_FRAME_ENTRY; + elf_section_data (sec)->sec_info = text_sec; + bfd_elf_record_eh_frame_entry (hdr_info, sec); + return TRUE; } /* Try to parse .eh_frame section SEC, which belongs to ABFD. Store the @@ -487,8 +587,6 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, htab = elf_hash_table (info); hdr_info = &htab->eh_info; - if (hdr_info->parsed_eh_frames) - return; if (sec->size == 0 || sec->sec_info_type != SEC_INFO_TYPE_NONE) @@ -563,10 +661,13 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, /* FIXME: octets_per_byte. */ #define ENSURE_NO_RELOCS(buf) \ - REQUIRE (!(cookie->rel < cookie->relend \ - && (cookie->rel->r_offset \ - < (bfd_size_type) ((buf) - ehbuf)) \ - && cookie->rel->r_info != 0)) + while (cookie->rel < cookie->relend \ + && (cookie->rel->r_offset \ + < (bfd_size_type) ((buf) - ehbuf))) \ + { \ + REQUIRE (cookie->rel->r_info == 0); \ + cookie->rel++; \ + } /* FIXME: octets_per_byte. */ #define SKIP_RELOCS(buf) \ @@ -632,7 +733,6 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, cie->cie_inf = this_inf; cie->length = hdr_length; - cie->output_sec = sec->output_section; start = buf; REQUIRE (read_byte (&buf, end, &cie->version)); @@ -734,6 +834,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, /* For shared libraries, try to get rid of as many RELATIVE relocs as possible. */ if (info->shared + && !info->relocatable && (get_elf_backend_data (abfd) ->elf_backend_can_make_relative_eh_frame (abfd, info, sec))) @@ -762,19 +863,21 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, cie->fde_encoding = DW_EH_PE_absptr; initial_insn_length = end - buf; - if (initial_insn_length <= sizeof (cie->initial_instructions)) - { - cie->initial_insn_length = initial_insn_length; - memcpy (cie->initial_instructions, buf, initial_insn_length); - } + cie->initial_insn_length = initial_insn_length; + memcpy (cie->initial_instructions, buf, + initial_insn_length <= sizeof (cie->initial_instructions) + ? initial_insn_length : sizeof (cie->initial_instructions)); insns = buf; buf += initial_insn_length; ENSURE_NO_RELOCS (buf); - if (hdr_info->merge_cies) - this_inf->u.cie.u.full_cie = cie; - this_inf->u.cie.per_encoding_relative - = (cie->per_encoding & 0x70) == DW_EH_PE_pcrel; + if (!info->relocatable) + { + /* Keep info for merging cies. */ + this_inf->u.cie.u.full_cie = cie; + this_inf->u.cie.per_encoding_relative + = (cie->per_encoding & 0x70) == DW_EH_PE_pcrel; + } } else { @@ -816,6 +919,16 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); REQUIRE (skip_bytes (&buf, end, 2 * length)); + SKIP_RELOCS (buf - length); + if (!GET_RELOC (buf - length) + && read_value (abfd, buf - length, length, FALSE) == 0) + { + (*info->callbacks->minfo) + (_("discarding zero address range FDE in %B(%A).\n"), + abfd, sec); + this_inf->u.fde.cie_inf = NULL; + } + /* Skip the augmentation size, if present. */ if (cie->augmentation[0] == 'z') REQUIRE (read_uleb128 (&buf, end, &length)); @@ -905,8 +1018,9 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, elf_section_data (sec)->sec_info = sec_info; sec->sec_info_type = SEC_INFO_TYPE_EH_FRAME; - if (hdr_info->merge_cies) + if (!info->relocatable) { + /* Keep info for merging cies. */ sec_info->cies = local_cies; local_cies = NULL; } @@ -916,7 +1030,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, (*info->callbacks->einfo) (_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"), abfd, sec); - hdr_info->table = FALSE; + hdr_info->u.dwarf.table = FALSE; if (sec_info) free (sec_info); success: @@ -927,15 +1041,87 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, #undef REQUIRE } -/* Finish a pass over all .eh_frame sections. */ +/* Order eh_frame_hdr entries by the VMA of their text section. */ -void +static int +cmp_eh_frame_hdr (const void *a, const void *b) +{ + bfd_vma text_a; + bfd_vma text_b; + asection *sec; + + sec = *(asection *const *)a; + sec = (asection *) elf_section_data (sec)->sec_info; + text_a = sec->output_section->vma + sec->output_offset; + sec = *(asection *const *)b; + sec = (asection *) elf_section_data (sec)->sec_info; + text_b = sec->output_section->vma + sec->output_offset; + + if (text_a < text_b) + return -1; + return text_a > text_b; + +} + +/* Add space for a CANTUNWIND terminator to SEC if the text sections + referenced by it and NEXT are not contiguous, or NEXT is NULL. */ + +static void +add_eh_frame_hdr_terminator (asection *sec, + asection *next) +{ + bfd_vma end; + bfd_vma next_start; + asection *text_sec; + + if (next) + { + /* See if there is a gap (presumably a text section without unwind info) + between these two entries. */ + text_sec = (asection *) elf_section_data (sec)->sec_info; + end = text_sec->output_section->vma + text_sec->output_offset + + text_sec->size; + text_sec = (asection *) elf_section_data (next)->sec_info; + next_start = text_sec->output_section->vma + text_sec->output_offset; + if (end == next_start) + return; + } + + /* Add space for a CANTUNWIND terminator. */ + if (!sec->rawsize) + sec->rawsize = sec->size; + + bfd_set_section_size (sec->owner, sec, sec->size + 8); +} + +/* Finish a pass over all .eh_frame_entry sections. */ + +bfd_boolean _bfd_elf_end_eh_frame_parsing (struct bfd_link_info *info) { struct eh_frame_hdr_info *hdr_info; + unsigned int i; hdr_info = &elf_hash_table (info)->eh_info; - hdr_info->parsed_eh_frames = TRUE; + + if (info->eh_frame_hdr_type != COMPACT_EH_HDR + || hdr_info->array_count == 0) + return FALSE; + + bfd_elf_discard_eh_frame_entry (hdr_info); + + qsort (hdr_info->u.compact.entries, hdr_info->array_count, + sizeof (asection *), cmp_eh_frame_hdr); + + for (i = 0; i < hdr_info->array_count - 1; i++) + { + add_eh_frame_hdr_terminator (hdr_info->u.compact.entries[i], + hdr_info->u.compact.entries[i + 1]); + } + + /* Add a CANTUNWIND terminator after the last entry. */ + add_eh_frame_hdr_terminator (hdr_info->u.compact.entries[i], NULL); + return TRUE; } /* Mark all relocations against CIE or FDE ENT, which occurs in @@ -977,7 +1163,7 @@ _bfd_elf_gc_mark_fdes (struct bfd_link_info *info, asection *sec, /* At this stage, all cie_inf fields point to local CIEs, so we can use the same cookie to refer to them. */ cie = fde->u.fde.cie_inf; - if (!cie->u.cie.gc_mark) + if (cie != NULL && !cie->u.cie.gc_mark) { cie->u.cie.gc_mark = 1; if (!mark_entry (info, eh_frame, cie, gc_mark_hook, cookie)) @@ -1027,8 +1213,12 @@ find_merged_cie (bfd *abfd, struct bfd_link_info *info, asection *sec, { bfd_boolean per_binds_local; - /* Work out the address of personality routine, either as an absolute - value or as a symbol. */ + /* Work out the address of personality routine, or at least + enough info that we could calculate the address had we made a + final section layout. The symbol on the reloc is enough, + either the hash for a global, or (bfd id, index) pair for a + local. The assumption here is that no one uses addends on + the reloc. */ rel = cookie->rels + cie->personality.reloc_index; memset (&cie->personality, 0, sizeof (cie->personality)); #ifdef BFD64 @@ -1068,14 +1258,14 @@ find_merged_cie (bfd *abfd, struct bfd_link_info *info, asection *sec, return cie_inf; cie->local_personality = 1; - cie->personality.val = (sym->st_value - + sym_sec->output_offset - + sym_sec->output_section->vma); + cie->personality.sym.bfd_id = abfd->id; + cie->personality.sym.index = r_symndx; per_binds_local = TRUE; } if (per_binds_local && info->shared + && !info->relocatable && (cie->per_encoding & 0x70) == DW_EH_PE_absptr && (get_elf_backend_data (abfd) ->elf_backend_can_make_relative_eh_frame (abfd, info, sec))) @@ -1086,15 +1276,15 @@ find_merged_cie (bfd *abfd, struct bfd_link_info *info, asection *sec, } /* See if we can merge this CIE with an earlier one. */ - cie->output_sec = sec->output_section; cie_compute_hash (cie); - if (hdr_info->cies == NULL) + if (hdr_info->u.dwarf.cies == NULL) { - hdr_info->cies = htab_try_create (1, cie_hash, cie_eq, free); - if (hdr_info->cies == NULL) + hdr_info->u.dwarf.cies = htab_try_create (1, cie_hash, cie_eq, free); + if (hdr_info->u.dwarf.cies == NULL) return cie_inf; } - loc = htab_find_slot_with_hash (hdr_info->cies, cie, cie->hash, INSERT); + loc = htab_find_slot_with_hash (hdr_info->u.dwarf.cies, cie, + cie->hash, INSERT); if (loc == NULL) return cie_inf; @@ -1153,7 +1343,7 @@ _bfd_elf_discard_section_eh_frame /* There should only be one zero terminator, on the last input file supplying .eh_frame (crtend.o). Remove any others. */ ent->removed = sec->map_head.s != NULL; - else if (!ent->cie) + else if (!ent->cie && ent->u.fde.cie_inf != NULL) { bfd_boolean keep; if ((sec->flags & SEC_LINKER_CREATED) != 0 && cookie->rels == NULL) @@ -1184,13 +1374,13 @@ _bfd_elf_discard_section_eh_frame which we cannot turn into PC relative, don't create the binary search table, since it is affected by runtime relocations. */ - hdr_info->table = FALSE; + hdr_info->u.dwarf.table = FALSE; (*info->callbacks->einfo) - (_("%P: fde encoding in %B(%A) prevents .eh_frame_hdr" + (_("%P: FDE encoding in %B(%A) prevents .eh_frame_hdr" " table being created.\n"), abfd, sec); } ent->removed = 0; - hdr_info->fde_count++; + hdr_info->u.dwarf.fde_count++; ent->u.fde.cie_inf = find_merged_cie (abfd, info, sec, hdr_info, cookie, ent->u.fde.cie_inf); } @@ -1229,19 +1419,28 @@ _bfd_elf_discard_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) htab = elf_hash_table (info); hdr_info = &htab->eh_info; - if (hdr_info->cies != NULL) + if (!hdr_info->frame_hdr_is_compact && hdr_info->u.dwarf.cies != NULL) { - htab_delete (hdr_info->cies); - hdr_info->cies = NULL; + htab_delete (hdr_info->u.dwarf.cies); + hdr_info->u.dwarf.cies = NULL; } sec = hdr_info->hdr_sec; if (sec == NULL) return FALSE; - sec->size = EH_FRAME_HDR_SIZE; - if (hdr_info->table) - sec->size += 4 + hdr_info->fde_count * 8; + if (info->eh_frame_hdr_type == COMPACT_EH_HDR) + { + /* For compact frames we only add the header. The actual table comes + from the .eh_frame_entry sections. */ + sec->size = 8; + } + else + { + sec->size = EH_FRAME_HDR_SIZE; + if (hdr_info->u.dwarf.table) + sec->size += 4 + hdr_info->u.dwarf.fde_count * 8; + } elf_eh_frame_hdr (abfd) = sec; return TRUE; @@ -1250,6 +1449,7 @@ _bfd_elf_discard_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) /* Return true if there is at least one non-empty .eh_frame section in input files. Can only be called after ld has mapped input to output sections, and before sections are stripped. */ + bfd_boolean _bfd_elf_eh_frame_present (struct bfd_link_info *info) { @@ -1267,6 +1467,29 @@ _bfd_elf_eh_frame_present (struct bfd_link_info *info) return FALSE; } +/* Return true if there is at least one .eh_frame_entry section in + input files. */ + +bfd_boolean +_bfd_elf_eh_frame_entry_present (struct bfd_link_info *info) +{ + asection *o; + bfd *abfd; + + for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) + { + for (o = abfd->sections; o; o = o->next) + { + const char *name = bfd_get_section_name (abfd, o); + + if (strcmp (name, ".eh_frame_entry") + && !bfd_is_abs_section (o->output_section)) + return TRUE; + } + } + return FALSE; +} + /* This function is called from size_dynamic_sections. It needs to decide whether .eh_frame_hdr should be output or not, because when the dynamic symbol table has been sized it is too late @@ -1277,6 +1500,8 @@ _bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *info) { struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; + struct bfd_link_hash_entry *bh = NULL; + struct elf_link_hash_entry *h; htab = elf_hash_table (info); hdr_info = &htab->eh_info; @@ -1284,15 +1509,32 @@ _bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *info) return TRUE; if (bfd_is_abs_section (hdr_info->hdr_sec->output_section) - || !info->eh_frame_hdr - || !_bfd_elf_eh_frame_present (info)) + || info->eh_frame_hdr_type == 0 + || (info->eh_frame_hdr_type == DWARF2_EH_HDR + && !_bfd_elf_eh_frame_present (info)) + || (info->eh_frame_hdr_type == COMPACT_EH_HDR + && !_bfd_elf_eh_frame_entry_present (info))) { hdr_info->hdr_sec->flags |= SEC_EXCLUDE; hdr_info->hdr_sec = NULL; return TRUE; } - hdr_info->table = TRUE; + /* Add a hidden symbol so that systems without access to PHDRs can + find the table. */ + if (! (_bfd_generic_link_add_one_symbol + (info, info->output_bfd, "__GNU_EH_FRAME_HDR", BSF_LOCAL, + hdr_info->hdr_sec, 0, NULL, FALSE, FALSE, &bh))) + return FALSE; + + h = (struct elf_link_hash_entry *) bh; + h->def_regular = 1; + h->other = STV_HIDDEN; + get_elf_backend_data + (info->output_bfd)->elf_backend_hide_symbol (info, h, TRUE); + + if (!hdr_info->frame_hdr_is_compact) + hdr_info->u.dwarf.table = TRUE; return TRUE; } @@ -1383,6 +1625,83 @@ _bfd_elf_eh_frame_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, + extra_augmentation_data_bytes (sec_info->entry + mid)); } +/* Write out .eh_frame_entry section. Add CANTUNWIND terminator if needed. + Also check that the contents look sane. */ + +bfd_boolean +_bfd_elf_write_section_eh_frame_entry (bfd *abfd, struct bfd_link_info *info, + asection *sec, bfd_byte *contents) +{ + const struct elf_backend_data *bed; + bfd_byte cantunwind[8]; + bfd_vma addr; + bfd_vma last_addr; + bfd_vma offset; + asection *text_sec = (asection *) elf_section_data (sec)->sec_info; + + if (!sec->rawsize) + sec->rawsize = sec->size; + + BFD_ASSERT (sec->sec_info_type == SEC_INFO_TYPE_EH_FRAME_ENTRY); + + /* Check to make sure that the text section corresponding to this eh_frame_entry + section has not been excluded. In particular, mips16 stub entries will be + excluded outside of the normal process. */ + if (sec->flags & SEC_EXCLUDE + || text_sec->flags & SEC_EXCLUDE) + return TRUE; + + if (!bfd_set_section_contents (abfd, sec->output_section, contents, + sec->output_offset, sec->rawsize)) + return FALSE; + + last_addr = bfd_get_signed_32 (abfd, contents); + /* Check that all the entries are in order. */ + for (offset = 8; offset < sec->rawsize; offset += 8) + { + addr = bfd_get_signed_32 (abfd, contents + offset) + offset; + if (addr <= last_addr) + { + (*_bfd_error_handler) (_("%B: %s not in order"), sec->owner, sec->name); + return FALSE; + } + + last_addr = addr; + } + + addr = text_sec->output_section->vma + text_sec->output_offset + + text_sec->size; + addr &= ~1; + addr -= (sec->output_section->vma + sec->output_offset + sec->rawsize); + if (addr & 1) + { + (*_bfd_error_handler) (_("%B: %s invalid input section size"), + sec->owner, sec->name); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + if (last_addr >= addr + sec->rawsize) + { + (*_bfd_error_handler) (_("%B: %s points past end of text section"), + sec->owner, sec->name); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + if (sec->size == sec->rawsize) + return TRUE; + + bed = get_elf_backend_data (abfd); + BFD_ASSERT (sec->size == sec->rawsize + 8); + BFD_ASSERT ((addr & 1) == 0); + BFD_ASSERT (bed->cant_unwind_opcode); + + bfd_put_32 (abfd, addr, cantunwind); + bfd_put_32 (abfd, (*bed->cant_unwind_opcode) (info), cantunwind + 4); + return bfd_set_section_contents (abfd, sec->output_section, cantunwind, + sec->output_offset + sec->rawsize, 8); +} + /* Write out .eh_frame section. This is called with the relocated contents. */ @@ -1397,6 +1716,7 @@ _bfd_elf_write_section_eh_frame (bfd *abfd, struct eh_frame_hdr_info *hdr_info; unsigned int ptr_size; struct eh_cie_fde *ent; + bfd_size_type sec_size; if (sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME) /* FIXME: octets_per_byte. */ @@ -1411,10 +1731,14 @@ _bfd_elf_write_section_eh_frame (bfd *abfd, htab = elf_hash_table (info); hdr_info = &htab->eh_info; - if (hdr_info->table && hdr_info->array == NULL) - hdr_info->array = (struct eh_frame_array_ent *) - bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array)); - if (hdr_info->array == NULL) + if (hdr_info->u.dwarf.table && hdr_info->u.dwarf.array == NULL) + { + hdr_info->frame_hdr_is_compact = FALSE; + hdr_info->u.dwarf.array = (struct eh_frame_array_ent *) + bfd_malloc (hdr_info->u.dwarf.fde_count + * sizeof (*hdr_info->u.dwarf.array)); + } + if (hdr_info->u.dwarf.array == NULL) hdr_info = NULL; /* The new offsets can be bigger or smaller than the original offsets. @@ -1583,6 +1907,8 @@ _bfd_elf_write_section_eh_frame (bfd *abfd, value = ((ent->new_offset + sec->output_offset + 4) - (cie->new_offset + cie->u.cie.u.sec->output_offset)); bfd_put_32 (abfd, value, buf); + if (info->relocatable) + continue; buf += 4; width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); value = read_value (abfd, buf, width, @@ -1647,8 +1973,11 @@ _bfd_elf_write_section_eh_frame (bfd *abfd, dwarf_vma is 64-bit. */ if (sizeof (address) > 4 && ptr_size == 4) address &= 0xffffffff; - hdr_info->array[hdr_info->array_count].initial_loc = address; - hdr_info->array[hdr_info->array_count++].fde + hdr_info->u.dwarf.array[hdr_info->array_count].initial_loc + = address; + hdr_info->u.dwarf.array[hdr_info->array_count].range + = read_value (abfd, buf + width, width, FALSE); + hdr_info->u.dwarf.array[hdr_info->array_count++].fde = (sec->output_section->vma + sec->output_offset + ent->new_offset); @@ -1718,7 +2047,11 @@ _bfd_elf_write_section_eh_frame (bfd *abfd, the pointer size. _bfd_elf_discard_section_eh_frame should have padded CIE/FDE records to multiple of pointer size with size_of_output_cie_fde. */ - if ((sec->size % ptr_size) != 0) + sec_size = sec->size; + if (sec_info->count != 0 + && sec_info->entry[sec_info->count - 1].size == 4) + sec_size -= 4; + if ((sec_size % ptr_size) != 0) abort (); /* FIXME: octets_per_byte. */ @@ -1739,13 +2072,118 @@ vma_compare (const void *a, const void *b) return 1; if (p->initial_loc < q->initial_loc) return -1; + if (p->range > q->range) + return 1; + if (p->range < q->range) + return -1; return 0; } -/* Write out .eh_frame_hdr section. This must be called after - _bfd_elf_write_section_eh_frame has been called on all input - .eh_frame sections. - .eh_frame_hdr format: +/* Reorder .eh_frame_entry sections to match the associated text sections. + This routine is called during the final linking step, just before writing + the contents. At this stage, sections in the eh_frame_hdr_info are already + sorted in order of increasing text section address and so we simply need + to make the .eh_frame_entrys follow that same order. Note that it is + invalid for a linker script to try to force a particular order of + .eh_frame_entry sections. */ + +bfd_boolean +_bfd_elf_fixup_eh_frame_hdr (struct bfd_link_info *info) +{ + asection *sec = NULL; + asection *osec; + struct eh_frame_hdr_info *hdr_info; + unsigned int i; + bfd_vma offset; + struct bfd_link_order *p; + + hdr_info = &elf_hash_table (info)->eh_info; + + if (hdr_info->hdr_sec == NULL + || info->eh_frame_hdr_type != COMPACT_EH_HDR + || hdr_info->array_count == 0) + return TRUE; + + /* Change section output offsets to be in text section order. */ + offset = 8; + osec = hdr_info->u.compact.entries[0]->output_section; + for (i = 0; i < hdr_info->array_count; i++) + { + sec = hdr_info->u.compact.entries[i]; + if (sec->output_section != osec) + { + (*_bfd_error_handler) + (_("Invalid output section for .eh_frame_entry: %s"), + sec->output_section->name); + return FALSE; + } + sec->output_offset = offset; + offset += sec->size; + } + + + /* Fix the link_order to match. */ + for (p = sec->output_section->map_head.link_order; p != NULL; p = p->next) + { + if (p->type != bfd_indirect_link_order) + abort(); + + p->offset = p->u.indirect.section->output_offset; + if (p->next != NULL) + i--; + } + + if (i != 0) + { + (*_bfd_error_handler) + (_("Invalid contents in %s section"), osec->name); + return FALSE; + } + + return TRUE; +} + +/* The .eh_frame_hdr format for Compact EH frames: + ubyte version (2) + ubyte eh_ref_enc (DW_EH_PE_* encoding of typinfo references) + uint32_t count (Number of entries in table) + [array from .eh_frame_entry sections] */ + +static bfd_boolean +write_compact_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) +{ + struct elf_link_hash_table *htab; + struct eh_frame_hdr_info *hdr_info; + asection *sec; + const struct elf_backend_data *bed; + bfd_vma count; + bfd_byte contents[8]; + unsigned int i; + + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; + sec = hdr_info->hdr_sec; + + if (sec->size != 8) + abort(); + + for (i = 0; i < sizeof (contents); i++) + contents[i] = 0; + + contents[0] = COMPACT_EH_HDR; + bed = get_elf_backend_data (abfd); + + BFD_ASSERT (bed->compact_eh_encoding); + contents[1] = (*bed->compact_eh_encoding) (info); + + count = (sec->output_section->size - 8) / 8; + bfd_put_32 (abfd, count, contents + 4); + return bfd_set_section_contents (abfd, sec->output_section, contents, + (file_ptr) sec->output_offset, sec->size); +} + +/* The .eh_frame_hdr format for DWARF frames: + ubyte version (currently 1) ubyte eh_frame_ptr_enc (DW_EH_PE_* encoding of pointer to start of .eh_frame section) @@ -1764,8 +2202,8 @@ vma_compare (const void *a, const void *b) FDE initial_location field and FDE address, sorted by increasing initial_loc). */ -bfd_boolean -_bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) +static bfd_boolean +write_dwarf_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) { struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; @@ -1775,77 +2213,130 @@ _bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) htab = elf_hash_table (info); hdr_info = &htab->eh_info; sec = hdr_info->hdr_sec; + bfd_byte *contents; + asection *eh_frame_sec; + bfd_size_type size; + bfd_vma encoded_eh_frame; + + size = EH_FRAME_HDR_SIZE; + if (hdr_info->u.dwarf.array + && hdr_info->array_count == hdr_info->u.dwarf.fde_count) + size += 4 + hdr_info->u.dwarf.fde_count * 8; + contents = (bfd_byte *) bfd_malloc (size); + if (contents == NULL) + return FALSE; - if (info->eh_frame_hdr && sec != NULL) + eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame"); + if (eh_frame_sec == NULL) { - bfd_byte *contents; - asection *eh_frame_sec; - bfd_size_type size; - bfd_vma encoded_eh_frame; - - size = EH_FRAME_HDR_SIZE; - if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) - size += 4 + hdr_info->fde_count * 8; - contents = (bfd_byte *) bfd_malloc (size); - if (contents == NULL) - return FALSE; + free (contents); + return FALSE; + } - eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame"); - if (eh_frame_sec == NULL) - { - free (contents); - return FALSE; - } + memset (contents, 0, EH_FRAME_HDR_SIZE); + /* Version. */ + contents[0] = 1; + /* .eh_frame offset. */ + contents[1] = get_elf_backend_data (abfd)->elf_backend_encode_eh_address + (abfd, info, eh_frame_sec, 0, sec, 4, &encoded_eh_frame); - memset (contents, 0, EH_FRAME_HDR_SIZE); - /* Version. */ - contents[0] = 1; - /* .eh_frame offset. */ - contents[1] = get_elf_backend_data (abfd)->elf_backend_encode_eh_address - (abfd, info, eh_frame_sec, 0, sec, 4, &encoded_eh_frame); + if (hdr_info->u.dwarf.array + && hdr_info->array_count == hdr_info->u.dwarf.fde_count) + { + /* FDE count encoding. */ + contents[2] = DW_EH_PE_udata4; + /* Search table encoding. */ + contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; + } + else + { + contents[2] = DW_EH_PE_omit; + contents[3] = DW_EH_PE_omit; + } + bfd_put_32 (abfd, encoded_eh_frame, contents + 4); - if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) + if (contents[2] != DW_EH_PE_omit) + { + unsigned int i; + bfd_boolean overlap, overflow; + + bfd_put_32 (abfd, hdr_info->u.dwarf.fde_count, + contents + EH_FRAME_HDR_SIZE); + qsort (hdr_info->u.dwarf.array, hdr_info->u.dwarf.fde_count, + sizeof (*hdr_info->u.dwarf.array), vma_compare); + overlap = FALSE; + overflow = FALSE; + for (i = 0; i < hdr_info->u.dwarf.fde_count; i++) { - /* FDE count encoding. */ - contents[2] = DW_EH_PE_udata4; - /* Search table encoding. */ - contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; + bfd_vma val; + + val = hdr_info->u.dwarf.array[i].initial_loc + - sec->output_section->vma; + val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000; + if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64 + && (hdr_info->u.dwarf.array[i].initial_loc + != sec->output_section->vma + val)) + overflow = TRUE; + bfd_put_32 (abfd, val, contents + EH_FRAME_HDR_SIZE + i * 8 + 4); + val = hdr_info->u.dwarf.array[i].fde - sec->output_section->vma; + val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000; + if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64 + && (hdr_info->u.dwarf.array[i].fde + != sec->output_section->vma + val)) + overflow = TRUE; + bfd_put_32 (abfd, val, contents + EH_FRAME_HDR_SIZE + i * 8 + 8); + if (i != 0 + && (hdr_info->u.dwarf.array[i].initial_loc + < (hdr_info->u.dwarf.array[i - 1].initial_loc + + hdr_info->u.dwarf.array[i - 1].range))) + overlap = TRUE; } - else + if (overflow) + (*info->callbacks->einfo) (_("%P: .eh_frame_hdr entry overflow.\n")); + if (overlap) + (*info->callbacks->einfo) + (_("%P: .eh_frame_hdr refers to overlapping FDEs.\n")); + if (overflow || overlap) { - contents[2] = DW_EH_PE_omit; - contents[3] = DW_EH_PE_omit; + bfd_set_error (bfd_error_bad_value); + retval = FALSE; } - bfd_put_32 (abfd, encoded_eh_frame, contents + 4); + } - if (contents[2] != DW_EH_PE_omit) - { - unsigned int i; + /* FIXME: octets_per_byte. */ + if (!bfd_set_section_contents (abfd, sec->output_section, contents, + (file_ptr) sec->output_offset, + sec->size)) + retval = FALSE; + free (contents); + + if (hdr_info->u.dwarf.array != NULL) + free (hdr_info->u.dwarf.array); + return retval; +} - bfd_put_32 (abfd, hdr_info->fde_count, contents + EH_FRAME_HDR_SIZE); - qsort (hdr_info->array, hdr_info->fde_count, - sizeof (*hdr_info->array), vma_compare); - for (i = 0; i < hdr_info->fde_count; i++) - { - bfd_put_32 (abfd, - hdr_info->array[i].initial_loc - - sec->output_section->vma, - contents + EH_FRAME_HDR_SIZE + i * 8 + 4); - bfd_put_32 (abfd, - hdr_info->array[i].fde - sec->output_section->vma, - contents + EH_FRAME_HDR_SIZE + i * 8 + 8); - } - } +/* Write out .eh_frame_hdr section. This must be called after + _bfd_elf_write_section_eh_frame has been called on all input + .eh_frame sections. */ - /* FIXME: octets_per_byte. */ - retval = bfd_set_section_contents (abfd, sec->output_section, contents, - (file_ptr) sec->output_offset, - sec->size); - free (contents); - } - if (hdr_info->array != NULL) - free (hdr_info->array); - return retval; +bfd_boolean +_bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) +{ + struct elf_link_hash_table *htab; + struct eh_frame_hdr_info *hdr_info; + asection *sec; + + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; + sec = hdr_info->hdr_sec; + + if (info->eh_frame_hdr_type == 0 || sec == NULL) + return TRUE; + + if (info->eh_frame_hdr_type == COMPACT_EH_HDR) + return write_compact_eh_frame_hdr (abfd, info); + else + return write_dwarf_eh_frame_hdr (abfd, info); } /* Return the width of FDE addresses. This is the default implementation. */ diff --git a/contrib/gdb-7/bfd/elf-ifunc.c b/contrib/gdb-7/bfd/elf-ifunc.c index e56427deff..f54c90b509 100644 --- a/contrib/gdb-7/bfd/elf-ifunc.c +++ b/contrib/gdb-7/bfd/elf-ifunc.c @@ -1,6 +1,5 @@ /* ELF STT_GNU_IFUNC support. - Copyright 2009 - Free Software Foundation, Inc. + Copyright (C) 2009-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -104,51 +103,6 @@ _bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info) return TRUE; } -/* For a STT_GNU_IFUNC symbol, create a dynamic reloc section, SRELOC, - for the input section, SEC, and append this reloc to HEAD. */ - -asection * -_bfd_elf_create_ifunc_dyn_reloc (bfd *abfd, struct bfd_link_info *info, - asection *sec, asection *sreloc, - struct elf_dyn_relocs **head) -{ - struct elf_dyn_relocs *p; - struct elf_link_hash_table *htab = elf_hash_table (info); - - if (sreloc == NULL) - { - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - - if (htab->dynobj == NULL) - htab->dynobj = abfd; - - sreloc = _bfd_elf_make_dynamic_reloc_section (sec, htab->dynobj, - bed->s->log_file_align, - abfd, - bed->rela_plts_and_copies_p); - if (sreloc == NULL) - return NULL; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof *p; - - p = ((struct elf_dyn_relocs *) bfd_alloc (htab->dynobj, amt)); - if (p == NULL) - return NULL; - p->next = *head; - *head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; - } - p->count += 1; - - return sreloc; -} - /* Allocate space in .plt, .got and associated reloc sections for dynamic relocs against a STT_GNU_IFUNC symbol definition. */ @@ -157,6 +111,7 @@ _bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info, struct elf_link_hash_entry *h, struct elf_dyn_relocs **head, unsigned int plt_entry_size, + unsigned int plt_header_size, unsigned int got_entry_size) { asection *plt, *gotplt, *relplt; @@ -187,23 +142,20 @@ _bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info, htab = elf_hash_table (info); + /* When building shared library, we need to handle the case where it is + marked with regular reference, but not non-GOT reference since the + non-GOT reference bit may not be set here. */ + if (info->shared && !h->non_got_ref && h->ref_regular) + for (p = *head; p != NULL; p = p->next) + if (p->count) + { + h->non_got_ref = 1; + goto keep; + } + /* Support garbage collection against STT_GNU_IFUNC symbols. */ if (h->plt.refcount <= 0 && h->got.refcount <= 0) { - /* When building shared library, we need to handle the case - where it is marked with regular reference, but not non-GOT - reference. It may happen if we didn't see STT_GNU_IFUNC - symbol at the time when checking relocations. */ - if (info->shared - && !h->non_got_ref - && h->ref_regular) - for (p = *head; p != NULL; p = p->next) - if (p->count) - { - h->non_got_ref = 1; - goto keep; - } - h->got = htab->init_got_offset; h->plt = htab->init_plt_offset; *head = NULL; @@ -241,7 +193,7 @@ keep: /* If this is the first .plt entry, make room for the special first entry. */ if (plt->size == 0) - plt->size += plt_entry_size; + plt->size += plt_header_size; } else { @@ -321,3 +273,128 @@ keep: return TRUE; } + +/* Similar to _bfd_elf_get_synthetic_symtab, optimized for unsorted PLT + entries. PLT is the PLT section. PLT_SYM_VAL is a function pointer + which returns an array of PLT entry symbol values. */ + +long +_bfd_elf_ifunc_get_synthetic_symtab + (bfd *abfd, long symcount ATTRIBUTE_UNUSED, + asymbol **syms ATTRIBUTE_UNUSED, long dynsymcount, asymbol **dynsyms, + asymbol **ret, asection *plt, + bfd_vma *(*get_plt_sym_val) (bfd *, asymbol **, asection *, asection *)) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + asection *relplt; + asymbol *s; + const char *relplt_name; + bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); + arelent *p; + long count, i, n; + size_t size; + Elf_Internal_Shdr *hdr; + char *names; + bfd_vma *plt_sym_val; + + *ret = NULL; + + if (plt == NULL) + return 0; + + if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) + return 0; + + if (dynsymcount <= 0) + return 0; + + relplt_name = bed->relplt_name; + if (relplt_name == NULL) + relplt_name = bed->rela_plts_and_copies_p ? ".rela.plt" : ".rel.plt"; + relplt = bfd_get_section_by_name (abfd, relplt_name); + if (relplt == NULL) + return 0; + + hdr = &elf_section_data (relplt)->this_hdr; + if (hdr->sh_link != elf_dynsymtab (abfd) + || (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA)) + return 0; + + slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; + if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) + return -1; + + count = relplt->size / hdr->sh_entsize; + size = count * sizeof (asymbol); + p = relplt->relocation; + for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel) + { + size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); + if (p->addend != 0) + { +#ifdef BFD64 + size += sizeof ("+0x") - 1 + 8 + 8 * (bed->s->elfclass == ELFCLASS64); +#else + size += sizeof ("+0x") - 1 + 8; +#endif + } + } + + plt_sym_val = get_plt_sym_val (abfd, dynsyms, plt, relplt); + if (plt_sym_val == NULL) + return -1; + + s = *ret = (asymbol *) bfd_malloc (size); + if (s == NULL) + { + free (plt_sym_val); + return -1; + } + + names = (char *) (s + count); + p = relplt->relocation; + n = 0; + for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel) + { + size_t len; + bfd_vma addr; + + addr = plt_sym_val[i]; + if (addr == (bfd_vma) -1) + continue; + + *s = **p->sym_ptr_ptr; + /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since + we are defining a symbol, ensure one of them is set. */ + if ((s->flags & BSF_LOCAL) == 0) + s->flags |= BSF_GLOBAL; + s->flags |= BSF_SYNTHETIC; + s->section = plt; + s->value = addr - plt->vma; + s->name = names; + s->udata.p = NULL; + len = strlen ((*p->sym_ptr_ptr)->name); + memcpy (names, (*p->sym_ptr_ptr)->name, len); + names += len; + if (p->addend != 0) + { + char buf[30], *a; + + memcpy (names, "+0x", sizeof ("+0x") - 1); + names += sizeof ("+0x") - 1; + bfd_sprintf_vma (abfd, buf, p->addend); + for (a = buf; *a == '0'; ++a) + ; + len = strlen (a); + memcpy (names, a, len); + names += len; + } + memcpy (names, "@plt", sizeof ("@plt")); + names += sizeof ("@plt"); + ++s, ++n; + } + + free (plt_sym_val); + + return n; +} diff --git a/contrib/gdb-7/bfd/elf-linux-psinfo.h b/contrib/gdb-7/bfd/elf-linux-psinfo.h index c9652844ea..dbaef92de8 100644 --- a/contrib/gdb-7/bfd/elf-linux-psinfo.h +++ b/contrib/gdb-7/bfd/elf-linux-psinfo.h @@ -1,5 +1,5 @@ /* Definitions for PRPSINFO structures under ELF on GNU/Linux. - Copyright 2013 Free Software Foundation, Inc. + Copyright (C) 2013-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. diff --git a/contrib/gdb-7/bfd/elf-nacl.c b/contrib/gdb-7/bfd/elf-nacl.c index 39ffb5d788..df41ee2a67 100644 --- a/contrib/gdb-7/bfd/elf-nacl.c +++ b/contrib/gdb-7/bfd/elf-nacl.c @@ -1,5 +1,5 @@ /* Native Client support for ELF - Copyright 2012 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -20,6 +20,7 @@ #include "sysdep.h" #include "bfd.h" +#include "libbfd.h" #include "elf-bfd.h" #include "elf-nacl.h" #include "elf/common.h" @@ -33,35 +34,32 @@ segment_executable (struct elf_segment_map *seg) else { /* The p_flags value has not been computed yet, - so we have to look through the sections. */ + so we have to look through the sections. */ unsigned int i; for (i = 0; i < seg->count; ++i) - if (seg->sections[i]->flags & SEC_CODE) - return TRUE; + if (seg->sections[i]->flags & SEC_CODE) + return TRUE; } return FALSE; } /* Determine if this segment is eligible to receive the file and program - headers. It must be read-only, non-executable, and have contents. + headers. It must be read-only and non-executable. Its first section must start far enough past the page boundary to allow space for the headers. */ static bfd_boolean segment_eligible_for_headers (struct elf_segment_map *seg, - bfd_vma maxpagesize, bfd_vma sizeof_headers) + bfd_vma minpagesize, bfd_vma sizeof_headers) { - bfd_boolean any_contents = FALSE; unsigned int i; - if (seg->count == 0 || seg->sections[0]->lma % maxpagesize < sizeof_headers) + if (seg->count == 0 || seg->sections[0]->lma % minpagesize < sizeof_headers) return FALSE; for (i = 0; i < seg->count; ++i) { if ((seg->sections[i]->flags & (SEC_CODE|SEC_READONLY)) != SEC_READONLY) - return FALSE; - if (seg->sections[i]->flags & SEC_HAS_CONTENTS) - any_contents = TRUE; + return FALSE; } - return any_contents; + return TRUE; } @@ -71,69 +69,154 @@ segment_eligible_for_headers (struct elf_segment_map *seg, bfd_boolean nacl_modify_segment_map (bfd *abfd, struct bfd_link_info *info) { + const struct elf_backend_data *const bed = get_elf_backend_data (abfd); struct elf_segment_map **m = &elf_seg_map (abfd); struct elf_segment_map **first_load = NULL; struct elf_segment_map **last_load = NULL; bfd_boolean moved_headers = FALSE; - int sizeof_headers = info == NULL ? 0 : bfd_sizeof_headers (abfd, info); - bfd_vma maxpagesize = get_elf_backend_data (abfd)->maxpagesize; + int sizeof_headers; if (info != NULL && info->user_phdrs) /* The linker script used PHDRS explicitly, so don't change what the user asked for. */ return TRUE; + if (info != NULL) + /* We're doing linking, so evalute SIZEOF_HEADERS as in a linker script. */ + sizeof_headers = bfd_sizeof_headers (abfd, info); + else + { + /* We're not doing linking, so this is objcopy or suchlike. + We just need to collect the size of the existing headers. */ + struct elf_segment_map *seg; + sizeof_headers = bed->s->sizeof_ehdr; + for (seg = *m; seg != NULL; seg = seg->next) + sizeof_headers += bed->s->sizeof_phdr; + } + while (*m != NULL) { struct elf_segment_map *seg = *m; if (seg->p_type == PT_LOAD) - { - /* First, we're just finding the earliest PT_LOAD. - By the normal rules, this will be the lowest-addressed one. - We only have anything interesting to do if it's executable. */ - last_load = m; - if (first_load == NULL) - { - if (!segment_executable (*m)) - return TRUE; - first_load = m; - } - /* Now that we've noted the first PT_LOAD, we're looking for - the first non-executable PT_LOAD with a nonempty p_filesz. */ - else if (!moved_headers - && segment_eligible_for_headers (seg, maxpagesize, - sizeof_headers)) - { - /* This is the one we were looking for! - - First, clear the flags on previous segments that - say they include the file header and phdrs. */ - struct elf_segment_map *prevseg; - for (prevseg = *first_load; - prevseg != seg; - prevseg = prevseg->next) - if (prevseg->p_type == PT_LOAD) - { - prevseg->includes_filehdr = 0; - prevseg->includes_phdrs = 0; - } - - /* This segment will include those headers instead. */ - seg->includes_filehdr = 1; - seg->includes_phdrs = 1; - - moved_headers = TRUE; - } - } - + { + bfd_boolean executable = segment_executable (seg); + + if (executable + && seg->count > 0 + && seg->sections[0]->vma % bed->minpagesize == 0) + { + asection *lastsec = seg->sections[seg->count - 1]; + bfd_vma end = lastsec->vma + lastsec->size; + if (end % bed->minpagesize != 0) + { + /* This is an executable segment that starts on a page + boundary but does not end on a page boundary. 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. + + To accomplish this, we must fake out the code in + assign_file_positions_for_load_sections (elf.c) so + that it advances past the rest of the final page, + rather than trying to put the next (unaligned, or + unallocated) section. We do this by appending a + dummy section record to this element in the segment + map. No such output section ever actually exists, + but this gets the layout logic to advance the file + positions past this partial page. Since we are + lying to BFD like this, nothing will ever know to + write the section contents. So we do that by hand + after the fact, in nacl_final_write_processing, below. */ + + struct elf_segment_map *newseg; + asection *sec; + struct bfd_elf_section_data *secdata; + + BFD_ASSERT (!seg->p_size_valid); + + secdata = bfd_zalloc (abfd, sizeof *secdata); + if (secdata == NULL) + return FALSE; + + sec = bfd_zalloc (abfd, sizeof *sec); + if (sec == NULL) + return FALSE; + + /* Fill in only the fields that actually affect the logic + in assign_file_positions_for_load_sections. */ + sec->vma = end; + sec->lma = lastsec->lma + lastsec->size; + sec->size = bed->minpagesize - (end % bed->minpagesize); + sec->flags = (SEC_ALLOC | SEC_LOAD + | SEC_READONLY | SEC_CODE | SEC_LINKER_CREATED); + sec->used_by_bfd = secdata; + + secdata->this_hdr.sh_type = SHT_PROGBITS; + secdata->this_hdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; + secdata->this_hdr.sh_addr = sec->vma; + secdata->this_hdr.sh_size = sec->size; + + newseg = bfd_alloc (abfd, + sizeof *newseg + ((seg->count + 1) + * sizeof (asection *))); + if (newseg == NULL) + return FALSE; + memcpy (newseg, seg, + sizeof *newseg + (seg->count * sizeof (asection *))); + newseg->sections[newseg->count++] = sec; + *m = seg = newseg; + } + } + + /* First, we're just finding the earliest PT_LOAD. + By the normal rules, this will be the lowest-addressed one. + We only have anything interesting to do if it's executable. */ + last_load = m; + if (first_load == NULL) + { + if (!executable) + goto next; + first_load = m; + } + /* Now that we've noted the first PT_LOAD, we're looking for + the first non-executable PT_LOAD with a nonempty p_filesz. */ + else if (!moved_headers + && segment_eligible_for_headers (seg, bed->minpagesize, + sizeof_headers)) + { + /* This is the one we were looking for! + + First, clear the flags on previous segments that + say they include the file header and phdrs. */ + struct elf_segment_map *prevseg; + for (prevseg = *first_load; + prevseg != seg; + prevseg = prevseg->next) + if (prevseg->p_type == PT_LOAD) + { + prevseg->includes_filehdr = 0; + prevseg->includes_phdrs = 0; + } + + /* This segment will include those headers instead. */ + seg->includes_filehdr = 1; + seg->includes_phdrs = 1; + + moved_headers = TRUE; + } + } + + next: m = &seg->next; } if (first_load != last_load && moved_headers) { /* Now swap the first and last PT_LOAD segments' - positions in segment_map. */ + positions in segment_map. */ struct elf_segment_map *first = *first_load; struct elf_segment_map *last = *last_load; *first_load = first->next; @@ -164,7 +247,7 @@ nacl_modify_program_headers (bfd *abfd, struct bfd_link_info *info) while (*m != NULL) { if ((*m)->p_type == PT_LOAD && (*m)->includes_filehdr) - break; + break; m = &(*m)->next; ++p; @@ -178,47 +261,95 @@ nacl_modify_program_headers (bfd *abfd, struct bfd_link_info *info) Elf_Internal_Phdr *next_load_phdr = NULL; /* Now move past that first one and find the PT_LOAD that should be - before it by address order. */ + before it by address order. */ m = &(*m)->next; ++p; - while ((*m) != NULL) - { - if (p->p_type == PT_LOAD && p->p_vaddr < first_load_phdr->p_vaddr) - { - next_load_seg = m; - next_load_phdr = p; - break; - } + while (*m != NULL) + { + if (p->p_type == PT_LOAD && p->p_vaddr < first_load_phdr->p_vaddr) + { + next_load_seg = m; + next_load_phdr = p; + break; + } - m = &(*m)->next; - ++p; - } + m = &(*m)->next; + ++p; + } /* Swap their positions in the segment_map back to how they used to be. - The phdrs have already been set up by now, so we have to slide up - the earlier ones to insert the one that should be first. */ + The phdrs have already been set up by now, so we have to slide up + the earlier ones to insert the one that should be first. */ if (next_load_seg != NULL) - { - Elf_Internal_Phdr move_phdr; - struct elf_segment_map *first_seg = *first_load_seg; - struct elf_segment_map *next_seg = *next_load_seg; - struct elf_segment_map *first_next = first_seg->next; - struct elf_segment_map *next_next = next_seg->next; - - first_seg->next = next_next; - *first_load_seg = next_seg; - - next_seg->next = first_next; - *next_load_seg = first_seg; - - move_phdr = *next_load_phdr; - memmove (first_load_phdr + 1, first_load_phdr, - (next_load_phdr - first_load_phdr) * sizeof move_phdr); - *first_load_phdr = move_phdr; - } + { + Elf_Internal_Phdr move_phdr; + struct elf_segment_map *first_seg = *first_load_seg; + struct elf_segment_map *next_seg = *next_load_seg; + struct elf_segment_map *first_next = first_seg->next; + struct elf_segment_map *next_next = next_seg->next; + + if (next_load_seg == &first_seg->next) + { + *first_load_seg = next_seg; + next_seg->next = first_seg; + first_seg->next = next_next; + } + else + { + *first_load_seg = first_next; + *next_load_seg = next_next; + + first_seg->next = *next_load_seg; + *next_load_seg = first_seg; + + next_seg->next = *first_load_seg; + *first_load_seg = next_seg; + } + + move_phdr = *next_load_phdr; + memmove (first_load_phdr + 1, first_load_phdr, + (next_load_phdr - first_load_phdr) * sizeof move_phdr); + *first_load_phdr = move_phdr; + } } return TRUE; } + +void +nacl_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) +{ + struct elf_segment_map *seg; + for (seg = elf_seg_map (abfd); seg != NULL; seg = seg->next) + if (seg->p_type == PT_LOAD + && seg->count > 1 + && seg->sections[seg->count - 1]->owner == NULL) + { + /* This is a fake section added in nacl_modify_segment_map, above. + It's not a real BFD section, so nothing wrote its contents. + Now write out its contents. */ + + asection *sec = seg->sections[seg->count - 1]; + char *fill; + + BFD_ASSERT (sec->flags & SEC_LINKER_CREATED); + BFD_ASSERT (sec->flags & SEC_CODE); + BFD_ASSERT (sec->size > 0); + + fill = abfd->arch_info->fill (sec->size, bfd_big_endian (abfd), TRUE); + + if (fill == NULL + || bfd_seek (abfd, sec->filepos, SEEK_SET) != 0 + || bfd_bwrite (fill, sec->size, abfd) != sec->size) + { + /* We don't have a proper way to report an error here. So + instead fudge things so that elf_write_shdrs_and_ehdr will + fail. */ + elf_elfheader (abfd)->e_shoff = (file_ptr) -1; + } + + free (fill); + } +} diff --git a/contrib/gdb-7/bfd/elf-nacl.h b/contrib/gdb-7/bfd/elf-nacl.h index 417c7e38e6..6b84298fa6 100644 --- a/contrib/gdb-7/bfd/elf-nacl.h +++ b/contrib/gdb-7/bfd/elf-nacl.h @@ -1,5 +1,5 @@ /* Native Client support for ELF - Copyright 2012 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -22,3 +22,4 @@ bfd_boolean nacl_modify_segment_map (bfd *, struct bfd_link_info *); bfd_boolean nacl_modify_program_headers (bfd *, struct bfd_link_info *); +void nacl_final_write_processing (bfd *, bfd_boolean linker); diff --git a/contrib/gdb-7/bfd/elf-strtab.c b/contrib/gdb-7/bfd/elf-strtab.c index 61cedaedcc..4d38e04e9c 100644 --- a/contrib/gdb-7/bfd/elf-strtab.c +++ b/contrib/gdb-7/bfd/elf-strtab.c @@ -1,6 +1,5 @@ /* ELF strtab with GC and suffix merging support. - Copyright 2001, 2002, 2003, 2005, 2006, 2007, 2008 - Free Software Foundation, Inc. + Copyright (C) 2001-2015 Free Software Foundation, Inc. Written by Jakub Jelinek . This file is part of BFD, the Binary File Descriptor library. diff --git a/contrib/gdb-7/bfd/elf-vxworks.c b/contrib/gdb-7/bfd/elf-vxworks.c index bb9dbbbafa..acc25c0444 100644 --- a/contrib/gdb-7/bfd/elf-vxworks.c +++ b/contrib/gdb-7/bfd/elf-vxworks.c @@ -1,5 +1,5 @@ /* VxWorks support for ELF - Copyright 2005, 2006, 2007, 2009, 2012 Free Software Foundation, Inc. + Copyright (C) 2005-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. diff --git a/contrib/gdb-7/bfd/elf-vxworks.h b/contrib/gdb-7/bfd/elf-vxworks.h index 4a9ed1d8e9..7bed0a87d7 100644 --- a/contrib/gdb-7/bfd/elf-vxworks.h +++ b/contrib/gdb-7/bfd/elf-vxworks.h @@ -1,5 +1,5 @@ /* VxWorks support for ELF - Copyright 2005, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 2005-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. diff --git a/contrib/gdb-7/bfd/elf.c b/contrib/gdb-7/bfd/elf.c index 3ba7e5f11a..98460467d0 100644 --- a/contrib/gdb-7/bfd/elf.c +++ b/contrib/gdb-7/bfd/elf.c @@ -1,6 +1,6 @@ /* ELF executable support for BFD. - Copyright 1993-2013 Free Software Foundation, Inc. + Copyright (C) 1993-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -51,7 +51,7 @@ SECTION static int elf_sort_sections (const void *, const void *); static bfd_boolean assign_file_positions_except_relocs (bfd *, struct bfd_link_info *); static bfd_boolean prep_headers (bfd *); -static bfd_boolean swap_out_syms (bfd *, struct bfd_strtab_hash **, int) ; +static bfd_boolean swap_out_syms (bfd *, struct elf_strtab_hash **, int) ; static bfd_boolean elf_read_notes (bfd *, file_ptr, bfd_size_type) ; static bfd_boolean elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset); @@ -297,13 +297,14 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) /* Allocate and clear an extra byte at the end, to prevent crashes in case the string table is not terminated. */ if (shstrtabsize + 1 <= 1 - || (shstrtab = (bfd_byte *) bfd_alloc (abfd, shstrtabsize + 1)) == NULL - || bfd_seek (abfd, offset, SEEK_SET) != 0) + || bfd_seek (abfd, offset, SEEK_SET) != 0 + || (shstrtab = (bfd_byte *) bfd_alloc (abfd, shstrtabsize + 1)) == NULL) shstrtab = NULL; else if (bfd_bread (shstrtab, shstrtabsize, abfd) != shstrtabsize) { if (bfd_get_error () != bfd_error_system_call) bfd_set_error (bfd_error_file_truncated); + bfd_release (abfd, shstrtab); shstrtab = NULL; /* Once we've failed to read it, make sure we don't keep trying. Otherwise, we'll keep allocating space for @@ -332,9 +333,19 @@ bfd_elf_string_from_elf_section (bfd *abfd, hdr = elf_elfsections (abfd)[shindex]; - if (hdr->contents == NULL - && bfd_elf_get_str_section (abfd, shindex) == NULL) - return NULL; + if (hdr->contents == NULL) + { + if (hdr->sh_type != SHT_STRTAB && hdr->sh_type < SHT_LOOS) + { + /* PR 17512: file: f057ec89. */ + _bfd_error_handler (_("%B: attempt to load strings from a non-string section (number %d)"), + abfd, shindex); + return NULL; + } + + if (bfd_elf_get_str_section (abfd, shindex) == NULL) + return NULL; + } if (strindex >= hdr->sh_size) { @@ -608,9 +619,10 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) if (shdr->contents == NULL) { _bfd_error_handler - (_("%B: Corrupt size field in group section header: 0x%lx"), abfd, shdr->sh_size); + (_("%B: corrupt size field in group section header: 0x%lx"), abfd, shdr->sh_size); bfd_set_error (bfd_error_bad_value); - return FALSE; + -- num_group; + continue; } memset (shdr->contents, 0, amt); @@ -618,7 +630,16 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) if (bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0 || (bfd_bread (shdr->contents, shdr->sh_size, abfd) != shdr->sh_size)) - return FALSE; + { + _bfd_error_handler + (_("%B: invalid size field in group section header: 0x%lx"), abfd, shdr->sh_size); + bfd_set_error (bfd_error_bad_value); + -- num_group; + /* PR 17510: If the group contents are even partially + corrupt, do not allow any of the contents to be used. */ + memset (shdr->contents, 0, amt); + continue; + } /* Translate raw contents, a flag word followed by an array of elf section indices all in target byte order, @@ -626,6 +647,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) pointers. */ src = shdr->contents + shdr->sh_size; dest = (Elf_Internal_Group *) (shdr->contents + amt); + while (1) { unsigned int idx; @@ -651,6 +673,21 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) } } } + + /* PR 17510: Corrupt binaries might contain invalid groups. */ + if (num_group != (unsigned) elf_tdata (abfd)->num_group) + { + elf_tdata (abfd)->num_group = num_group; + + /* If all groups are invalid then fail. */ + if (num_group == 0) + { + elf_tdata (abfd)->group_sect_ptr = NULL; + elf_tdata (abfd)->num_group = num_group = -1; + (*_bfd_error_handler) (_("%B: no valid group sections found"), abfd); + bfd_set_error (bfd_error_bad_value); + } + } } } @@ -716,6 +753,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) { (*_bfd_error_handler) (_("%B: no group info for section %A"), abfd, newsect); + return FALSE; } return TRUE; } @@ -817,6 +855,31 @@ bfd_elf_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec) return elf_next_in_group (sec) != NULL; } +static char * +convert_debug_to_zdebug (bfd *abfd, const char *name) +{ + unsigned int len = strlen (name); + char *new_name = bfd_alloc (abfd, len + 2); + if (new_name == NULL) + return NULL; + new_name[0] = '.'; + new_name[1] = 'z'; + memcpy (new_name + 2, name + 1, len); + return new_name; +} + +static char * +convert_zdebug_to_debug (bfd *abfd, const char *name) +{ + unsigned int len = strlen (name); + char *new_name = bfd_alloc (abfd, len); + if (new_name == NULL) + return NULL; + new_name[0] = '.'; + memcpy (new_name + 1, name + 2, len - 1); + return new_name; +} + /* Make a BFD section from an ELF section. We store a pointer to the BFD section in the bfd_section field of the header. */ @@ -1003,27 +1066,38 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, || (name[1] == 'z' && name[7] == '_'))) { enum { nothing, compress, decompress } action = nothing; - char *new_name; + int compression_header_size; + bfd_size_type uncompressed_size; + bfd_boolean compressed + = bfd_is_section_compressed_with_header (abfd, newsect, + &compression_header_size, + &uncompressed_size); - if (bfd_is_section_compressed (abfd, newsect)) + if (compressed) { /* Compressed section. Check if we should decompress. */ if ((abfd->flags & BFD_DECOMPRESS)) action = decompress; } - else + + /* Compress the uncompressed section or convert from/to .zdebug* + section. Check if we should compress. */ + if (action == nothing) { - /* Normal section. Check if we should compress. */ - if ((abfd->flags & BFD_COMPRESS) && newsect->size != 0) + if (newsect->size != 0 + && (abfd->flags & BFD_COMPRESS) + && compression_header_size >= 0 + && uncompressed_size > 0 + && (!compressed + || ((compression_header_size > 0) + != ((abfd->flags & BFD_COMPRESS_GABI) != 0)))) action = compress; + else + return TRUE; } - new_name = NULL; - switch (action) + if (action == compress) { - case nothing: - break; - case compress: if (!bfd_init_section_compress_status (abfd, newsect)) { (*_bfd_error_handler) @@ -1031,19 +1105,9 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, abfd, name); return FALSE; } - if (name[1] != 'z') - { - unsigned int len = strlen (name); - - new_name = bfd_alloc (abfd, len + 2); - if (new_name == NULL) - return FALSE; - new_name[0] = '.'; - new_name[1] = 'z'; - memcpy (new_name + 2, name + 1, len); - } - break; - case decompress: + } + else + { if (!bfd_init_section_decompress_status (abfd, newsect)) { (*_bfd_error_handler) @@ -1051,20 +1115,28 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, abfd, name); return FALSE; } - if (name[1] == 'z') - { - unsigned int len = strlen (name); + } - new_name = bfd_alloc (abfd, len); + if (abfd->is_linker_input) + { + if (name[1] == 'z' + && (action == decompress + || (action == compress + && (abfd->flags & BFD_COMPRESS_GABI) != 0))) + { + /* Convert section name from .zdebug_* to .debug_* so + that linker will consider this section as a debug + section. */ + char *new_name = convert_zdebug_to_debug (abfd, name); if (new_name == NULL) return FALSE; - new_name[0] = '.'; - memcpy (new_name + 1, name + 2, len - 1); + bfd_rename_section (abfd, newsect, new_name); } - break; } - if (new_name != NULL) - bfd_rename_section (abfd, newsect, new_name); + else + /* For objdump, don't rename the section. For objcopy, delay + section rename to elf_fake_sections. */ + newsect->flags |= SEC_ELF_RENAME; } return TRUE; @@ -1117,13 +1189,17 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) || bfd_get_flavour (obfd) != bfd_target_elf_flavour) return TRUE; - BFD_ASSERT (!elf_flags_init (obfd) - || (elf_elfheader (obfd)->e_flags - == elf_elfheader (ibfd)->e_flags)); + if (!elf_flags_init (obfd)) + { + elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; + elf_flags_init (obfd) = TRUE; + } elf_gp (obfd) = elf_gp (ibfd); - elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; - elf_flags_init (obfd) = TRUE; + + /* Also copy the EI_OSABI field. */ + elf_elfheader (obfd)->e_ident[EI_OSABI] = + elf_elfheader (ibfd)->e_ident[EI_OSABI]; /* Copy object attributes. */ _bfd_elf_copy_obj_attributes (ibfd, obfd); @@ -1223,8 +1299,13 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; extdyn = dynbuf; + /* PR 17512: file: 6f427532. */ + if (s->size < extdynsize) + goto error_return; extdynend = extdyn + s->size; - for (; extdyn < extdynend; extdyn += extdynsize) + /* PR 17512: file: id:000006,sig:06,src:000000,op:flip4,pos:5664. + Fix range check. */ + for (; extdyn <= (extdynend - extdynsize); extdyn += extdynsize) { Elf_Internal_Dyn dyn; const char *name = ""; @@ -1392,6 +1473,53 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) return FALSE; } +/* Get version string. */ + +const char * +_bfd_elf_get_symbol_version_string (bfd *abfd, asymbol *symbol, + bfd_boolean *hidden) +{ + const char *version_string = NULL; + if (elf_dynversym (abfd) != 0 + && (elf_dynverdef (abfd) != 0 || elf_dynverref (abfd) != 0)) + { + unsigned int vernum = ((elf_symbol_type *) symbol)->version; + + *hidden = (vernum & VERSYM_HIDDEN) != 0; + vernum &= VERSYM_VERSION; + + if (vernum == 0) + version_string = ""; + else if (vernum == 1) + version_string = "Base"; + else if (vernum <= elf_tdata (abfd)->cverdefs) + version_string = + elf_tdata (abfd)->verdef[vernum - 1].vd_nodename; + else + { + Elf_Internal_Verneed *t; + + version_string = ""; + for (t = elf_tdata (abfd)->verref; + t != NULL; + t = t->vn_nextref) + { + Elf_Internal_Vernaux *a; + + for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) + { + if (a->vna_other == vernum) + { + version_string = a->vna_nodename; + break; + } + } + } + } + } + return version_string; +} + /* Display ELF-specific fields of a symbol. */ void @@ -1418,6 +1546,8 @@ bfd_elf_print_symbol (bfd *abfd, const struct elf_backend_data *bed; unsigned char st_other; bfd_vma val; + const char *version_string; + bfd_boolean hidden; section_name = symbol->section ? symbol->section->name : "(*none*)"; @@ -1443,45 +1573,12 @@ bfd_elf_print_symbol (bfd *abfd, bfd_fprintf_vma (abfd, file, val); /* If we have version information, print it. */ - if (elf_dynversym (abfd) != 0 - && (elf_dynverdef (abfd) != 0 - || elf_dynverref (abfd) != 0)) + version_string = _bfd_elf_get_symbol_version_string (abfd, + symbol, + &hidden); + if (version_string) { - unsigned int vernum; - const char *version_string; - - vernum = ((elf_symbol_type *) symbol)->version & VERSYM_VERSION; - - if (vernum == 0) - version_string = ""; - else if (vernum == 1) - version_string = "Base"; - else if (vernum <= elf_tdata (abfd)->cverdefs) - version_string = - elf_tdata (abfd)->verdef[vernum - 1].vd_nodename; - else - { - Elf_Internal_Verneed *t; - - version_string = ""; - for (t = elf_tdata (abfd)->verref; - t != NULL; - t = t->vn_nextref) - { - Elf_Internal_Vernaux *a; - - for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) - { - if (a->vna_other == vernum) - { - version_string = a->vna_nodename; - break; - } - } - } - } - - if ((((elf_symbol_type *) symbol)->version & VERSYM_HIDDEN) == 0) + if (!hidden) fprintf (file, " %-11s", version_string); else { @@ -1513,29 +1610,6 @@ bfd_elf_print_symbol (bfd *abfd, break; } } - -/* Allocate an ELF string table--force the first byte to be zero. */ - -struct bfd_strtab_hash * -_bfd_elf_stringtab_init (void) -{ - struct bfd_strtab_hash *ret; - - ret = _bfd_stringtab_init (); - if (ret != NULL) - { - bfd_size_type loc; - - loc = _bfd_stringtab_add (ret, "", TRUE, FALSE); - BFD_ASSERT (loc == 0 || loc == (bfd_size_type) -1); - if (loc == (bfd_size_type) -1) - { - _bfd_stringtab_free (ret); - ret = NULL; - } - } - return ret; -} /* ELF .o/exec file reading */ @@ -1548,38 +1622,74 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) Elf_Internal_Ehdr *ehdr; const struct elf_backend_data *bed; const char *name; + bfd_boolean ret = TRUE; + static bfd_boolean * sections_being_created = NULL; + static bfd * sections_being_created_abfd = NULL; + static unsigned int nesting = 0; if (shindex >= elf_numsections (abfd)) return FALSE; + if (++ nesting > 3) + { + /* PR17512: A corrupt ELF binary might contain a recursive group of + sections, with each the string indicies pointing to the next in the + loop. Detect this here, by refusing to load a section that we are + already in the process of loading. We only trigger this test if + we have nested at least three sections deep as normal ELF binaries + can expect to recurse at least once. + + FIXME: It would be better if this array was attached to the bfd, + rather than being held in a static pointer. */ + + if (sections_being_created_abfd != abfd) + sections_being_created = NULL; + if (sections_being_created == NULL) + { + /* FIXME: It would be more efficient to attach this array to the bfd somehow. */ + sections_being_created = (bfd_boolean *) + bfd_zalloc (abfd, elf_numsections (abfd) * sizeof (bfd_boolean)); + sections_being_created_abfd = abfd; + } + if (sections_being_created [shindex]) + { + (*_bfd_error_handler) + (_("%B: warning: loop in section dependencies detected"), abfd); + return FALSE; + } + sections_being_created [shindex] = TRUE; + } + hdr = elf_elfsections (abfd)[shindex]; ehdr = elf_elfheader (abfd); name = bfd_elf_string_from_elf_section (abfd, ehdr->e_shstrndx, hdr->sh_name); if (name == NULL) - return FALSE; + goto fail; bed = get_elf_backend_data (abfd); switch (hdr->sh_type) { case SHT_NULL: /* Inactive section. Throw it away. */ - return TRUE; + goto success; - case SHT_PROGBITS: /* Normal section with contents. */ - case SHT_NOBITS: /* .bss section. */ - case SHT_HASH: /* .hash section. */ - case SHT_NOTE: /* .note section. */ + case SHT_PROGBITS: /* Normal section with contents. */ + case SHT_NOBITS: /* .bss section. */ + case SHT_HASH: /* .hash section. */ + case SHT_NOTE: /* .note section. */ case SHT_INIT_ARRAY: /* .init_array section. */ case SHT_FINI_ARRAY: /* .fini_array section. */ case SHT_PREINIT_ARRAY: /* .preinit_array section. */ case SHT_GNU_LIBLIST: /* .gnu.liblist section. */ case SHT_GNU_HASH: /* .gnu.hash section. */ - return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + goto success; case SHT_DYNAMIC: /* Dynamic linking information. */ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) - return FALSE; + goto fail; + if (hdr->sh_link > elf_numsections (abfd)) { /* PR 10478: Accept Solaris binaries with a sh_link @@ -1593,11 +1703,11 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) break; /* Otherwise fall through. */ default: - return FALSE; + goto fail; } } else if (elf_elfsections (abfd)[hdr->sh_link] == NULL) - return FALSE; + goto fail; else if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB) { Elf_Internal_Shdr *dynsymhdr; @@ -1626,24 +1736,26 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) } } } - break; + goto success; - case SHT_SYMTAB: /* A symbol table */ + case SHT_SYMTAB: /* A symbol table. */ if (elf_onesymtab (abfd) == shindex) - return TRUE; + goto success; if (hdr->sh_entsize != bed->s->sizeof_sym) - return FALSE; + goto fail; + if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size) { if (hdr->sh_size != 0) - return FALSE; + goto fail; /* Some assemblers erroneously set sh_info to one with a zero sh_size. ld sees this as a global symbol count of (unsigned) -1. Fix it here. */ hdr->sh_info = 0; - return TRUE; + goto success; } + BFD_ASSERT (elf_onesymtab (abfd) == 0); elf_onesymtab (abfd) = shindex; elf_tdata (abfd)->symtab_hdr = *hdr; @@ -1660,7 +1772,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) && (abfd->flags & DYNAMIC) != 0 && ! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) - return FALSE; + goto fail; /* Go looking for SHT_SYMTAB_SHNDX too, since if there is one we can't read symbols without that section loaded as well. It @@ -1686,26 +1798,29 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) break; } if (i != shindex) - return bfd_section_from_shdr (abfd, i); + ret = bfd_section_from_shdr (abfd, i); } - return TRUE; + goto success; - case SHT_DYNSYM: /* A dynamic symbol table */ + case SHT_DYNSYM: /* A dynamic symbol table. */ if (elf_dynsymtab (abfd) == shindex) - return TRUE; + goto success; if (hdr->sh_entsize != bed->s->sizeof_sym) - return FALSE; + goto fail; + if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size) { if (hdr->sh_size != 0) - return FALSE; + goto fail; + /* Some linkers erroneously set sh_info to one with a zero sh_size. ld sees this as a global symbol count of (unsigned) -1. Fix it here. */ hdr->sh_info = 0; - return TRUE; + goto success; } + BFD_ASSERT (elf_dynsymtab (abfd) == 0); elf_dynsymtab (abfd) = shindex; elf_tdata (abfd)->dynsymtab_hdr = *hdr; @@ -1714,34 +1829,38 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) /* Besides being a symbol table, we also treat this as a regular section, so that objcopy can handle it. */ - return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + goto success; - case SHT_SYMTAB_SHNDX: /* Symbol section indices when >64k sections */ + case SHT_SYMTAB_SHNDX: /* Symbol section indices when >64k sections. */ if (elf_symtab_shndx (abfd) == shindex) - return TRUE; + goto success; BFD_ASSERT (elf_symtab_shndx (abfd) == 0); elf_symtab_shndx (abfd) = shindex; elf_tdata (abfd)->symtab_shndx_hdr = *hdr; elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->symtab_shndx_hdr; - return TRUE; + goto success; - case SHT_STRTAB: /* A string table */ + case SHT_STRTAB: /* A string table. */ if (hdr->bfd_section != NULL) - return TRUE; + goto success; + if (ehdr->e_shstrndx == shindex) { elf_tdata (abfd)->shstrtab_hdr = *hdr; elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->shstrtab_hdr; - return TRUE; + goto success; } + if (elf_elfsections (abfd)[elf_onesymtab (abfd)]->sh_link == shindex) { symtab_strtab: elf_tdata (abfd)->strtab_hdr = *hdr; elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->strtab_hdr; - return TRUE; + goto success; } + if (elf_elfsections (abfd)[elf_dynsymtab (abfd)]->sh_link == shindex) { dynsymtab_strtab: @@ -1750,8 +1869,9 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) elf_elfsections (abfd)[shindex] = hdr; /* We also treat this as a regular section, so that objcopy can handle it. */ - return _bfd_elf_make_section_from_shdr (abfd, hdr, name, - shindex); + ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, + shindex); + goto success; } /* If the string table isn't one of the above, then treat it as a @@ -1769,9 +1889,9 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) { /* Prevent endless recursion on broken objects. */ if (i == shindex) - return FALSE; + goto fail; if (! bfd_section_from_shdr (abfd, i)) - return FALSE; + goto fail; if (elf_onesymtab (abfd) == i) goto symtab_strtab; if (elf_dynsymtab (abfd) == i) @@ -1779,7 +1899,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) } } } - return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + goto success; case SHT_REL: case SHT_RELA: @@ -1794,7 +1915,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if (hdr->sh_entsize != (bfd_size_type) (hdr->sh_type == SHT_REL ? bed->s->sizeof_rel : bed->s->sizeof_rela)) - return FALSE; + goto fail; /* Check for a bogus link to avoid crashing. */ if (hdr->sh_link >= num_sec) @@ -1802,8 +1923,9 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) ((*_bfd_error_handler) (_("%B: invalid link %lu for reloc section %s (index %u)"), abfd, hdr->sh_link, name, shindex)); - return _bfd_elf_make_section_from_shdr (abfd, hdr, name, - shindex); + ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, + shindex); + goto success; } /* For some incomprehensible reason Oracle distributes @@ -1844,7 +1966,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if ((elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_SYMTAB || elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_DYNSYM) && ! bfd_section_from_shdr (abfd, hdr->sh_link)) - return FALSE; + goto fail; /* If this reloc section does not use the main symbol table we don't treat it as a reloc section. BFD can't adequately @@ -1859,14 +1981,18 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) || hdr->sh_info >= num_sec || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA) - return _bfd_elf_make_section_from_shdr (abfd, hdr, name, - shindex); + { + ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, + shindex); + goto success; + } if (! bfd_section_from_shdr (abfd, hdr->sh_info)) - return FALSE; + goto fail; + target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info); if (target_sect == NULL) - return FALSE; + goto fail; esdt = elf_section_data (target_sect); if (hdr->sh_type == SHT_RELA) @@ -1874,11 +2000,13 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) else p_hdr = &esdt->rel.hdr; - BFD_ASSERT (*p_hdr == NULL); + /* PR 17512: file: 0b4f81b7. */ + if (*p_hdr != NULL) + goto fail; amt = sizeof (*hdr2); hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt); if (hdr2 == NULL) - return FALSE; + goto fail; *hdr2 = *hdr; *p_hdr = hdr2; elf_elfsections (abfd)[shindex] = hdr2; @@ -1894,46 +2022,55 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) target_sect->use_rela_p = 1; } abfd->flags |= HAS_RELOC; - return TRUE; + goto success; } case SHT_GNU_verdef: elf_dynverdef (abfd) = shindex; elf_tdata (abfd)->dynverdef_hdr = *hdr; - return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + goto success; case SHT_GNU_versym: if (hdr->sh_entsize != sizeof (Elf_External_Versym)) - return FALSE; + goto fail; + elf_dynversym (abfd) = shindex; elf_tdata (abfd)->dynversym_hdr = *hdr; - return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + goto success; case SHT_GNU_verneed: elf_dynverref (abfd) = shindex; elf_tdata (abfd)->dynverref_hdr = *hdr; - return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + goto success; case SHT_SHLIB: - return TRUE; + goto success; case SHT_GROUP: if (! IS_VALID_GROUP_SECTION_HEADER (hdr, GRP_ENTRY_SIZE)) - return FALSE; + goto fail; + if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) - return FALSE; + goto fail; + if (hdr->contents != NULL) { Elf_Internal_Group *idx = (Elf_Internal_Group *) hdr->contents; - unsigned int n_elt = hdr->sh_size / GRP_ENTRY_SIZE; + unsigned int n_elt = hdr->sh_size / sizeof (* idx); asection *s; + if (n_elt == 0) + goto fail; if (idx->flags & GRP_COMDAT) hdr->bfd_section->flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; /* We try to keep the same section order as it comes in. */ idx += n_elt; + while (--n_elt != 0) { --idx; @@ -1947,7 +2084,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) } } } - break; + goto success; default: /* Possibly an attributes section. */ @@ -1955,14 +2092,14 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) || hdr->sh_type == bed->obj_attrs_section_type) { if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) - return FALSE; + goto fail; _bfd_elf_parse_attributes (abfd, hdr); - return TRUE; + goto success; } /* Check for any processor-specific section types. */ if (bed->elf_backend_section_from_shdr (abfd, hdr, name, shindex)) - return TRUE; + goto success; if (hdr->sh_type >= SHT_LOUSER && hdr->sh_type <= SHT_HIUSER) { @@ -1974,9 +2111,12 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) "specific section `%s' [0x%8x]"), abfd, name, hdr->sh_type); else - /* Allow sections reserved for applications. */ - return _bfd_elf_make_section_from_shdr (abfd, hdr, name, - shindex); + { + /* Allow sections reserved for applications. */ + ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, + shindex); + goto success; + } } else if (hdr->sh_type >= SHT_LOPROC && hdr->sh_type <= SHT_HIPROC) @@ -1997,8 +2137,11 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) "`%s' [0x%8x]"), abfd, name, hdr->sh_type); else - /* Otherwise it should be processed. */ - return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + { + /* Otherwise it should be processed. */ + ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + goto success; + } } else /* FIXME: We should handle this section. */ @@ -2006,10 +2149,20 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) (_("%B: don't know how to handle section `%s' [0x%8x]"), abfd, name, hdr->sh_type); - return FALSE; + goto fail; } - return TRUE; + fail: + ret = FALSE; + success: + if (sections_being_created && sections_being_created_abfd == abfd) + sections_being_created [shindex] = FALSE; + if (-- nesting == 0) + { + sections_being_created = NULL; + sections_being_created_abfd = abfd; + } + return ret; } /* Return the local symbol specified by ABFD, R_SYMNDX. */ @@ -2516,19 +2669,40 @@ _bfd_elf_single_rel_hdr (asection *sec) return elf_section_data (sec)->rela.hdr; } +static bfd_boolean +_bfd_elf_set_reloc_sh_name (bfd *abfd, + Elf_Internal_Shdr *rel_hdr, + const char *sec_name, + bfd_boolean use_rela_p) +{ + char *name = (char *) bfd_alloc (abfd, + sizeof ".rela" + strlen (sec_name)); + if (name == NULL) + return FALSE; + + sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", sec_name); + rel_hdr->sh_name = + (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), name, + FALSE); + if (rel_hdr->sh_name == (unsigned int) -1) + return FALSE; + + return TRUE; +} + /* Allocate and initialize a section-header for a new reloc section, containing relocations against ASECT. It is stored in RELDATA. If USE_RELA_P is TRUE, we use RELA relocations; otherwise, we use REL relocations. */ -bfd_boolean +static bfd_boolean _bfd_elf_init_reloc_shdr (bfd *abfd, struct bfd_elf_section_reloc_data *reldata, - asection *asect, - bfd_boolean use_rela_p) + const char *sec_name, + bfd_boolean use_rela_p, + bfd_boolean delay_st_name_p) { Elf_Internal_Shdr *rel_hdr; - char *name; const struct elf_backend_data *bed = get_elf_backend_data (abfd); bfd_size_type amt; @@ -2537,15 +2711,10 @@ _bfd_elf_init_reloc_shdr (bfd *abfd, rel_hdr = bfd_zalloc (abfd, amt); reldata->hdr = rel_hdr; - amt = sizeof ".rela" + strlen (asect->name); - name = (char *) bfd_alloc (abfd, amt); - if (name == NULL) - return FALSE; - sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name); - rel_hdr->sh_name = - (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), name, - FALSE); - if (rel_hdr->sh_name == (unsigned int) -1) + if (delay_st_name_p) + rel_hdr->sh_name = (unsigned int) -1; + else if (!_bfd_elf_set_reloc_sh_name (abfd, rel_hdr, sec_name, + use_rela_p)) return FALSE; rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL; rel_hdr->sh_entsize = (use_rela_p @@ -2587,6 +2756,8 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg) struct bfd_elf_section_data *esd = elf_section_data (asect); Elf_Internal_Shdr *this_hdr; unsigned int sh_type; + const char *name = asect->name; + bfd_boolean delay_st_name_p = FALSE; if (arg->failed) { @@ -2597,12 +2768,72 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg) this_hdr = &esd->this_hdr; - this_hdr->sh_name = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), - asect->name, FALSE); - if (this_hdr->sh_name == (unsigned int) -1) + if (arg->link_info) { - arg->failed = TRUE; - return; + /* ld: compress DWARF debug sections with names: .debug_*. */ + if ((arg->link_info->compress_debug & COMPRESS_DEBUG) + && (asect->flags & SEC_DEBUGGING) + && name[1] == 'd' + && name[6] == '_') + { + /* Set SEC_ELF_COMPRESS to indicate this section should be + compressed. */ + asect->flags |= SEC_ELF_COMPRESS; + + /* If this section will be compressed, delay adding setion + name to section name section after it is compressed in + _bfd_elf_assign_file_positions_for_non_load. */ + delay_st_name_p = TRUE; + } + } + else if ((asect->flags & SEC_ELF_RENAME)) + { + /* objcopy: rename output DWARF debug section. */ + if ((abfd->flags & (BFD_DECOMPRESS | BFD_COMPRESS_GABI))) + { + /* When we decompress or compress with SHF_COMPRESSED, + convert section name from .zdebug_* to .debug_* if + needed. */ + if (name[1] == 'z') + { + char *new_name = convert_zdebug_to_debug (abfd, name); + if (new_name == NULL) + { + arg->failed = TRUE; + return; + } + name = new_name; + } + } + else if (asect->compress_status == COMPRESS_SECTION_DONE) + { + /* PR binutils/18087: Compression does not always make a + section smaller. So only rename the section when + compression has actually taken place. If input section + name is .zdebug_*, we should never compress it again. */ + char *new_name = convert_debug_to_zdebug (abfd, name); + if (new_name == NULL) + { + arg->failed = TRUE; + return; + } + BFD_ASSERT (name[1] != 'z'); + name = new_name; + } + } + + if (delay_st_name_p) + this_hdr->sh_name = (unsigned int) -1; + else + { + this_hdr->sh_name + = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), + name, FALSE); + if (this_hdr->sh_name == (unsigned int) -1) + { + arg->failed = TRUE; + return; + } } /* Don't clear sh_flags. Assembler may set additional bits. */ @@ -2616,6 +2847,15 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg) this_hdr->sh_offset = 0; this_hdr->sh_size = asect->size; this_hdr->sh_link = 0; + /* PR 17512: file: 0eb809fe, 8b0535ee. */ + if (asect->alignment_power >= (sizeof (bfd_vma) * 8) - 1) + { + (*_bfd_error_handler) + (_("%B: error: Alignment power %d of section `%A' is too big"), + abfd, asect, asect->alignment_power); + arg->failed = TRUE; + return; + } this_hdr->sh_addralign = (bfd_vma) 1 << asect->alignment_power; /* The sh_entsize and sh_info fields may have been set already by copy_private_section_data. */ @@ -2767,13 +3007,15 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg) && (arg->link_info->relocatable || arg->link_info->emitrelocations)) { if (esd->rel.count && esd->rel.hdr == NULL - && !_bfd_elf_init_reloc_shdr (abfd, &esd->rel, asect, FALSE)) + && !_bfd_elf_init_reloc_shdr (abfd, &esd->rel, name, FALSE, + delay_st_name_p)) { arg->failed = TRUE; return; } if (esd->rela.count && esd->rela.hdr == NULL - && !_bfd_elf_init_reloc_shdr (abfd, &esd->rela, asect, TRUE)) + && !_bfd_elf_init_reloc_shdr (abfd, &esd->rela, name, TRUE, + delay_st_name_p)) { arg->failed = TRUE; return; @@ -2782,8 +3024,9 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg) else if (!_bfd_elf_init_reloc_shdr (abfd, (asect->use_rela_p ? &esd->rela : &esd->rel), - asect, - asect->use_rela_p)) + name, + asect->use_rela_p, + delay_st_name_p)) arg->failed = TRUE; } @@ -2917,6 +3160,48 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg) H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc); } +/* Return the section which RELOC_SEC applies to. */ + +asection * +_bfd_elf_get_reloc_section (asection *reloc_sec) +{ + const char *name; + unsigned int type; + bfd *abfd; + + if (reloc_sec == NULL) + return NULL; + + type = elf_section_data (reloc_sec)->this_hdr.sh_type; + if (type != SHT_REL && type != SHT_RELA) + return NULL; + + /* We look up the section the relocs apply to by name. */ + name = reloc_sec->name; + if (type == SHT_REL) + name += 4; + else + name += 5; + + /* If a target needs .got.plt section, relocations in rela.plt/rel.plt + section apply to .got.plt section. */ + abfd = reloc_sec->owner; + if (get_elf_backend_data (abfd)->want_got_plt + && strcmp (name, ".plt") == 0) + { + /* .got.plt is a linker created input section. It may be mapped + to some other output section. Try two likely sections. */ + name = ".got.plt"; + reloc_sec = bfd_get_section_by_name (abfd, name); + if (reloc_sec != NULL) + return reloc_sec; + name = ".got"; + } + + reloc_sec = bfd_get_section_by_name (abfd, name); + return reloc_sec; +} + /* Assign all ELF section numbers. The dummy first section is handled here too. The link/info pointers for the standard section types are filled in here too, while we're at it. */ @@ -2926,7 +3211,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) { struct elf_obj_tdata *t = elf_tdata (abfd); asection *sec; - unsigned int section_number, secn; + unsigned int section_number; Elf_Internal_Shdr **i_shdrp; struct bfd_elf_section_data *d; bfd_boolean need_symtab; @@ -2963,11 +3248,13 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) if (d->this_hdr.sh_type != SHT_GROUP) d->this_idx = section_number++; - _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name); + if (d->this_hdr.sh_name != (unsigned int) -1) + _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name); if (d->rel.hdr) { d->rel.idx = section_number++; - _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel.hdr->sh_name); + if (d->rel.hdr->sh_name != (unsigned int) -1) + _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel.hdr->sh_name); } else d->rel.idx = 0; @@ -2975,7 +3262,8 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) if (d->rela.hdr) { d->rela.idx = section_number++; - _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rela.hdr->sh_name); + if (d->rela.hdr->sh_name != (unsigned int) -1) + _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rela.hdr->sh_name); } else d->rela.idx = 0; @@ -3013,9 +3301,6 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) return FALSE; } - _bfd_elf_strtab_finalize (elf_shstrtab (abfd)); - t->shstrtab_hdr.sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd)); - elf_numsections (abfd) = section_number; elf_elfheader (abfd)->e_shnum = section_number; @@ -3052,7 +3337,6 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) for (sec = abfd->sections; sec; sec = sec->next) { asection *s; - const char *name; d = elf_section_data (sec); @@ -3071,11 +3355,13 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) { d->rel.hdr->sh_link = elf_onesymtab (abfd); d->rel.hdr->sh_info = d->this_idx; + d->rel.hdr->sh_flags |= SHF_INFO_LINK; } if (d->rela.idx != 0) { d->rela.hdr->sh_link = elf_onesymtab (abfd); d->rela.hdr->sh_info = d->this_idx; + d->rela.hdr->sh_flags |= SHF_INFO_LINK; } /* We need to set up sh_link for SHF_LINK_ORDER. */ @@ -3154,15 +3440,12 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) if (s != NULL) d->this_hdr.sh_link = elf_section_data (s)->this_idx; - /* We look up the section the relocs apply to by name. */ - name = sec->name; - if (d->this_hdr.sh_type == SHT_REL) - name += 4; - else - name += 5; - s = bfd_get_section_by_name (abfd, name); + s = get_elf_backend_data (abfd)->get_reloc_section (sec); if (s != NULL) - d->this_hdr.sh_info = elf_section_data (s)->this_idx; + { + d->this_hdr.sh_info = elf_section_data (s)->this_idx; + d->this_hdr.sh_flags |= SHF_INFO_LINK; + } break; case SHT_STRTAB: @@ -3233,12 +3516,10 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) } } - for (secn = 1; secn < section_number; ++secn) - if (i_shdrp[secn] == NULL) - i_shdrp[secn] = i_shdrp[0]; - else - i_shdrp[secn]->sh_name = _bfd_elf_strtab_offset (elf_shstrtab (abfd), - i_shdrp[secn]->sh_name); + /* Delay setting sh_name to _bfd_elf_write_object_contents so that + _bfd_elf_assign_file_positions_for_non_load can convert DWARF + debug section name from .debug_* to .zdebug_* if needed. */ + return TRUE; } @@ -3438,7 +3719,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, const struct elf_backend_data *bed = get_elf_backend_data (abfd); struct fake_section_arg fsargs; bfd_boolean failed; - struct bfd_strtab_hash *strtab = NULL; + struct elf_strtab_hash *strtab = NULL; Elf_Internal_Shdr *shstrtab_hdr; bfd_boolean need_symtab; @@ -3453,8 +3734,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, return FALSE; /* Post process the headers if necessary. */ - if (bed->elf_backend_post_process_headers) - (*bed->elf_backend_post_process_headers) (abfd, link_info); + (*bed->elf_backend_post_process_headers) (abfd, link_info); fsargs.failed = FALSE; fsargs.link_info = link_info; @@ -3492,11 +3772,11 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, shstrtab_hdr->sh_type = SHT_STRTAB; shstrtab_hdr->sh_flags = 0; shstrtab_hdr->sh_addr = 0; - shstrtab_hdr->sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd)); + /* sh_size is set in _bfd_elf_assign_file_positions_for_non_load. */ shstrtab_hdr->sh_entsize = 0; shstrtab_hdr->sh_link = 0; shstrtab_hdr->sh_info = 0; - /* sh_offset is set in assign_file_positions_except_relocs. */ + /* sh_offset is set in _bfd_elf_assign_file_positions_for_non_load. */ shstrtab_hdr->sh_addralign = 1; if (!assign_file_positions_except_relocs (abfd, link_info)) @@ -3524,9 +3804,9 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, /* Now that we know where the .strtab section goes, write it out. */ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 - || ! _bfd_stringtab_emit (abfd, strtab)) + || ! _bfd_elf_strtab_emit (abfd, strtab)) return FALSE; - _bfd_stringtab_free (strtab); + _bfd_elf_strtab_free (strtab); } abfd->output_has_begun = TRUE; @@ -3865,6 +4145,11 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) last_size = 0; phdr_index = 0; maxpagesize = bed->maxpagesize; + /* PR 17512: file: c8455299. + Avoid divide-by-zero errors later on. + FIXME: Should we abort if the maxpagesize is zero ? */ + if (maxpagesize == 0) + maxpagesize = 1; writable = FALSE; dynsec = bfd_get_section_by_name (abfd, ".dynamic"); if (dynsec != NULL @@ -4109,11 +4394,31 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) /* Mandated PF_R. */ m->p_flags = PF_R; m->p_flags_valid = 1; + s = first_tls; for (i = 0; i < (unsigned int) tls_count; ++i) { - BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL); - m->sections[i] = first_tls; - first_tls = first_tls->next; + if ((s->flags & SEC_THREAD_LOCAL) == 0) + { + _bfd_error_handler + (_("%B: TLS sections are not adjacent:"), abfd); + s = first_tls; + i = 0; + while (i < (unsigned int) tls_count) + { + if ((s->flags & SEC_THREAD_LOCAL) != 0) + { + _bfd_error_handler (_(" TLS: %A"), s); + i++; + } + else + _bfd_error_handler (_(" non-TLS: %A"), s); + s = s->next; + } + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + m->sections[i] = s; + s = s->next; } *pm = m; @@ -4176,11 +4481,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) == (SEC_LOAD | SEC_HAS_CONTENTS)) break; - if (i == (unsigned) -1) - continue; - - if (m->sections[i]->vma + m->sections[i]->size - >= info->relro_end) + if (i != (unsigned) -1) break; } } @@ -4305,6 +4606,9 @@ elf_sort_sections (const void *arg1, const void *arg2) static file_ptr vma_page_aligned_bias (bfd_vma vma, ufile_ptr off, bfd_vma maxpagesize) { + /* PR binutils/16199: Handle an alignment of zero. */ + if (maxpagesize == 0) + maxpagesize = 1; return ((vma - off) % maxpagesize); } @@ -4781,6 +5085,7 @@ assign_file_positions_for_load_sections (bfd *abfd, p->p_flags |= PF_W; } } + off -= off_adjust; /* Check that all sections are in a PT_LOAD segment. @@ -4832,7 +5137,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd, { const struct elf_backend_data *bed = get_elf_backend_data (abfd); Elf_Internal_Shdr **i_shdrpp; - Elf_Internal_Shdr **hdrpp; + Elf_Internal_Shdr **hdrpp, **end_hdrpp; Elf_Internal_Phdr *phdrs; Elf_Internal_Phdr *p; struct elf_segment_map *m; @@ -4840,14 +5145,12 @@ assign_file_positions_for_non_load_sections (bfd *abfd, bfd_vma filehdr_vaddr, filehdr_paddr; bfd_vma phdrs_vaddr, phdrs_paddr; file_ptr off; - unsigned int num_sec; - unsigned int i; unsigned int count; i_shdrpp = elf_elfsections (abfd); - num_sec = elf_numsections (abfd); + end_hdrpp = i_shdrpp + elf_numsections (abfd); off = elf_next_file_pos (abfd); - for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++) + for (hdrpp = i_shdrpp + 1; hdrpp < end_hdrpp; hdrpp++) { Elf_Internal_Shdr *hdr; @@ -4878,9 +5181,13 @@ assign_file_positions_for_non_load_sections (bfd *abfd, } else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) && hdr->bfd_section == NULL) + || (hdr->bfd_section != NULL + && (hdr->bfd_section->flags & SEC_ELF_COMPRESS)) + /* Compress DWARF debug sections. */ || hdr == i_shdrpp[elf_onesymtab (abfd)] || hdr == i_shdrpp[elf_symtab_shndx (abfd)] - || hdr == i_shdrpp[elf_strtab_sec (abfd)]) + || hdr == i_shdrpp[elf_strtab_sec (abfd)] + || hdr == i_shdrpp[elf_shstrtab_sec (abfd)]) hdr->sh_offset = -1; else off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); @@ -4982,14 +5289,11 @@ assign_file_positions_for_non_load_sections (bfd *abfd, { if (lp->p_type == PT_LOAD && lp->p_vaddr < link_info->relro_end - && lp->p_vaddr + lp->p_filesz >= link_info->relro_end && lm->count != 0 && lm->sections[0]->vma >= link_info->relro_start) break; } - /* PR ld/14207. If the RELRO segment doesn't fit in the - LOAD segment, it should be removed. */ BFD_ASSERT (lm != NULL); } else @@ -5039,11 +5343,19 @@ assign_file_positions_for_non_load_sections (bfd *abfd, } else if (m->count != 0) { + unsigned int i; if (p->p_type != PT_LOAD && (p->p_type != PT_NOTE || bfd_get_format (abfd) != bfd_core)) { - BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs); + if (m->includes_filehdr || m->includes_phdrs) + { + /* PR 17512: file: 2195325e. */ + (*_bfd_error_handler) + (_("%B: warning: non-load segment includes file header and/or program header"), + abfd); + return FALSE; + } p->p_filesz = 0; p->p_offset = m->sections[0]->filepos; @@ -5099,7 +5411,6 @@ assign_file_positions_except_relocs (bfd *abfd, { struct elf_obj_tdata *tdata = elf_tdata (abfd); Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); - file_ptr off; const struct elf_backend_data *bed = get_elf_backend_data (abfd); if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 @@ -5109,6 +5420,7 @@ assign_file_positions_except_relocs (bfd *abfd, unsigned int num_sec = elf_numsections (abfd); Elf_Internal_Shdr **hdrpp; unsigned int i; + file_ptr off; /* Start after the ELF header. */ off = i_ehdrp->e_ehsize; @@ -5123,15 +5435,21 @@ assign_file_positions_except_relocs (bfd *abfd, hdr = *hdrpp; if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) && hdr->bfd_section == NULL) + || (hdr->bfd_section != NULL + && (hdr->bfd_section->flags & SEC_ELF_COMPRESS)) + /* Compress DWARF debug sections. */ || i == elf_onesymtab (abfd) || i == elf_symtab_shndx (abfd) - || i == elf_strtab_sec (abfd)) + || i == elf_strtab_sec (abfd) + || i == elf_shstrtab_sec (abfd)) { hdr->sh_offset = -1; } else off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); } + + elf_next_file_pos (abfd) = off; } else { @@ -5152,21 +5470,33 @@ assign_file_positions_except_relocs (bfd *abfd, return FALSE; } - /* Write out the program headers. */ - alloc = elf_program_header_size (abfd) / bed->s->sizeof_phdr; - if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0 - || bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0) - return FALSE; + /* Set e_type in ELF header to ET_EXEC for -pie -Ttext-segment=. */ + if (link_info != NULL + && link_info->executable + && link_info->shared) + { + unsigned int num_segments = elf_elfheader (abfd)->e_phnum; + Elf_Internal_Phdr *segment = elf_tdata (abfd)->phdr; + Elf_Internal_Phdr *end_segment = &segment[num_segments]; - off = elf_next_file_pos (abfd); - } + /* Find the lowest p_vaddr in PT_LOAD segments. */ + bfd_vma p_vaddr = (bfd_vma) -1; + for (; segment < end_segment; segment++) + if (segment->p_type == PT_LOAD && p_vaddr > segment->p_vaddr) + p_vaddr = segment->p_vaddr; - /* Place the section headers. */ - off = align_file_position (off, 1 << bed->s->log_file_align); - i_ehdrp->e_shoff = off; - off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize; + /* Set e_type to ET_EXEC if the lowest p_vaddr in PT_LOAD + segments is non-zero. */ + if (p_vaddr) + i_ehdrp->e_type = ET_EXEC; + } - elf_next_file_pos (abfd) = off; + /* Write out the program headers. */ + alloc = elf_program_header_size (abfd) / bed->s->sizeof_phdr; + if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0 + || bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0) + return FALSE; + } return TRUE; } @@ -5252,7 +5582,7 @@ prep_headers (bfd *abfd) elf_tdata (abfd)->shstrtab_hdr.sh_name = (unsigned int) _bfd_elf_strtab_add (shstrtab, ".shstrtab", FALSE); if (elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1 - || elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1 + || elf_tdata (abfd)->strtab_hdr.sh_name == (unsigned int) -1 || elf_tdata (abfd)->shstrtab_hdr.sh_name == (unsigned int) -1) return FALSE; @@ -5260,29 +5590,101 @@ prep_headers (bfd *abfd) } /* Assign file positions for all the reloc sections which are not part - of the loadable file image. */ + of the loadable file image, and the file position of section headers. */ -void -_bfd_elf_assign_file_positions_for_relocs (bfd *abfd) +static bfd_boolean +_bfd_elf_assign_file_positions_for_non_load (bfd *abfd) { file_ptr off; - unsigned int i, num_sec; - Elf_Internal_Shdr **shdrpp; + Elf_Internal_Shdr **shdrpp, **end_shdrpp; + Elf_Internal_Shdr *shdrp; + Elf_Internal_Ehdr *i_ehdrp; + const struct elf_backend_data *bed; off = elf_next_file_pos (abfd); - num_sec = elf_numsections (abfd); - for (i = 1, shdrpp = elf_elfsections (abfd) + 1; i < num_sec; i++, shdrpp++) + shdrpp = elf_elfsections (abfd); + end_shdrpp = shdrpp + elf_numsections (abfd); + for (shdrpp++; shdrpp < end_shdrpp; shdrpp++) { - Elf_Internal_Shdr *shdrp; - shdrp = *shdrpp; - if ((shdrp->sh_type == SHT_REL || shdrp->sh_type == SHT_RELA) - && shdrp->sh_offset == -1) - off = _bfd_elf_assign_file_position_for_section (shdrp, off, TRUE); + if (shdrp->sh_offset == -1) + { + asection *sec = shdrp->bfd_section; + bfd_boolean is_rel = (shdrp->sh_type == SHT_REL + || shdrp->sh_type == SHT_RELA); + if (is_rel + || (sec != NULL && (sec->flags & SEC_ELF_COMPRESS))) + { + if (!is_rel) + { + const char *name = sec->name; + struct bfd_elf_section_data *d; + + /* Compress DWARF debug sections. */ + if (!bfd_compress_section (abfd, sec, + shdrp->contents)) + return FALSE; + + if (sec->compress_status == COMPRESS_SECTION_DONE + && (abfd->flags & BFD_COMPRESS_GABI) == 0) + { + /* If section is compressed with zlib-gnu, convert + section name from .debug_* to .zdebug_*. */ + char *new_name + = convert_debug_to_zdebug (abfd, name); + if (new_name == NULL) + return FALSE; + name = new_name; + } + /* Add setion name to section name section. */ + if (shdrp->sh_name != (unsigned int) -1) + abort (); + shdrp->sh_name + = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), + name, FALSE); + d = elf_section_data (sec); + + /* Add reloc setion name to section name section. */ + if (d->rel.hdr + && !_bfd_elf_set_reloc_sh_name (abfd, + d->rel.hdr, + name, FALSE)) + return FALSE; + if (d->rela.hdr + && !_bfd_elf_set_reloc_sh_name (abfd, + d->rela.hdr, + name, FALSE)) + return FALSE; + + /* Update section size and contents. */ + shdrp->sh_size = sec->size; + shdrp->contents = sec->contents; + shdrp->bfd_section->contents = NULL; + } + off = _bfd_elf_assign_file_position_for_section (shdrp, + off, + TRUE); + } + } } + /* Place section name section after DWARF debug sections have been + compressed. */ + _bfd_elf_strtab_finalize (elf_shstrtab (abfd)); + shdrp = &elf_tdata (abfd)->shstrtab_hdr; + shdrp->sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd)); + off = _bfd_elf_assign_file_position_for_section (shdrp, off, TRUE); + + /* Place the section headers. */ + i_ehdrp = elf_elfheader (abfd); + bed = get_elf_backend_data (abfd); + off = align_file_position (off, 1 << bed->s->log_file_align); + i_ehdrp->e_shoff = off; + off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize; elf_next_file_pos (abfd) = off; + + return TRUE; } bfd_boolean @@ -5305,12 +5707,16 @@ _bfd_elf_write_object_contents (bfd *abfd) if (failed) return FALSE; - _bfd_elf_assign_file_positions_for_relocs (abfd); + if (!_bfd_elf_assign_file_positions_for_non_load (abfd)) + return FALSE; /* After writing the headers, we need to write the sections too... */ num_sec = elf_numsections (abfd); for (count = 1; count < num_sec; count++) { + i_shdrp[count]->sh_name + = _bfd_elf_strtab_offset (elf_shstrtab (abfd), + i_shdrp[count]->sh_name); if (bed->elf_backend_section_processing) (*bed->elf_backend_section_processing) (abfd, i_shdrp[count]); if (i_shdrp[count]->contents) @@ -5762,8 +6168,8 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) something. They are allowed by the ELF spec however, so only a warning is produced. */ if (segment->p_type == PT_LOAD) - (*_bfd_error_handler) (_("%B: warning: Empty loadable segment" - " detected, is this intentional ?\n"), + (*_bfd_error_handler) (_("\ +%B: warning: Empty loadable segment detected, is this intentional ?"), ibfd); map->count = 0; @@ -6213,7 +6619,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) phdr_included = TRUE; } - lowest_section = first_section; + lowest_section = NULL; if (section_count != 0) { unsigned int isec = 0; @@ -6226,12 +6632,14 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) if (ELF_SECTION_IN_SEGMENT (this_hdr, segment)) { map->sections[isec++] = section->output_section; - if (section->lma < lowest_section->lma) - lowest_section = section; if ((section->flags & SEC_ALLOC) != 0) { bfd_vma seg_off; + if (lowest_section == NULL + || section->lma < lowest_section->lma) + lowest_section = section; + /* Section lmas are set up from PT_LOAD header p_paddr in _bfd_elf_make_section_from_shdr. If this header has a p_paddr that disagrees @@ -6374,7 +6782,15 @@ rewrite: i++, segment++) if (segment->p_type == PT_LOAD && maxpagesize < segment->p_align) - maxpagesize = segment->p_align; + { + /* PR 17512: file: f17299af. */ + if (segment->p_align > (bfd_vma) 1 << ((sizeof (bfd_vma) * 8) - 2)) + (*_bfd_error_handler) (_("\ +%B: warning: segment alignment of 0x%llx is too large"), + ibfd, (long long) segment->p_align); + else + maxpagesize = segment->p_align; + } if (maxpagesize != get_elf_backend_data (obfd)->maxpagesize) bfd_emul_set_maxpagesize (bfd_get_target (obfd), maxpagesize); @@ -6431,6 +6847,11 @@ _bfd_elf_init_private_section_data (bfd *ibfd, elf_next_in_group (osec) = elf_next_in_group (isec); elf_section_data (osec)->group = elf_section_data (isec)->group; } + + /* If not decompress, preserve SHF_COMPRESSED. */ + if ((ibfd->flags & BFD_DECOMPRESS) == 0) + elf_section_flags (osec) |= (elf_section_flags (isec) + & SHF_COMPRESSED); } ihdr = &elf_section_data (isec)->this_hdr; @@ -6621,18 +7042,21 @@ _bfd_elf_copy_private_symbol_data (bfd *ibfd, static bfd_boolean swap_out_syms (bfd *abfd, - struct bfd_strtab_hash **sttp, + struct elf_strtab_hash **sttp, int relocatable_p) { const struct elf_backend_data *bed; int symcount; asymbol **syms; - struct bfd_strtab_hash *stt; + struct elf_strtab_hash *stt; Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Shdr *symtab_shndx_hdr; Elf_Internal_Shdr *symstrtab_hdr; + struct elf_sym_strtab *symstrtab; bfd_byte *outbound_syms; bfd_byte *outbound_shndx; + unsigned long outbound_syms_index; + unsigned long outbound_shndx_index; int idx; unsigned int num_locals; bfd_size_type amt; @@ -6642,7 +7066,7 @@ swap_out_syms (bfd *abfd, return FALSE; /* Dump out the symtabs. */ - stt = _bfd_elf_stringtab_init (); + stt = _bfd_elf_strtab_init (); if (stt == NULL) return FALSE; @@ -6658,16 +7082,29 @@ swap_out_syms (bfd *abfd, symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; symstrtab_hdr->sh_type = SHT_STRTAB; + /* Allocate buffer to swap out the .strtab section. */ + symstrtab = (struct elf_sym_strtab *) bfd_malloc ((symcount + 1) + * sizeof (*symstrtab)); + if (symstrtab == NULL) + { + _bfd_elf_strtab_free (stt); + return FALSE; + } + outbound_syms = (bfd_byte *) bfd_alloc2 (abfd, 1 + symcount, bed->s->sizeof_sym); if (outbound_syms == NULL) { - _bfd_stringtab_free (stt); +error_return: + _bfd_elf_strtab_free (stt); + free (symstrtab); return FALSE; } symtab_hdr->contents = outbound_syms; + outbound_syms_index = 0; outbound_shndx = NULL; + outbound_shndx_index = 0; symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; if (symtab_shndx_hdr->sh_name != 0) { @@ -6675,10 +7112,7 @@ swap_out_syms (bfd *abfd, outbound_shndx = (bfd_byte *) bfd_zalloc2 (abfd, 1 + symcount, sizeof (Elf_External_Sym_Shndx)); if (outbound_shndx == NULL) - { - _bfd_stringtab_free (stt); - return FALSE; - } + goto error_return; symtab_shndx_hdr->contents = outbound_shndx; symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX; @@ -6698,10 +7132,12 @@ swap_out_syms (bfd *abfd, sym.st_other = 0; sym.st_shndx = SHN_UNDEF; sym.st_target_internal = 0; - bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx); - outbound_syms += bed->s->sizeof_sym; + symstrtab[0].sym = sym; + symstrtab[0].dest_index = outbound_syms_index; + symstrtab[0].destshndx_index = outbound_shndx_index; + outbound_syms_index++; if (outbound_shndx != NULL) - outbound_shndx += sizeof (Elf_External_Sym_Shndx); + outbound_shndx_index++; } name_local_sections @@ -6709,7 +7145,7 @@ swap_out_syms (bfd *abfd, && bed->elf_backend_name_local_section_symbols (abfd)); syms = bfd_get_outsymbols (abfd); - for (idx = 0; idx < symcount; idx++) + for (idx = 0; idx < symcount;) { Elf_Internal_Sym sym; bfd_vma value = syms[idx]->value; @@ -6721,18 +7157,17 @@ swap_out_syms (bfd *abfd, && (flags & (BSF_SECTION_SYM | BSF_GLOBAL)) == BSF_SECTION_SYM) { /* Local section symbols have no name. */ - sym.st_name = 0; + sym.st_name = (unsigned long) -1; } else { - sym.st_name = (unsigned long) _bfd_stringtab_add (stt, - syms[idx]->name, - TRUE, FALSE); + /* Call _bfd_elf_strtab_offset after _bfd_elf_strtab_finalize + to get the final offset for st_name. */ + sym.st_name + = (unsigned long) _bfd_elf_strtab_add (stt, syms[idx]->name, + FALSE); if (sym.st_name == (unsigned long) -1) - { - _bfd_stringtab_free (stt); - return FALSE; - } + goto error_return; } type_ptr = elf_symbol_from (abfd, syms[idx]); @@ -6822,8 +7257,7 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"), syms[idx]->name ? syms[idx]->name : "", sec->name); bfd_set_error (bfd_error_invalid_operation); - _bfd_stringtab_free (stt); - return FALSE; + goto error_return; } shndx = _bfd_elf_section_from_bfd_section (abfd, sec2); @@ -6909,14 +7343,40 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"), sym.st_target_internal = 0; } - bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx); - outbound_syms += bed->s->sizeof_sym; + idx++; + symstrtab[idx].sym = sym; + symstrtab[idx].dest_index = outbound_syms_index; + symstrtab[idx].destshndx_index = outbound_shndx_index; + + outbound_syms_index++; if (outbound_shndx != NULL) - outbound_shndx += sizeof (Elf_External_Sym_Shndx); + outbound_shndx_index++; } + /* Finalize the .strtab section. */ + _bfd_elf_strtab_finalize (stt); + + /* Swap out the .strtab section. */ + for (idx = 0; idx <= symcount; idx++) + { + struct elf_sym_strtab *elfsym = &symstrtab[idx]; + if (elfsym->sym.st_name == (unsigned long) -1) + elfsym->sym.st_name = 0; + else + elfsym->sym.st_name = _bfd_elf_strtab_offset (stt, + elfsym->sym.st_name); + bed->s->swap_symbol_out (abfd, &elfsym->sym, + (outbound_syms + + (elfsym->dest_index + * bed->s->sizeof_sym)), + (outbound_shndx + + (elfsym->destshndx_index + * sizeof (Elf_External_Sym_Shndx)))); + } + free (symstrtab); + *sttp = stt; - symstrtab_hdr->sh_size = _bfd_stringtab_size (stt); + symstrtab_hdr->sh_size = _bfd_elf_strtab_size (stt); symstrtab_hdr->sh_type = SHT_STRTAB; symstrtab_hdr->sh_flags = 0; @@ -7120,26 +7580,30 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) hdr = &elf_tdata (abfd)->dynverref_hdr; - elf_tdata (abfd)->verref = (Elf_Internal_Verneed *) - bfd_zalloc2 (abfd, hdr->sh_info, sizeof (Elf_Internal_Verneed)); - if (elf_tdata (abfd)->verref == NULL) - goto error_return; - - elf_tdata (abfd)->cverrefs = hdr->sh_info; - - contents = (bfd_byte *) bfd_malloc (hdr->sh_size); - if (contents == NULL) + if (hdr->sh_info == 0 || hdr->sh_size < sizeof (Elf_External_Verneed)) { +error_return_bad_verref: + (*_bfd_error_handler) + (_("%B: .gnu.version_r invalid entry"), abfd); + bfd_set_error (bfd_error_bad_value); error_return_verref: elf_tdata (abfd)->verref = NULL; elf_tdata (abfd)->cverrefs = 0; goto error_return; } + + contents = (bfd_byte *) bfd_malloc (hdr->sh_size); + if (contents == NULL) + goto error_return_verref; + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size) goto error_return_verref; - if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verneed)) + elf_tdata (abfd)->verref = (Elf_Internal_Verneed *) + bfd_zalloc2 (abfd, hdr->sh_info, sizeof (Elf_Internal_Verneed)); + + if (elf_tdata (abfd)->verref == NULL) goto error_return_verref; BFD_ASSERT (sizeof (Elf_External_Verneed) @@ -7161,7 +7625,7 @@ error_return_verref: bfd_elf_string_from_elf_section (abfd, hdr->sh_link, iverneed->vn_file); if (iverneed->vn_filename == NULL) - goto error_return_verref; + goto error_return_bad_verref; if (iverneed->vn_cnt == 0) iverneed->vn_auxptr = NULL; @@ -7176,7 +7640,7 @@ error_return_verref: if (iverneed->vn_aux > (size_t) (contents_end - (bfd_byte *) everneed)) - goto error_return_verref; + goto error_return_bad_verref; evernaux = ((Elf_External_Vernaux *) ((bfd_byte *) everneed + iverneed->vn_aux)); @@ -7189,36 +7653,42 @@ error_return_verref: bfd_elf_string_from_elf_section (abfd, hdr->sh_link, ivernaux->vna_name); if (ivernaux->vna_nodename == NULL) - goto error_return_verref; + goto error_return_bad_verref; + if (ivernaux->vna_other > freeidx) + freeidx = ivernaux->vna_other; + + ivernaux->vna_nextptr = NULL; + if (ivernaux->vna_next == 0) + { + iverneed->vn_cnt = j + 1; + break; + } if (j + 1 < iverneed->vn_cnt) ivernaux->vna_nextptr = ivernaux + 1; - else - ivernaux->vna_nextptr = NULL; if (ivernaux->vna_next > (size_t) (contents_end - (bfd_byte *) evernaux)) - goto error_return_verref; + goto error_return_bad_verref; evernaux = ((Elf_External_Vernaux *) ((bfd_byte *) evernaux + ivernaux->vna_next)); - - if (ivernaux->vna_other > freeidx) - freeidx = ivernaux->vna_other; } + iverneed->vn_nextref = NULL; + if (iverneed->vn_next == 0) + break; if (i + 1 < hdr->sh_info) iverneed->vn_nextref = iverneed + 1; - else - iverneed->vn_nextref = NULL; if (iverneed->vn_next > (size_t) (contents_end - (bfd_byte *) everneed)) - goto error_return_verref; + goto error_return_bad_verref; everneed = ((Elf_External_Verneed *) ((bfd_byte *) everneed + iverneed->vn_next)); } + elf_tdata (abfd)->cverrefs = i; free (contents); contents = NULL; @@ -7237,15 +7707,24 @@ error_return_verref: hdr = &elf_tdata (abfd)->dynverdef_hdr; + if (hdr->sh_info == 0 || hdr->sh_size < sizeof (Elf_External_Verdef)) + { + error_return_bad_verdef: + (*_bfd_error_handler) + (_("%B: .gnu.version_d invalid entry"), abfd); + bfd_set_error (bfd_error_bad_value); + error_return_verdef: + elf_tdata (abfd)->verdef = NULL; + elf_tdata (abfd)->cverdefs = 0; + goto error_return; + } + contents = (bfd_byte *) bfd_malloc (hdr->sh_size); if (contents == NULL) - goto error_return; + goto error_return_verdef; if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size) - goto error_return; - - if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verdef)) - goto error_return; + goto error_return_verdef; BFD_ASSERT (sizeof (Elf_External_Verdef) >= sizeof (Elf_External_Verdaux)); @@ -7263,12 +7742,17 @@ error_return_verref: { _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem); + if ((iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION)) == 0) + goto error_return_bad_verdef; if ((iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION)) > maxidx) maxidx = iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION); + if (iverdefmem.vd_next == 0) + break; + if (iverdefmem.vd_next > (size_t) (contents_end_def - (bfd_byte *) everdef)) - goto error_return; + goto error_return_bad_verdef; everdef = ((Elf_External_Verdef *) ((bfd_byte *) everdef + iverdefmem.vd_next)); @@ -7281,10 +7765,11 @@ error_return_verref: else freeidx = ++maxidx; } + elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) - bfd_zalloc2 (abfd, maxidx, sizeof (Elf_Internal_Verdef)); + bfd_zalloc2 (abfd, maxidx, sizeof (Elf_Internal_Verdef)); if (elf_tdata (abfd)->verdef == NULL) - goto error_return; + goto error_return_verdef; elf_tdata (abfd)->cverdefs = maxidx; @@ -7299,12 +7784,7 @@ error_return_verref: _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem); if ((iverdefmem.vd_ndx & VERSYM_VERSION) == 0) - { -error_return_verdef: - elf_tdata (abfd)->verdef = NULL; - elf_tdata (abfd)->cverdefs = 0; - goto error_return; - } + goto error_return_bad_verdef; iverdef = &iverdefarr[(iverdefmem.vd_ndx & VERSYM_VERSION) - 1]; memcpy (iverdef, &iverdefmem, sizeof (Elf_Internal_Verdef)); @@ -7324,7 +7804,7 @@ error_return_verdef: if (iverdef->vd_aux > (size_t) (contents_end_aux - (bfd_byte *) everdef)) - goto error_return_verdef; + goto error_return_bad_verdef; everdaux = ((Elf_External_Verdaux *) ((bfd_byte *) everdef + iverdef->vd_aux)); @@ -7337,16 +7817,20 @@ error_return_verdef: bfd_elf_string_from_elf_section (abfd, hdr->sh_link, iverdaux->vda_name); if (iverdaux->vda_nodename == NULL) - goto error_return_verdef; + goto error_return_bad_verdef; + iverdaux->vda_nextptr = NULL; + if (iverdaux->vda_next == 0) + { + iverdef->vd_cnt = j + 1; + break; + } if (j + 1 < iverdef->vd_cnt) iverdaux->vda_nextptr = iverdaux + 1; - else - iverdaux->vda_nextptr = NULL; if (iverdaux->vda_next > (size_t) (contents_end_aux - (bfd_byte *) everdaux)) - goto error_return_verdef; + goto error_return_bad_verdef; everdaux = ((Elf_External_Verdaux *) ((bfd_byte *) everdaux + iverdaux->vda_next)); @@ -7355,10 +7839,11 @@ error_return_verdef: if (iverdef->vd_cnt) iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename; + iverdef->vd_nextdef = NULL; + if (iverdef->vd_next == 0) + break; if ((size_t) (iverdef - iverdefarr) + 1 < maxidx) iverdef->vd_nextdef = iverdef + 1; - else - iverdef->vd_nextdef = NULL; everdef = ((Elf_External_Verdef *) ((bfd_byte *) everdef + iverdef->vd_next)); @@ -7401,14 +7886,13 @@ error_return_verdef: if (iverdef->vd_nodename == NULL) goto error_return_verdef; iverdef->vd_nextdef = NULL; - iverdef->vd_auxptr = (struct elf_internal_verdaux *) - bfd_alloc (abfd, sizeof (Elf_Internal_Verdaux)); + iverdef->vd_auxptr = ((struct elf_internal_verdaux *) + bfd_zalloc (abfd, sizeof (Elf_Internal_Verdaux))); if (iverdef->vd_auxptr == NULL) goto error_return_verdef; iverdaux = iverdef->vd_auxptr; iverdaux->vda_nodename = iverdef->vd_nodename; - iverdaux->vda_nextptr = NULL; } return TRUE; @@ -7423,16 +7907,12 @@ asymbol * _bfd_elf_make_empty_symbol (bfd *abfd) { elf_symbol_type *newsym; - bfd_size_type amt = sizeof (elf_symbol_type); - newsym = (elf_symbol_type *) bfd_zalloc (abfd, amt); + newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof * newsym); if (!newsym) return NULL; - else - { - newsym->symbol.the_bfd = abfd; - return &newsym->symbol; - } + newsym->symbol.the_bfd = abfd; + return &newsym->symbol; } void @@ -7469,6 +7949,47 @@ _bfd_elf_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_') return TRUE; + /* Treat assembler generated fake symbols, dollar local labels and + forward-backward labels (aka local labels) as locals. + These labels have the form: + + L0^A.* (fake symbols) + + [.]?L[0123456789]+{^A|^B}[0123456789]* (local labels) + + Versions which start with .L will have already been matched above, + so we only need to match the rest. */ + if (name[0] == 'L' && ISDIGIT (name[1])) + { + bfd_boolean ret = FALSE; + const char * p; + char c; + + for (p = name + 2; (c = *p); p++) + { + if (c == 1 || c == 2) + { + if (c == 1 && p == name + 2) + /* A fake symbol. */ + return TRUE; + + /* FIXME: We are being paranoid here and treating symbols like + L0^Bfoo as if there were non-local, on the grounds that the + assembler will never generate them. But can any symbol + containing an ASCII value in the range 1-31 ever be anything + other than some kind of local ? */ + ret = TRUE; + } + + if (! ISDIGIT (c)) + { + ret = FALSE; + break; + } + } + return ret; + } + return FALSE; } @@ -7495,163 +8016,34 @@ _bfd_elf_set_arch_mach (bfd *abfd, return bfd_default_set_arch_mach (abfd, arch, machine); } -/* Find the function to a particular section and offset, - for error reporting. */ - -static bfd_boolean -elf_find_function (bfd *abfd, - asection *section, - asymbol **symbols, - bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr) -{ - struct elf_find_function_cache - { - asection *last_section; - asymbol *func; - const char *filename; - bfd_size_type func_size; - } *cache; - - if (symbols == NULL) - return FALSE; - - cache = elf_tdata (abfd)->elf_find_function_cache; - if (cache == NULL) - { - cache = bfd_zalloc (abfd, sizeof (*cache)); - elf_tdata (abfd)->elf_find_function_cache = cache; - if (cache == NULL) - return FALSE; - } - if (cache->last_section != section - || cache->func == NULL - || offset < cache->func->value - || offset >= cache->func->value + cache->func_size) - { - asymbol *file; - bfd_vma low_func; - asymbol **p; - /* ??? Given multiple file symbols, it is impossible to reliably - choose the right file name for global symbols. File symbols are - local symbols, and thus all file symbols must sort before any - global symbols. The ELF spec may be interpreted to say that a - file symbol must sort before other local symbols, but currently - ld -r doesn't do this. So, for ld -r output, it is possible to - make a better choice of file name for local symbols by ignoring - file symbols appearing after a given local symbol. */ - enum { nothing_seen, symbol_seen, file_after_symbol_seen } state; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - - file = NULL; - low_func = 0; - state = nothing_seen; - cache->filename = NULL; - cache->func = NULL; - cache->func_size = 0; - cache->last_section = section; - - for (p = symbols; *p != NULL; p++) - { - asymbol *sym = *p; - bfd_vma code_off; - bfd_size_type size; - - if ((sym->flags & BSF_FILE) != 0) - { - file = sym; - if (state == symbol_seen) - state = file_after_symbol_seen; - continue; - } - - size = bed->maybe_function_sym (sym, section, &code_off); - if (size != 0 - && code_off <= offset - && (code_off > low_func - || (code_off == low_func - && size > cache->func_size))) - { - cache->func = sym; - cache->func_size = size; - cache->filename = NULL; - low_func = code_off; - if (file != NULL - && ((sym->flags & BSF_LOCAL) != 0 - || state != file_after_symbol_seen)) - cache->filename = bfd_asymbol_name (file); - } - if (state == nothing_seen) - state = symbol_seen; - } - } - - if (cache->func == NULL) - return FALSE; - - if (filename_ptr) - *filename_ptr = cache->filename; - if (functionname_ptr) - *functionname_ptr = bfd_asymbol_name (cache->func); - - return TRUE; -} - /* Find the nearest line to a particular section and offset, for error reporting. */ bfd_boolean _bfd_elf_find_nearest_line (bfd *abfd, - asection *section, asymbol **symbols, + asection *section, bfd_vma offset, const char **filename_ptr, const char **functionname_ptr, - unsigned int *line_ptr) -{ - return _bfd_elf_find_nearest_line_discriminator (abfd, section, symbols, - offset, filename_ptr, - functionname_ptr, - line_ptr, - NULL); -} - -bfd_boolean -_bfd_elf_find_nearest_line_discriminator (bfd *abfd, - asection *section, - asymbol **symbols, - bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr, - unsigned int *line_ptr, - unsigned int *discriminator_ptr) + unsigned int *line_ptr, + unsigned int *discriminator_ptr) { bfd_boolean found; - if (_bfd_dwarf1_find_nearest_line (abfd, section, symbols, offset, - filename_ptr, functionname_ptr, - line_ptr)) - { - if (!*functionname_ptr) - elf_find_function (abfd, section, symbols, offset, - *filename_ptr ? NULL : filename_ptr, - functionname_ptr); - - return TRUE; - } - - if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections, - section, symbols, offset, + if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset, filename_ptr, functionname_ptr, - line_ptr, discriminator_ptr, 0, - &elf_tdata (abfd)->dwarf2_find_line_info)) + line_ptr, discriminator_ptr, + dwarf_debug_sections, 0, + &elf_tdata (abfd)->dwarf2_find_line_info) + || _bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset, + filename_ptr, functionname_ptr, + line_ptr)) { if (!*functionname_ptr) - elf_find_function (abfd, section, symbols, offset, - *filename_ptr ? NULL : filename_ptr, - functionname_ptr); - + _bfd_elf_find_function (abfd, symbols, section, offset, + *filename_ptr ? NULL : filename_ptr, + functionname_ptr); return TRUE; } @@ -7666,8 +8058,8 @@ _bfd_elf_find_nearest_line_discriminator (bfd *abfd, if (symbols == NULL) return FALSE; - if (! elf_find_function (abfd, section, symbols, offset, - filename_ptr, functionname_ptr)) + if (! _bfd_elf_find_function (abfd, symbols, section, offset, + filename_ptr, functionname_ptr)) return FALSE; *line_ptr = 0; @@ -7680,20 +8072,10 @@ bfd_boolean _bfd_elf_find_line (bfd *abfd, asymbol **symbols, asymbol *symbol, const char **filename_ptr, unsigned int *line_ptr) { - return _bfd_elf_find_line_discriminator (abfd, symbols, symbol, - filename_ptr, line_ptr, - NULL); -} - -bfd_boolean -_bfd_elf_find_line_discriminator (bfd *abfd, asymbol **symbols, asymbol *symbol, - const char **filename_ptr, - unsigned int *line_ptr, - unsigned int *discriminator_ptr) -{ - return _bfd_dwarf2_find_line (abfd, symbols, symbol, - filename_ptr, line_ptr, discriminator_ptr, 0, - &elf_tdata (abfd)->dwarf2_find_line_info); + return _bfd_dwarf2_find_nearest_line (abfd, symbols, symbol, NULL, 0, + filename_ptr, NULL, line_ptr, NULL, + dwarf_debug_sections, 0, + &elf_tdata (abfd)->dwarf2_find_line_info); } /* After a call to bfd_find_nearest_line, successive calls to @@ -7752,13 +8134,27 @@ _bfd_elf_set_section_contents (bfd *abfd, bfd_size_type count) { Elf_Internal_Shdr *hdr; - bfd_signed_vma pos; + file_ptr pos; if (! abfd->output_has_begun && ! _bfd_elf_compute_section_file_positions (abfd, NULL)) return FALSE; + if (!count) + return TRUE; + hdr = &elf_section_data (section)->this_hdr; + if (hdr->sh_offset == (file_ptr) -1) + { + /* We must compress this section. Write output to the buffer. */ + unsigned char *contents = hdr->contents; + if ((offset + count) > hdr->sh_size + || (section->flags & SEC_ELF_COMPRESS) == 0 + || contents == NULL) + abort (); + memcpy (contents + offset, location, count); + return TRUE; + } pos = hdr->sh_offset + offset; if (bfd_seek (abfd, pos, SEEK_SET) != 0 || bfd_bwrite (location, count, abfd) != count) @@ -8177,6 +8573,18 @@ elfcore_grok_s390_tdb (bfd *abfd, Elf_Internal_Note *note) return elfcore_make_note_pseudosection (abfd, ".reg-s390-tdb", note); } +static bfd_boolean +elfcore_grok_s390_vxrs_low (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-s390-vxrs-low", note); +} + +static bfd_boolean +elfcore_grok_s390_vxrs_high (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-s390-vxrs-high", note); +} + static bfd_boolean elfcore_grok_arm_vfp (bfd *abfd, Elf_Internal_Note *note) { @@ -8561,6 +8969,9 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) if (note->namesz == 6 && strcmp (note->namedata, "LINUX") == 0) return elfcore_grok_xstatereg (abfd, note); + else if (note->namesz == 8 + && strcmp (note->namedata, "FreeBSD") == 0) + return elfcore_grok_xstatereg (abfd, note); else return TRUE; @@ -8641,6 +9052,20 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) else return TRUE; + case NT_S390_VXRS_LOW: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_s390_vxrs_low (abfd, note); + else + return TRUE; + + case NT_S390_VXRS_HIGH: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_s390_vxrs_high (abfd, note); + else + return TRUE; + case NT_ARM_VFP: if (note->namesz == 6 && strcmp (note->namedata, "LINUX") == 0) @@ -8707,18 +9132,18 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) static bfd_boolean elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note) { - struct elf_obj_tdata *t; + struct bfd_build_id* build_id; if (note->descsz == 0) return FALSE; - t = elf_tdata (abfd); - t->build_id = bfd_alloc (abfd, sizeof (*t->build_id) - 1 + note->descsz); - if (t->build_id == NULL) + build_id = bfd_alloc (abfd, sizeof (struct bfd_build_id) - 1 + note->descsz); + if (build_id == NULL) return FALSE; - t->build_id->size = note->descsz; - memcpy (t->build_id->data, note->descdata, note->descsz); + build_id->size = note->descsz; + memcpy (build_id->data, note->descdata, note->descsz); + abfd->build_id = build_id; return TRUE; } @@ -9286,7 +9711,7 @@ elfcore_write_lwpstatus (bfd *abfd, lwpstat.pr_lwpid = pid >> 16; lwpstat.pr_cursig = cursig; #if defined (HAVE_LWPSTATUS_T_PR_REG) - memcpy (lwpstat.pr_reg, gregs, sizeof (lwpstat.pr_reg)); + memcpy (&lwpstat.pr_reg, gregs, sizeof (lwpstat.pr_reg)); #elif defined (HAVE_LWPSTATUS_T_PR_CONTEXT) #if !defined(gregs) memcpy (lwpstat.pr_context.uc_mcontext.gregs, @@ -9366,7 +9791,11 @@ char * elfcore_write_xstatereg (bfd *abfd, char *buf, int *bufsiz, const void *xfpregs, int size) { - char *note_name = "LINUX"; + char *note_name; + if (get_elf_backend_data (abfd)->elf_osabi == ELFOSABI_FREEBSD) + note_name = "FreeBSD"; + else + note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, note_name, NT_X86_XSTATE, xfpregs, size); } @@ -9506,6 +9935,31 @@ elfcore_write_s390_tdb (bfd *abfd, note_name, NT_S390_TDB, s390_tdb, size); } +char * +elfcore_write_s390_vxrs_low (bfd *abfd, + char *buf, + int *bufsiz, + const void *s390_vxrs_low, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_S390_VXRS_LOW, s390_vxrs_low, size); +} + +char * +elfcore_write_s390_vxrs_high (bfd *abfd, + char *buf, + int *bufsiz, + const void *s390_vxrs_high, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_S390_VXRS_HIGH, + s390_vxrs_high, size); +} + char * elfcore_write_arm_vfp (bfd *abfd, char *buf, @@ -9590,6 +10044,10 @@ elfcore_write_register_note (bfd *abfd, return elfcore_write_s390_system_call (abfd, buf, bufsiz, data, size); if (strcmp (section, ".reg-s390-tdb") == 0) return elfcore_write_s390_tdb (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-s390-vxrs-low") == 0) + return elfcore_write_s390_vxrs_low (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-s390-vxrs-high") == 0) + return elfcore_write_s390_vxrs_high (abfd, buf, bufsiz, data, size); if (strcmp (section, ".reg-arm-vfp") == 0) return elfcore_write_arm_vfp (abfd, buf, bufsiz, data, size); if (strcmp (section, ".reg-aarch-tls") == 0) @@ -9637,32 +10095,38 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset) return TRUE; case bfd_core: - if (CONST_STRNEQ (in.namedata, "NetBSD-CORE")) - { - if (! elfcore_grok_netbsd_note (abfd, &in)) - return FALSE; - } - else if (CONST_STRNEQ (in.namedata, "OpenBSD")) - { - if (! elfcore_grok_openbsd_note (abfd, &in)) - return FALSE; - } - else if (CONST_STRNEQ (in.namedata, "QNX")) - { - if (! elfcore_grok_nto_note (abfd, &in)) - return FALSE; - } - else if (CONST_STRNEQ (in.namedata, "SPU/")) + { +#define GROKER_ELEMENT(S,F) {S, sizeof (S) - 1, F} + struct { - if (! elfcore_grok_spu_note (abfd, &in)) - return FALSE; + const char * string; + size_t len; + bfd_boolean (* func)(bfd *, Elf_Internal_Note *); } - else + grokers[] = { - if (! elfcore_grok_note (abfd, &in)) - return FALSE; - } - break; + GROKER_ELEMENT ("", elfcore_grok_note), + GROKER_ELEMENT ("NetBSD-CORE", elfcore_grok_netbsd_note), + GROKER_ELEMENT ( "OpenBSD", elfcore_grok_openbsd_note), + GROKER_ELEMENT ("QNX", elfcore_grok_nto_note), + GROKER_ELEMENT ("SPU/", elfcore_grok_spu_note) + }; +#undef GROKER_ELEMENT + int i; + + for (i = ARRAY_SIZE (grokers); i--;) + { + if (in.namesz >= grokers[i].len + && strncmp (in.namedata, grokers[i].string, + grokers[i].len) == 0) + { + if (! grokers[i].func (abfd, & in)) + return FALSE; + break; + } + } + break; + } case bfd_object: if (in.namesz == sizeof "GNU" && strcmp (in.namedata, "GNU") == 0) @@ -9696,10 +10160,14 @@ elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size) if (bfd_seek (abfd, offset, SEEK_SET) != 0) return FALSE; - buf = (char *) bfd_malloc (size); + buf = (char *) bfd_malloc (size + 1); if (buf == NULL) return FALSE; + /* PR 17512: file: ec08f814 + 0-termintate the buffer so that string searches will not overflow. */ + buf[size] = 0; + if (bfd_bread (buf, size, abfd) != size || !elf_parse_notes (abfd, buf, size, offset)) { @@ -9756,7 +10224,9 @@ bfd_get_elf_phdrs (bfd *abfd, void *phdrs) } enum elf_reloc_type_class -_bfd_elf_reloc_type_class (const Elf_Internal_Rela *rela ATTRIBUTE_UNUSED) +_bfd_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, + const asection *rel_sec ATTRIBUTE_UNUSED, + const Elf_Internal_Rela *rela ATTRIBUTE_UNUSED) { return reloc_class_normal; } @@ -9858,11 +10328,12 @@ bfd * bfd_elf_bfd_from_remote_memory (bfd *templ, bfd_vma ehdr_vma, + bfd_size_type size, bfd_vma *loadbasep, int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type)) { return (*get_elf_backend_data (templ)->elf_backend_bfd_from_remote_memory) - (templ, ehdr_vma, loadbasep, target_read_memory); + (templ, ehdr_vma, size, loadbasep, target_read_memory); } long @@ -9988,8 +10459,8 @@ asection _bfd_elf_large_com_section SEC_IS_COMMON, NULL, "LARGE_COMMON", 0); void -_bfd_elf_set_osabi (bfd * abfd, - struct bfd_link_info * link_info ATTRIBUTE_UNUSED) +_bfd_elf_post_process_headers (bfd * abfd, + struct bfd_link_info * link_info ATTRIBUTE_UNUSED) { Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form. */ diff --git a/contrib/gdb-7/bfd/elf32-ft32.c b/contrib/gdb-7/bfd/elf32-ft32.c new file mode 100644 index 0000000000..ea73d97371 --- /dev/null +++ b/contrib/gdb-7/bfd/elf32-ft32.c @@ -0,0 +1,380 @@ +/* ft32-specific support for 32-bit ELF. + Copyright (C) 2013-2015 Free Software Foundation, Inc. + + Copied from elf32-moxie.c which is.. + Copyright (C) 2009-2015 Free Software Foundation, Inc. + Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/ft32.h" + +/* Forward declarations. */ + +static reloc_howto_type ft32_elf_howto_table [] = +{ + /* This reloc does nothing. */ + HOWTO (R_FT32_NONE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_FT32_NONE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 32 bit absolute relocation. */ + + HOWTO (R_FT32_32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_FT32_32", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_FT32_16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_FT32_16", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_FT32_8, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_FT32_8", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x000000ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_FT32_10, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 10, /* bitsize */ + FALSE, /* pc_relative */ + 4, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_FT32_10", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x00003ff0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_FT32_20, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_FT32_20", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x000fffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_FT32_17, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 17, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_FT32_17", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x0001ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_FT32_18, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 18, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_FT32_18", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x0003ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + +}; + +/* Map BFD reloc types to FT32 ELF reloc types. */ + +struct ft32_reloc_map +{ + bfd_reloc_code_real_type bfd_reloc_val; + unsigned int ft32_reloc_val; +}; + +static const struct ft32_reloc_map ft32_reloc_map [] = +{ + { BFD_RELOC_NONE, R_FT32_NONE }, + { BFD_RELOC_32, R_FT32_20 }, + { BFD_RELOC_16, R_FT32_16 }, + { BFD_RELOC_8, R_FT32_8 }, + { BFD_RELOC_FT32_10, R_FT32_10 }, + { BFD_RELOC_FT32_20, R_FT32_20 }, + { BFD_RELOC_FT32_17, R_FT32_17 }, + { BFD_RELOC_FT32_18, R_FT32_18 }, +}; + +static reloc_howto_type * +ft32_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) +{ + unsigned int i; + + for (i = sizeof (ft32_reloc_map) / sizeof (ft32_reloc_map[0]); + --i;) + if (ft32_reloc_map [i].bfd_reloc_val == code) + return & ft32_elf_howto_table [ft32_reloc_map[i].ft32_reloc_val]; + + return NULL; +} + +static reloc_howto_type * +ft32_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) +{ + unsigned int i; + + for (i = 0; + i < sizeof (ft32_elf_howto_table) / sizeof (ft32_elf_howto_table[0]); + i++) + if (ft32_elf_howto_table[i].name != NULL + && strcasecmp (ft32_elf_howto_table[i].name, r_name) == 0) + return &ft32_elf_howto_table[i]; + + return NULL; +} + +/* Set the howto pointer for an FT32 ELF reloc. */ + +static void +ft32_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, + arelent *cache_ptr, + Elf_Internal_Rela *dst) +{ + unsigned int r_type; + + r_type = ELF32_R_TYPE (dst->r_info); + BFD_ASSERT (r_type < (unsigned int) R_FT32_max); + cache_ptr->howto = & ft32_elf_howto_table [r_type]; +} + +/* Relocate an FT32 ELF section. + + The RELOCATE_SECTION function is called by the new ELF backend linker + to handle the relocations for a section. + + The relocs are always passed as Rela structures; if the section + actually uses Rel structures, the r_addend field will always be + zero. + + This function is responsible for adjusting the section contents as + necessary, and (if using Rela relocs and generating a relocatable + output file) adjusting the reloc addend as necessary. + + This function does not have to worry about setting the reloc + address or the reloc symbol index. + + LOCAL_SYMS is a pointer to the swapped in local symbols. + + LOCAL_SECTIONS is an array giving the section in the input file + corresponding to the st_shndx field of each local symbol. + + The global hash table entry for the global symbols can be found + via elf_sym_hashes (input_bfd). + + When generating relocatable output, this function must handle + STB_LOCAL/STT_SECTION symbols specially. The output symbol is + going to be the section symbol corresponding to the output + section, which means that the addend must be adjusted + accordingly. */ + +static bfd_boolean +ft32_elf_relocate_section (bfd *output_bfd, + struct bfd_link_info *info, + bfd *input_bfd, + asection *input_section, + bfd_byte *contents, + Elf_Internal_Rela *relocs, + Elf_Internal_Sym *local_syms, + asection **local_sections) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + + symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + relend = relocs + input_section->reloc_count; + + for (rel = relocs; rel < relend; rel ++) + { + reloc_howto_type *howto; + unsigned long r_symndx; + Elf_Internal_Sym *sym; + asection *sec; + struct elf_link_hash_entry *h; + bfd_vma relocation; + bfd_reloc_status_type r; + const char *name; + int r_type; + + r_type = ELF32_R_TYPE (rel->r_info); + r_symndx = ELF32_R_SYM (rel->r_info); + howto = ft32_elf_howto_table + r_type; + h = NULL; + sym = NULL; + sec = NULL; + + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections [r_symndx]; + relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); + name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; + } + else + { + bfd_boolean unresolved_reloc, warned, ignored; + + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, + r_symndx, symtab_hdr, sym_hashes, + h, sec, relocation, + unresolved_reloc, warned, ignored); + + name = h->root.root.string; + } + + if (sec != NULL && discarded_section (sec)) + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, + rel, 1, relend, howto, 0, contents); + + if (info->relocatable) + continue; + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + + if (r != bfd_reloc_ok) + { + const char * msg = NULL; + + switch (r) + { + case bfd_reloc_overflow: + r = info->callbacks->reloc_overflow + (info, (h ? &h->root : NULL), name, howto->name, + (bfd_vma) 0, input_bfd, input_section, rel->r_offset); + break; + + case bfd_reloc_undefined: + r = info->callbacks->undefined_symbol + (info, name, input_bfd, input_section, rel->r_offset, + TRUE); + break; + + case bfd_reloc_outofrange: + msg = _("internal error: out of range error"); + break; + + case bfd_reloc_notsupported: + msg = _("internal error: unsupported relocation error"); + break; + + case bfd_reloc_dangerous: + msg = _("internal error: dangerous relocation"); + break; + + default: + msg = _("internal error: unknown error"); + break; + } + + if (msg) + r = info->callbacks->warning + (info, msg, name, input_bfd, input_section, rel->r_offset); + + if (! r) + return FALSE; + } + } + + return TRUE; +} + +#define ELF_ARCH bfd_arch_ft32 +#define ELF_MACHINE_CODE EM_FT32 +#define ELF_MAXPAGESIZE 0x1 + +#define TARGET_LITTLE_SYM ft32_elf32_vec +#define TARGET_LITTLE_NAME "elf32-ft32" + +#define elf_info_to_howto_rel NULL +#define elf_info_to_howto ft32_info_to_howto_rela +#define elf_backend_relocate_section ft32_elf_relocate_section + +#define elf_backend_can_gc_sections 1 +#define elf_backend_rela_normal 1 + +#define bfd_elf32_bfd_reloc_type_lookup ft32_reloc_type_lookup +#define bfd_elf32_bfd_reloc_name_lookup ft32_reloc_name_lookup + +#include "elf32-target.h" diff --git a/contrib/gdb-7/bfd/elf32-gen.c b/contrib/gdb-7/bfd/elf32-gen.c index 32814290db..32a83fb1bd 100644 --- a/contrib/gdb-7/bfd/elf32-gen.c +++ b/contrib/gdb-7/bfd/elf32-gen.c @@ -1,6 +1,5 @@ /* Generic support for 32-bit ELF - Copyright 1993, 1995, 1998, 1999, 2001, 2002, 2004, 2005, 2007 - Free Software Foundation, Inc. + Copyright (C) 1993-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -87,9 +86,9 @@ elf32_generic_link_add_symbols (bfd *abfd, struct bfd_link_info *info) return bfd_elf_link_add_symbols (abfd, info); } -#define TARGET_LITTLE_SYM bfd_elf32_little_generic_vec +#define TARGET_LITTLE_SYM elf32_le_vec #define TARGET_LITTLE_NAME "elf32-little" -#define TARGET_BIG_SYM bfd_elf32_big_generic_vec +#define TARGET_BIG_SYM elf32_be_vec #define TARGET_BIG_NAME "elf32-big" #define ELF_ARCH bfd_arch_unknown #define ELF_MACHINE_CODE EM_NONE diff --git a/contrib/gdb-7/bfd/elf32-i386.c b/contrib/gdb-7/bfd/elf32-i386.c index c048e58e90..92e7f72ad5 100644 --- a/contrib/gdb-7/bfd/elf32-i386.c +++ b/contrib/gdb-7/bfd/elf32-i386.c @@ -1,7 +1,5 @@ /* Intel 80386/80486-specific support for 32-bit ELF - Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 - Free Software Foundation, Inc. + Copyright (C) 1993-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -39,7 +37,7 @@ static reloc_howto_type elf_howto_table[]= { - HOWTO(R_386_NONE, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, + HOWTO(R_386_NONE, 0, 3, 0, FALSE, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_NONE", TRUE, 0x00000000, 0x00000000, FALSE), HOWTO(R_386_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, @@ -381,7 +379,9 @@ elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type) abfd, (int) r_type); indx = R_386_NONE; } - BFD_ASSERT (elf_howto_table [indx].type == r_type); + /* PR 17512: file: 0f67f69d. */ + if (elf_howto_table [indx].type != r_type) + return NULL; return &elf_howto_table[indx]; } @@ -582,6 +582,24 @@ static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = 0, 0, 0, 0 /* replaced with offset to start of .plt. */ }; +/* Entries in the GOT procedure linkage table look like this. */ + +static const bfd_byte elf_i386_got_plt_entry[8] = +{ + 0xff, 0x25, /* jmp indirect */ + 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ + 0x66, 0x90 /* xchg %ax,%ax */ +}; + +/* Entries in the PIC GOT procedure linkage table look like this. */ + +static const bfd_byte elf_i386_pic_got_plt_entry[8] = +{ + 0xff, 0xa3, /* jmp *offset(%ebx) */ + 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ + 0x66, 0x90 /* xchg %ax,%ax */ +}; + /* .eh_frame covering the .plt section. */ static const bfd_byte elf_i386_eh_frame_plt[] = @@ -738,6 +756,13 @@ struct elf_i386_link_hash_entry (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type)) unsigned char tls_type; + /* Symbol is referenced by R_386_GOTOFF relocation. */ + unsigned int gotoff_ref : 1; + + /* Information about the GOT PLT entry. Filled when there are both + GOT and PLT relocations against the same function. */ + union gotplt_union plt_got; + /* Offset of the GOTPLT entry reserved for the TLS descriptor, starting at the end of the jump table. */ bfd_vma tlsdesc_got; @@ -787,6 +812,7 @@ struct elf_i386_link_hash_table asection *sdynbss; asection *srelbss; asection *plt_eh_frame; + asection *plt_got; union { @@ -828,7 +854,7 @@ struct elf_i386_link_hash_table == I386_ELF_DATA ? ((struct elf_i386_link_hash_table *) ((p)->hash)) : NULL) #define elf_i386_compute_jump_table_size(htab) \ - ((htab)->next_tls_desc_index * 4) + ((htab)->elf.srelplt->reloc_count * 4) /* Create an entry in an i386 ELF linker hash table. */ @@ -856,6 +882,8 @@ elf_i386_link_hash_newfunc (struct bfd_hash_entry *entry, eh = (struct elf_i386_link_hash_entry *) entry; eh->dyn_relocs = NULL; eh->tls_type = GOT_UNKNOWN; + eh->gotoff_ref = 0; + eh->plt_got.offset = (bfd_vma) -1; eh->tlsdesc_got = (bfd_vma) -1; } @@ -924,11 +952,27 @@ elf_i386_get_local_sym_hash (struct elf_i386_link_hash_table *htab, ret->elf.indx = sec->id; ret->elf.dynstr_index = ELF32_R_SYM (rel->r_info); ret->elf.dynindx = -1; + ret->plt_got.offset = (bfd_vma) -1; *slot = ret; } return &ret->elf; } +/* Destroy an i386 ELF linker hash table. */ + +static void +elf_i386_link_hash_table_free (bfd *obfd) +{ + struct elf_i386_link_hash_table *htab + = (struct elf_i386_link_hash_table *) obfd->link.hash; + + if (htab->loc_hash_table) + htab_delete (htab->loc_hash_table); + if (htab->loc_hash_memory) + objalloc_free ((struct objalloc *) htab->loc_hash_memory); + _bfd_elf_link_hash_table_free (obfd); +} + /* Create an i386 ELF linker hash table. */ static struct bfd_link_hash_table * @@ -957,28 +1001,14 @@ elf_i386_link_hash_table_create (bfd *abfd) ret->loc_hash_memory = objalloc_create (); if (!ret->loc_hash_table || !ret->loc_hash_memory) { - free (ret); + elf_i386_link_hash_table_free (abfd); return NULL; } + ret->elf.root.hash_table_free = elf_i386_link_hash_table_free; return &ret->elf.root; } -/* Destroy an i386 ELF linker hash table. */ - -static void -elf_i386_link_hash_table_free (struct bfd_link_hash_table *hash) -{ - struct elf_i386_link_hash_table *htab - = (struct elf_i386_link_hash_table *) hash; - - if (htab->loc_hash_table) - htab_delete (htab->loc_hash_table); - if (htab->loc_hash_memory) - objalloc_free ((struct objalloc *) htab->loc_hash_memory); - _bfd_elf_link_hash_table_free (hash); -} - /* Create .plt, .rel.plt, .got, .got.plt, .rel.got, .dynbss, and .rel.bss sections in DYNOBJ, and set up shortcuts to them in our hash table. */ @@ -996,13 +1026,28 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) return FALSE; htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss"); - if (!info->shared) - htab->srelbss = bfd_get_linker_section (dynobj, ".rel.bss"); - - if (!htab->sdynbss - || (!info->shared && !htab->srelbss)) + if (!htab->sdynbss) abort (); + if (info->executable) + { + /* Always allow copy relocs for building executables. */ + asection *s = bfd_get_linker_section (dynobj, ".rel.bss"); + if (s == NULL) + { + const struct elf_backend_data *bed = get_elf_backend_data (dynobj); + s = bfd_make_section_anyway_with_flags (dynobj, + ".rel.bss", + (bed->dynamic_sec_flags + | SEC_READONLY)); + if (s == NULL + || ! bfd_set_section_alignment (dynobj, s, + bed->s->log_file_align)) + return FALSE; + } + htab->srelbss = s; + } + if (get_elf_i386_backend_data (dynobj)->is_vxworks && !elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2)) @@ -1075,6 +1120,10 @@ elf_i386_copy_indirect_symbol (struct bfd_link_info *info, eind->tls_type = GOT_UNKNOWN; } + /* Copy gotoff_ref so that elf_i386_adjust_dynamic_symbol will + generate a R_386_COPY reloc. */ + edir->gotoff_ref |= eind->gotoff_ref; + if (ELIMINATE_COPY_RELOCS && ind->root.type != bfd_link_hash_indirect && dir->dynamic_adjusted) @@ -1403,6 +1452,10 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd, return TRUE; } +/* Rename some of the generic section flags to better document how they + are used here. */ +#define need_convert_mov_to_lea sec_flg0 + /* Look through the relocs for a section during the first phase, and calculate needed space in the global offset table, procedure linkage table, and dynamic reloc sections. */ @@ -1419,6 +1472,7 @@ elf_i386_check_relocs (bfd *abfd, const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; asection *sreloc; + bfd_boolean use_plt_got; if (info->relocatable) return TRUE; @@ -1429,6 +1483,10 @@ elf_i386_check_relocs (bfd *abfd, if (htab == NULL) return FALSE; + use_plt_got = (!get_elf_i386_backend_data (abfd)->is_vxworks + && (get_elf_i386_backend_data (abfd) + == &elf_i386_arch_bed)); + symtab_hdr = &elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); @@ -1440,6 +1498,7 @@ elf_i386_check_relocs (bfd *abfd, unsigned int r_type; unsigned long r_symndx; struct elf_link_hash_entry *h; + struct elf_i386_link_hash_entry *eh; Elf_Internal_Sym *isym; const char *name; bfd_boolean size_reloc; @@ -1489,6 +1548,7 @@ elf_i386_check_relocs (bfd *abfd, h = (struct elf_link_hash_entry *) h->root.u.i.link; } + eh = (struct elf_i386_link_hash_entry *) h; if (h != NULL) { /* Create the ifunc sections for static executables. If we @@ -1500,11 +1560,12 @@ elf_i386_check_relocs (bfd *abfd, default: break; + case R_386_GOTOFF: + eh->gotoff_ref = 1; case R_386_32: case R_386_PC32: case R_386_PLT32: case R_386_GOT32: - case R_386_GOTOFF: if (htab->elf.dynobj == NULL) htab->elf.dynobj = abfd; if (!_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info)) @@ -1514,6 +1575,7 @@ elf_i386_check_relocs (bfd *abfd, /* It is referenced by a non-shared object. */ h->ref_regular = 1; + h->root.non_ir_ref = 1; } if (! elf_i386_tls_transition (info, abfd, sec, NULL, @@ -1755,7 +1817,7 @@ do_size: relocations we need for this symbol. */ if (h != NULL) { - head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs; + head = &eh->dyn_relocs; } else { @@ -1819,6 +1881,44 @@ do_size: default: break; } + + if (use_plt_got + && h != NULL + && h->plt.refcount > 0 + && (((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed) + || h->got.refcount > 0) + && htab->plt_got == NULL) + { + /* Create the GOT procedure linkage table. */ + unsigned int plt_got_align; + const struct elf_backend_data *bed; + + bed = get_elf_backend_data (info->output_bfd); + BFD_ASSERT (sizeof (elf_i386_got_plt_entry) == 8 + && (sizeof (elf_i386_got_plt_entry) + == sizeof (elf_i386_pic_got_plt_entry))); + plt_got_align = 3; + + if (htab->elf.dynobj == NULL) + htab->elf.dynobj = abfd; + htab->plt_got + = bfd_make_section_anyway_with_flags (htab->elf.dynobj, + ".plt.got", + (bed->dynamic_sec_flags + | SEC_ALLOC + | SEC_CODE + | SEC_LOAD + | SEC_READONLY)); + if (htab->plt_got == NULL + || !bfd_set_section_alignment (htab->elf.dynobj, + htab->plt_got, + plt_got_align)) + return FALSE; + } + + if (r_type == R_386_GOT32 + && (h == NULL || h->type != STT_GNU_IFUNC)) + sec->need_convert_mov_to_lea = 1; } return TRUE; @@ -2102,12 +2202,14 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, only references to the symbol are via the global offset table. For such cases we need not do anything here; the relocations will be handled correctly by relocate_section. */ - if (info->shared) + if (!info->executable) return TRUE; /* If there are no references to this symbol that do not use the - GOT, we don't need to generate a copy reloc. */ - if (!h->non_got_ref) + GOT nor R_386_GOTOFF relocation, we don't need to generate a copy + reloc. */ + eh = (struct elf_i386_link_hash_entry *) h; + if (!h->non_got_ref && !eh->gotoff_ref) return TRUE; /* If -z nocopyreloc was given, we won't generate them either. */ @@ -2121,14 +2223,15 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, if (htab == NULL) return FALSE; - /* If there aren't any dynamic relocs in read-only sections, then - we can keep the dynamic relocs and avoid the copy reloc. This - doesn't work on VxWorks, where we can not have dynamic relocations - (other than copy and jump slot relocations) in an executable. */ + /* If there aren't any dynamic relocs in read-only sections nor + R_386_GOTOFF relocation, then we can keep the dynamic relocs and + avoid the copy reloc. This doesn't work on VxWorks, where we can + not have dynamic relocations (other than copy and jump slot + relocations) in an executable. */ if (ELIMINATE_COPY_RELOCS + && !eh->gotoff_ref && !get_elf_i386_backend_data (info->output_bfd)->is_vxworks) { - eh = (struct elf_i386_link_hash_entry *) h; for (p = eh->dyn_relocs; p != NULL; p = p->next) { s = p->sec->output_section; @@ -2164,7 +2267,7 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, s = htab->sdynbss; - return _bfd_elf_adjust_dynamic_copy (h, s); + return _bfd_elf_adjust_dynamic_copy (info, h, s); } /* Allocate space in .plt, .got and associated reloc sections for @@ -2191,15 +2294,48 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd); + /* We can't use the GOT PLT if pointer equality is needed since + finish_dynamic_symbol won't clear symbol value and the dynamic + linker won't update the GOT slot. We will get into an infinite + loop at run-time. */ + if (htab->plt_got != NULL + && h->type != STT_GNU_IFUNC + && !h->pointer_equality_needed + && h->plt.refcount > 0 + && h->got.refcount > 0) + { + /* Don't use the regular PLT if there are both GOT and GOTPLT + reloctions. */ + h->plt.offset = (bfd_vma) -1; + + /* Use the GOT PLT. */ + eh->plt_got.refcount = 1; + } + /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it here if it is defined and referenced in a non-shared object. */ if (h->type == STT_GNU_IFUNC && h->def_regular) return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs, - plt_entry_size, 4); + plt_entry_size, + plt_entry_size, 4); else if (htab->elf.dynamic_sections_created - && h->plt.refcount > 0) + && (h->plt.refcount > 0 || eh->plt_got.refcount > 0)) { + bfd_boolean use_plt_got; + + if ((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed) + { + /* Don't use the regular PLT for DF_BIND_NOW. */ + h->plt.offset = (bfd_vma) -1; + + /* Use the GOT PLT. */ + h->got.refcount = 1; + eh->plt_got.refcount = 1; + } + + use_plt_got = eh->plt_got.refcount > 0; + /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ if (h->dynindx == -1 @@ -2213,13 +2349,18 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) { asection *s = htab->elf.splt; + asection *got_s = htab->plt_got; /* If this is the first .plt entry, make room for the special - first entry. */ + first entry. The .plt section is used by prelink to undo + prelinking for dynamic relocations. */ if (s->size == 0) - s->size += plt_entry_size; + s->size = plt_entry_size; - h->plt.offset = s->size; + if (use_plt_got) + eh->plt_got.offset = got_s->size; + else + h->plt.offset = s->size; /* If this symbol is not defined in a regular file, and we are not generating a shared library, then set the symbol to this @@ -2229,20 +2370,36 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (! info->shared && !h->def_regular) { - h->root.u.def.section = s; - h->root.u.def.value = h->plt.offset; + if (use_plt_got) + { + /* We need to make a call to the entry of the GOT PLT + instead of regular PLT entry. */ + h->root.u.def.section = got_s; + h->root.u.def.value = eh->plt_got.offset; + } + else + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } } /* Make room for this entry. */ - s->size += plt_entry_size; + if (use_plt_got) + got_s->size += sizeof (elf_i386_got_plt_entry); + else + { + s->size += plt_entry_size; - /* We also need to make an entry in the .got.plt section, which - will be placed in the .got section by the linker script. */ - htab->elf.sgotplt->size += 4; + /* We also need to make an entry in the .got.plt section, + which will be placed in the .got section by the linker + script. */ + htab->elf.sgotplt->size += 4; - /* We also need to make an entry in the .rel.plt section. */ - htab->elf.srelplt->size += sizeof (Elf32_External_Rel); - htab->elf.srelplt->reloc_count++; + /* We also need to make an entry in the .rel.plt section. */ + htab->elf.srelplt->size += sizeof (Elf32_External_Rel); + htab->elf.srelplt->reloc_count++; + } if (get_elf_i386_backend_data (info->output_bfd)->is_vxworks && !info->shared) @@ -2494,8 +2651,9 @@ elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) info->flags |= DF_TEXTREL; - if (info->warn_shared_textrel && info->shared) - info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'.\n"), + if ((info->warn_shared_textrel && info->shared) + || info->error_textrel) + info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'\n"), p->sec->owner, h->root.root.string, p->sec); @@ -2529,10 +2687,10 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec, if (!is_elf_hash_table (link_info->hash)) return FALSE; - /* Nothing to do if there are no codes, no relocations or no output. */ + /* Nothing to do if there is no need or no output. */ if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC) - || sec->reloc_count == 0 - || discarded_section (sec)) + || sec->need_convert_mov_to_lea == 0 + || bfd_is_abs_section (sec->output_section)) return TRUE; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; @@ -2579,11 +2737,10 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec, /* STT_GNU_IFUNC must keep R_386_GOT32 relocation. */ if (ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC - && bfd_get_8 (input_bfd, - contents + irel->r_offset - 2) == 0x8b) + && irel->r_offset >= 2 + && bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b) { - bfd_put_8 (output_bfd, 0x8d, - contents + irel->r_offset - 2); + bfd_put_8 (abfd, 0x8d, contents + irel->r_offset - 2); irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF); if (local_got_refcounts != NULL && local_got_refcounts[r_symndx] > 0) @@ -2608,11 +2765,10 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec, && h->type != STT_GNU_IFUNC && h != htab->elf.hdynamic && SYMBOL_REFERENCES_LOCAL (link_info, h) - && bfd_get_8 (input_bfd, - contents + irel->r_offset - 2) == 0x8b) + && irel->r_offset >= 2 + && bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b) { - bfd_put_8 (output_bfd, 0x8d, - contents + irel->r_offset - 2); + bfd_put_8 (abfd, 0x8d, contents + irel->r_offset - 2); irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF); if (h->got.refcount > 0) h->got.refcount -= 1; @@ -2686,7 +2842,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) /* Set up .got offsets for local syms, and space for local dynamic relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { bfd_signed_vma *local_got; bfd_signed_vma *end_local_got; @@ -2734,8 +2890,9 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) && (info->flags & DF_TEXTREL) == 0) { info->flags |= DF_TEXTREL; - if (info->warn_shared_textrel && info->shared) - info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'.\n"), + if ((info->warn_shared_textrel && info->shared) + || info->error_textrel) + info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'\n"), p->sec->owner, p->sec); } } @@ -2883,6 +3040,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) else if (s == htab->elf.sgotplt || s == htab->elf.iplt || s == htab->elf.igotplt + || s == htab->plt_got || s == htab->plt_eh_frame || s == htab->sdynbss) { @@ -2961,11 +3119,18 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) if (htab->elf.splt->size != 0) { - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_REL) - || !add_dynamic_entry (DT_JMPREL, 0)) + /* DT_PLTGOT is used by prelink even if there is no PLT + relocation. */ + if (!add_dynamic_entry (DT_PLTGOT, 0)) return FALSE; + + if (htab->elf.srelplt->size != 0) + { + if (!add_dynamic_entry (DT_PLTRELSZ, 0) + || !add_dynamic_entry (DT_PLTREL, DT_REL) + || !add_dynamic_entry (DT_JMPREL, 0)) + return FALSE; + } } if (relocs) @@ -3032,6 +3197,7 @@ elf_i386_always_size_sections (bfd *output_bfd, tlsbase = (struct elf_link_hash_entry *)bh; tlsbase->def_regular = 1; tlsbase->other = STV_HIDDEN; + tlsbase->root.linker_def = 1; (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE); } } @@ -3180,15 +3346,17 @@ elf_i386_relocate_section (bfd *output_bfd, reloc_howto_type *howto; unsigned long r_symndx; struct elf_link_hash_entry *h; + struct elf_i386_link_hash_entry *eh; Elf_Internal_Sym *sym; asection *sec; - bfd_vma off, offplt; + bfd_vma off, offplt, plt_offset; bfd_vma relocation; bfd_boolean unresolved_reloc; bfd_reloc_status_type r; unsigned int indx; int tls_type; bfd_vma st_size; + asection *resolved_plt; r_type = ELF32_R_TYPE (rel->r_info); if (r_type == R_386_GNU_VTINHERIT @@ -3309,11 +3477,12 @@ elf_i386_relocate_section (bfd *output_bfd, else { bfd_boolean warned ATTRIBUTE_UNUSED; + bfd_boolean ignored ATTRIBUTE_UNUSED; RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, r_symndx, symtab_hdr, sym_hashes, h, sec, relocation, - unresolved_reloc, warned); + unresolved_reloc, warned, ignored); st_size = h->size; } @@ -3591,11 +3760,11 @@ elf_i386_relocate_section (bfd *output_bfd, /* Relocation is relative to the start of the global offset table. */ - /* Check to make sure it isn't a protected function symbol - for shared library since it may not be local when used - as function address. We also need to make sure that a - symbol is defined locally. */ - if (info->shared && h) + /* Check to make sure it isn't a protected function or data + symbol for shared library since it may not be local when + used as function address or with copy relocation. We also + need to make sure that a symbol is referenced locally. */ + if (!info->executable && h) { if (!h->def_regular) { @@ -3623,14 +3792,16 @@ elf_i386_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); return FALSE; } - else if (!info->executable - && !SYMBOLIC_BIND (info, h) - && h->type == STT_FUNC + else if (!SYMBOL_REFERENCES_LOCAL (info, h) + && (h->type == STT_FUNC + || h->type == STT_OBJECT) && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) { (*_bfd_error_handler) - (_("%B: relocation R_386_GOTOFF against protected function `%s' can not be used when making a shared object"), - input_bfd, h->root.root.string); + (_("%B: relocation R_386_GOTOFF against protected %s `%s' can not be used when making a shared object"), + input_bfd, + h->type == STT_FUNC ? "function" : "data", + h->root.root.string); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -3661,7 +3832,9 @@ elf_i386_relocate_section (bfd *output_bfd, if (h == NULL) break; - if (h->plt.offset == (bfd_vma) -1 + eh = (struct elf_i386_link_hash_entry *) h; + if ((h->plt.offset == (bfd_vma) -1 + && eh->plt_got.offset == (bfd_vma) -1) || htab->elf.splt == NULL) { /* We didn't make a PLT entry for this symbol. This @@ -3670,9 +3843,20 @@ elf_i386_relocate_section (bfd *output_bfd, break; } - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset); + if (h->plt.offset != (bfd_vma) -1) + { + resolved_plt = htab->elf.splt; + plt_offset = h->plt.offset; + } + else + { + resolved_plt = htab->plt_got; + plt_offset = eh->plt_got.offset; + } + + relocation = (resolved_plt->output_section->vma + + resolved_plt->output_offset + + plt_offset); unresolved_reloc = FALSE; break; @@ -4423,6 +4607,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, struct elf_i386_link_hash_table *htab; unsigned plt_entry_size; const struct elf_i386_backend_data *abed; + struct elf_i386_link_hash_entry *eh; htab = elf_i386_hash_table (info); if (htab == NULL) @@ -4431,6 +4616,8 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, abed = get_elf_i386_backend_data (output_bfd); plt_entry_size = GET_PLT_ENTRY_SIZE (output_bfd); + eh = (struct elf_i386_link_hash_entry *) h; + if (h->plt.offset != (bfd_vma) -1) { bfd_vma plt_index; @@ -4595,21 +4782,65 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, plt->contents + h->plt.offset + abed->plt->plt_plt_offset); } + } + else if (eh->plt_got.offset != (bfd_vma) -1) + { + bfd_vma got_offset, plt_offset; + asection *plt, *got, *gotplt; + const bfd_byte *got_plt_entry; - if (!h->def_regular) + /* Offset of displacement of the indirect jump. */ + bfd_vma plt_got_offset = 2; + + /* Set the entry in the GOT procedure linkage table. */ + plt = htab->plt_got; + got = htab->elf.sgot; + gotplt = htab->elf.sgotplt; + got_offset = h->got.offset; + + if (got_offset == (bfd_vma) -1 + || plt == NULL + || got == NULL + || gotplt == NULL) + abort (); + + /* Fill in the entry in the GOT procedure linkage table. */ + if (! info->shared) { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value if there were any - relocations where pointer equality matters (this is a clue - for the dynamic linker, to make function pointer - comparisons work between an application and shared - library), otherwise set it to zero. If a function is only - called from a binary, there is no need to slow down - shared libraries because of that. */ - sym->st_shndx = SHN_UNDEF; - if (!h->pointer_equality_needed) - sym->st_value = 0; + got_plt_entry = elf_i386_got_plt_entry; + got_offset += got->output_section->vma + got->output_offset; } + else + { + got_plt_entry = elf_i386_pic_got_plt_entry; + got_offset += (got->output_section->vma + + got->output_offset + - gotplt->output_section->vma + - gotplt->output_offset); + } + + plt_offset = eh->plt_got.offset; + memcpy (plt->contents + plt_offset, got_plt_entry, + sizeof (elf_i386_got_plt_entry)); + bfd_put_32 (output_bfd, got_offset, + plt->contents + plt_offset + plt_got_offset); + } + + if (!h->def_regular + && (h->plt.offset != (bfd_vma) -1 + || eh->plt_got.offset != (bfd_vma) -1)) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value if there were any + relocations where pointer equality matters (this is a clue + for the dynamic linker, to make function pointer + comparisons work between an application and shared + library), otherwise set it to zero. If a function is only + called from a binary, there is no need to slow down + shared libraries because of that. */ + sym->st_shndx = SHN_UNDEF; + if (!h->pointer_equality_needed) + sym->st_value = 0; } if (h->got.offset != (bfd_vma) -1 @@ -4718,7 +4949,9 @@ elf_i386_finish_local_dynamic_symbol (void **slot, void *inf) dynamic linker, before writing them out. */ static enum elf_reloc_type_class -elf_i386_reloc_type_class (const Elf_Internal_Rela *rela) +elf_i386_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, + const asection *rel_sec ATTRIBUTE_UNUSED, + const Elf_Internal_Rela *rela) { switch (ELF32_R_TYPE (rela->r_info)) { @@ -4972,14 +5205,96 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, return TRUE; } -/* Return address for Ith PLT stub in section PLT, for relocation REL - or (bfd_vma) -1 if it should not be included. */ +/* Return an array of PLT entry symbol values. */ -static bfd_vma -elf_i386_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) +static bfd_vma * +elf_i386_get_plt_sym_val (bfd *abfd, asymbol **dynsyms, asection *plt, + asection *relplt) { - return plt->vma + (i + 1) * GET_PLT_ENTRY_SIZE (plt->owner); + bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); + arelent *p; + long count, i; + bfd_vma *plt_sym_val; + bfd_vma plt_offset; + bfd_byte *plt_contents; + const struct elf_i386_backend_data *bed + = get_elf_i386_backend_data (abfd); + Elf_Internal_Shdr *hdr; + + /* Get the .plt section contents. */ + plt_contents = (bfd_byte *) bfd_malloc (plt->size); + if (plt_contents == NULL) + return NULL; + if (!bfd_get_section_contents (abfd, (asection *) plt, + plt_contents, 0, plt->size)) + { +bad_return: + free (plt_contents); + return NULL; + } + + slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; + if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) + goto bad_return; + + hdr = &elf_section_data (relplt)->this_hdr; + count = relplt->size / hdr->sh_entsize; + + plt_sym_val = (bfd_vma *) bfd_malloc (sizeof (bfd_vma) * count); + if (plt_sym_val == NULL) + goto bad_return; + + for (i = 0; i < count; i++) + plt_sym_val[i] = -1; + + plt_offset = bed->plt->plt_entry_size; + p = relplt->relocation; + for (i = 0; i < count; i++, p++) + { + long reloc_index; + + /* Skip unknown relocation. PR 17512: file: bc9d6cf5. */ + if (p->howto == NULL) + continue; + + if (p->howto->type != R_386_JUMP_SLOT + && p->howto->type != R_386_IRELATIVE) + continue; + + reloc_index = H_GET_32 (abfd, (plt_contents + plt_offset + + bed->plt->plt_reloc_offset)); + reloc_index /= sizeof (Elf32_External_Rel); + if (reloc_index >= count) + abort (); + plt_sym_val[reloc_index] = plt->vma + plt_offset; + plt_offset += bed->plt->plt_entry_size; + + /* PR binutils/18437: Skip extra relocations in the .rel.plt + section. */ + if (plt_offset >= plt->size) + break; + } + + free (plt_contents); + + return plt_sym_val; +} + +/* Similar to _bfd_elf_get_synthetic_symtab. */ + +static long +elf_i386_get_synthetic_symtab (bfd *abfd, + long symcount, + asymbol **syms, + long dynsymcount, + asymbol **dynsyms, + asymbol **ret) +{ + asection *plt = bfd_get_section_by_name (abfd, ".plt"); + return _bfd_elf_ifunc_get_synthetic_symtab (abfd, symcount, syms, + dynsymcount, dynsyms, ret, + plt, + elf_i386_get_plt_sym_val); } /* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ @@ -5000,22 +5315,23 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *h) static bfd_boolean elf_i386_add_symbol_hook (bfd * abfd, - struct bfd_link_info * info ATTRIBUTE_UNUSED, + struct bfd_link_info * info, Elf_Internal_Sym * sym, const char ** namep ATTRIBUTE_UNUSED, flagword * flagsp ATTRIBUTE_UNUSED, asection ** secp ATTRIBUTE_UNUSED, bfd_vma * valp ATTRIBUTE_UNUSED) { - if ((abfd->flags & DYNAMIC) == 0 - && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)) + if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC + || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE) + && (abfd->flags & DYNAMIC) == 0 + && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; return TRUE; } -#define TARGET_LITTLE_SYM bfd_elf32_i386_vec +#define TARGET_LITTLE_SYM i386_elf32_vec #define TARGET_LITTLE_NAME "elf32-i386" #define ELF_ARCH bfd_arch_i386 #define ELF_TARGET_ID I386_ELF_DATA @@ -5029,6 +5345,7 @@ elf_i386_add_symbol_hook (bfd * abfd, #define elf_backend_want_plt_sym 0 #define elf_backend_got_header_size 12 #define elf_backend_plt_alignment 4 +#define elf_backend_extern_protected_data 1 /* Support RELA for objdump of prelink objects. */ #define elf_info_to_howto elf_i386_info_to_howto_rel @@ -5038,9 +5355,9 @@ elf_i386_add_symbol_hook (bfd * abfd, #define bfd_elf32_bfd_is_local_label_name elf_i386_is_local_label_name #define bfd_elf32_bfd_link_hash_table_create elf_i386_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_free elf_i386_link_hash_table_free #define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup #define bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup +#define bfd_elf32_get_synthetic_symtab elf_i386_get_synthetic_symtab #define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol #define elf_backend_relocs_compatible _bfd_elf_relocs_compatible @@ -5060,18 +5377,15 @@ elf_i386_add_symbol_hook (bfd * abfd, #define elf_backend_always_size_sections elf_i386_always_size_sections #define elf_backend_omit_section_dynsym \ ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_plt_sym_val elf_i386_plt_sym_val #define elf_backend_hash_symbol elf_i386_hash_symbol #define elf_backend_add_symbol_hook elf_i386_add_symbol_hook -#undef elf_backend_post_process_headers -#define elf_backend_post_process_headers _bfd_elf_set_osabi #include "elf32-target.h" /* FreeBSD support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf32_i386_freebsd_vec +#define TARGET_LITTLE_SYM i386_elf32_fbsd_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-i386-freebsd" #undef ELF_OSABI @@ -5084,11 +5398,14 @@ elf_i386_add_symbol_hook (bfd * abfd, static void elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info) { - _bfd_elf_set_osabi (abfd, info); + _bfd_elf_post_process_headers (abfd, info); #ifdef OLD_FREEBSD_ABI_LABEL - /* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard. */ - memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8); + { + /* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard. */ + Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); + memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8); + } #endif } @@ -5104,10 +5421,12 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info) /* Solaris 2. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf32_i386_sol2_vec +#define TARGET_LITTLE_SYM i386_elf32_sol2_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-i386-sol2" +#undef elf_backend_post_process_headers + /* Restore default: we cannot use ELFOSABI_SOLARIS, otherwise ELFOSABI_NONE objects won't be recognized. */ #undef ELF_OSABI @@ -5129,10 +5448,51 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info) #include "elf32-target.h" +/* Intel MCU support. */ + +static bfd_boolean +elf32_iamcu_elf_object_p (bfd *abfd) +{ + /* Set the right machine number for an IAMCU elf32 file. */ + bfd_default_set_arch_mach (abfd, bfd_arch_iamcu, bfd_mach_i386_iamcu); + return TRUE; +} + +#undef TARGET_LITTLE_SYM +#define TARGET_LITTLE_SYM iamcu_elf32_vec +#undef TARGET_LITTLE_NAME +#define TARGET_LITTLE_NAME "elf32-iamcu" +#undef ELF_ARCH +#define ELF_ARCH bfd_arch_iamcu + +#undef ELF_MACHINE_CODE +#define ELF_MACHINE_CODE EM_IAMCU + +#undef ELF_OSABI + +#undef elf32_bed +#define elf32_bed elf32_iamcu_bed + +#undef elf_backend_object_p +#define elf_backend_object_p elf32_iamcu_elf_object_p + +#undef elf_backend_static_tls_alignment + +#undef elf_backend_want_plt_sym +#define elf_backend_want_plt_sym 0 + +#include "elf32-target.h" + +/* Restore defaults. */ +#undef ELF_ARCH +#define ELF_ARCH bfd_arch_i386 +#undef ELF_MACHINE_CODE +#define ELF_MACHINE_CODE EM_386 + /* Native Client support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf32_i386_nacl_vec +#define TARGET_LITTLE_SYM i386_elf32_nacl_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-i386-nacl" #undef elf32_bed @@ -5146,7 +5506,6 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info) #undef elf_backend_want_plt_sym #define elf_backend_want_plt_sym 0 #undef elf_backend_post_process_headers -#define elf_backend_post_process_headers _bfd_elf_set_osabi #undef elf_backend_static_tls_alignment /* NaCl uses substantially different PLT entries for the same effects. */ @@ -5291,24 +5650,38 @@ static const struct elf_i386_backend_data elf_i386_nacl_arch_bed = 0, /* is_vxworks */ }; +static bfd_boolean +elf32_i386_nacl_elf_object_p (bfd *abfd) +{ + /* Set the right machine number for a NaCl i386 ELF32 file. */ + bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_i386_i386_nacl); + return TRUE; +} + #undef elf_backend_arch_data #define elf_backend_arch_data &elf_i386_nacl_arch_bed +#undef elf_backend_object_p +#define elf_backend_object_p elf32_i386_nacl_elf_object_p #undef elf_backend_modify_segment_map #define elf_backend_modify_segment_map nacl_modify_segment_map #undef elf_backend_modify_program_headers #define elf_backend_modify_program_headers nacl_modify_program_headers +#undef elf_backend_final_write_processing +#define elf_backend_final_write_processing nacl_final_write_processing #include "elf32-target.h" /* Restore defaults. */ +#undef elf_backend_object_p #undef elf_backend_modify_segment_map #undef elf_backend_modify_program_headers +#undef elf_backend_final_write_processing /* VxWorks support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf32_i386_vxworks_vec +#define TARGET_LITTLE_SYM i386_elf32_vxworks_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-i386-vxworks" #undef ELF_OSABI @@ -5326,7 +5699,6 @@ static const struct elf_i386_backend_data elf_i386_vxworks_arch_bed = #define elf_backend_arch_data &elf_i386_vxworks_arch_bed #undef elf_backend_relocs_compatible -#undef elf_backend_post_process_headers #undef elf_backend_add_symbol_hook #define elf_backend_add_symbol_hook \ elf_vxworks_add_symbol_hook diff --git a/contrib/gdb-7/bfd/elf32-nds32.c b/contrib/gdb-7/bfd/elf32-nds32.c new file mode 100644 index 0000000000..ed4383db5a --- /dev/null +++ b/contrib/gdb-7/bfd/elf32-nds32.c @@ -0,0 +1,15755 @@ +/* NDS32-specific support for 32-bit ELF. + Copyright (C) 2012-2015 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 "sysdep.h" +#include "bfd.h" +#include "bfd_stdint.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "libiberty.h" +#include "bfd_stdint.h" +#include "elf/nds32.h" +#include "opcode/nds32.h" +#include "elf32-nds32.h" +#include "opcode/cgen.h" +#include "../opcodes/nds32-opc.h" + +/* Relocation HOWTO functions. */ +static bfd_reloc_status_type nds32_elf_ignore_reloc + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +static bfd_reloc_status_type nds32_elf_9_pcrel_reloc + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +static bfd_reloc_status_type nds32_elf_hi20_reloc + (bfd *, arelent *, asymbol *, void *, + asection *, bfd *, char **); +static bfd_reloc_status_type nds32_elf_lo12_reloc + (bfd *, arelent *, asymbol *, void *, + asection *, bfd *, char **); +static bfd_reloc_status_type nds32_elf_generic_reloc + (bfd *, arelent *, asymbol *, void *, + asection *, bfd *, char **); +static bfd_reloc_status_type nds32_elf_sda15_reloc + (bfd *, arelent *, asymbol *, void *, + asection *, bfd *, char **); + +/* Helper functions for HOWTO. */ +static bfd_reloc_status_type nds32_elf_do_9_pcrel_reloc + (bfd *, reloc_howto_type *, asection *, bfd_byte *, bfd_vma, + asection *, bfd_vma, bfd_vma); +static void nds32_elf_relocate_hi20 + (bfd *, int, Elf_Internal_Rela *, Elf_Internal_Rela *, bfd_byte *, bfd_vma); +static reloc_howto_type *bfd_elf32_bfd_reloc_type_table_lookup + (enum elf_nds32_reloc_type); +static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup + (bfd *, bfd_reloc_code_real_type); + +/* Target hooks. */ +static void nds32_info_to_howto_rel + (bfd *, arelent *, Elf_Internal_Rela *dst); +static void nds32_info_to_howto + (bfd *, arelent *, Elf_Internal_Rela *dst); +static bfd_boolean nds32_elf_add_symbol_hook + (bfd *, struct bfd_link_info *, Elf_Internal_Sym *, const char **, + flagword *, asection **, bfd_vma *); +static bfd_boolean nds32_elf_relocate_section + (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **); +static bfd_boolean nds32_elf_object_p (bfd *); +static void nds32_elf_final_write_processing (bfd *, bfd_boolean); +static bfd_boolean nds32_elf_set_private_flags (bfd *, flagword); +static bfd_boolean nds32_elf_merge_private_bfd_data (bfd *, bfd *); +static bfd_boolean nds32_elf_print_private_bfd_data (bfd *, void *); +static bfd_boolean nds32_elf_gc_sweep_hook + (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *); +static bfd_boolean nds32_elf_check_relocs + (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *); +static asection *nds32_elf_gc_mark_hook + (asection *, struct bfd_link_info *, Elf_Internal_Rela *, + struct elf_link_hash_entry *, Elf_Internal_Sym *); +static bfd_boolean nds32_elf_adjust_dynamic_symbol + (struct bfd_link_info *, struct elf_link_hash_entry *); +static bfd_boolean nds32_elf_size_dynamic_sections + (bfd *, struct bfd_link_info *); +static bfd_boolean nds32_elf_create_dynamic_sections + (bfd *, struct bfd_link_info *); +static bfd_boolean nds32_elf_finish_dynamic_sections + (bfd *, struct bfd_link_info *info); +static bfd_boolean nds32_elf_finish_dynamic_symbol + (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, + Elf_Internal_Sym *); +static bfd_boolean nds32_elf_mkobject (bfd *); + +/* Nds32 helper functions. */ +static bfd_reloc_status_type nds32_elf_final_sda_base + (bfd *, struct bfd_link_info *, bfd_vma *, bfd_boolean); +static bfd_boolean allocate_dynrelocs (struct elf_link_hash_entry *, void *); +static bfd_boolean readonly_dynrelocs (struct elf_link_hash_entry *, void *); +static Elf_Internal_Rela *find_relocs_at_address + (Elf_Internal_Rela *, Elf_Internal_Rela *, + Elf_Internal_Rela *, enum elf_nds32_reloc_type); +static bfd_vma calculate_memory_address +(bfd *, Elf_Internal_Rela *, Elf_Internal_Sym *, Elf_Internal_Shdr *); +static int nds32_get_section_contents (bfd *, asection *, + bfd_byte **, bfd_boolean); +static bfd_boolean nds32_elf_ex9_build_hash_table +(bfd *, asection *, struct bfd_link_info *); +static bfd_boolean nds32_elf_ex9_itb_base (struct bfd_link_info *); +static void nds32_elf_ex9_import_table (struct bfd_link_info *); +static void nds32_elf_ex9_finish (struct bfd_link_info *); +static void nds32_elf_ex9_reloc_jmp (struct bfd_link_info *); +static void nds32_elf_get_insn_with_reg + (Elf_Internal_Rela *, uint32_t, uint32_t *); +static int nds32_get_local_syms (bfd *, asection *ATTRIBUTE_UNUSED, + Elf_Internal_Sym **); +static bfd_boolean nds32_elf_ex9_replace_instruction + (struct bfd_link_info *, bfd *, asection *); +static bfd_boolean nds32_elf_ifc_calc (struct bfd_link_info *, bfd *, + asection *); +static bfd_boolean nds32_elf_ifc_finish (struct bfd_link_info *); +static bfd_boolean nds32_elf_ifc_replace (struct bfd_link_info *); +static bfd_boolean nds32_elf_ifc_reloc (void); +static bfd_boolean nds32_relax_fp_as_gp + (struct bfd_link_info *link_info, bfd *abfd, asection *sec, + Elf_Internal_Rela *internal_relocs, Elf_Internal_Rela *irelend, + Elf_Internal_Sym *isymbuf); +static bfd_boolean nds32_fag_remove_unused_fpbase + (bfd *abfd, asection *sec, Elf_Internal_Rela *internal_relocs, + Elf_Internal_Rela *irelend); +static bfd_byte * +nds32_elf_get_relocated_section_contents (bfd *abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + bfd_byte *data, + bfd_boolean relocatable, + asymbol **symbols); + +enum +{ + MACH_V1 = bfd_mach_n1h, + MACH_V2 = bfd_mach_n1h_v2, + MACH_V3 = bfd_mach_n1h_v3, + MACH_V3M = bfd_mach_n1h_v3m +}; + +#define MIN(a, b) ((a) > (b) ? (b) : (a)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +/* The name of the dynamic interpreter. This is put in the .interp + section. */ +#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" + +/* The nop opcode we use. */ +#define NDS32_NOP32 0x40000009 +#define NDS32_NOP16 0x9200 + +/* The size in bytes of an entry in the procedure linkage table. */ +#define PLT_ENTRY_SIZE 24 +#define PLT_HEADER_SIZE 24 + +/* The first entry in a procedure linkage table are reserved, + and the initial contents are unimportant (we zero them out). + Subsequent entries look like this. */ +#define PLT0_ENTRY_WORD0 0x46f00000 /* sethi r15, HI20(.got+4) */ +#define PLT0_ENTRY_WORD1 0x58f78000 /* ori r15, r25, LO12(.got+4) */ +#define PLT0_ENTRY_WORD2 0x05178000 /* lwi r17, [r15+0] */ +#define PLT0_ENTRY_WORD3 0x04f78001 /* lwi r15, [r15+4] */ +#define PLT0_ENTRY_WORD4 0x4a003c00 /* jr r15 */ + +/* $ta is change to $r15 (from $r25). */ +#define PLT0_PIC_ENTRY_WORD0 0x46f00000 /* sethi r15, HI20(got[1]@GOT) */ +#define PLT0_PIC_ENTRY_WORD1 0x58f78000 /* ori r15, r15, LO12(got[1]@GOT) */ +#define PLT0_PIC_ENTRY_WORD2 0x40f7f400 /* add r15, gp, r15 */ +#define PLT0_PIC_ENTRY_WORD3 0x05178000 /* lwi r17, [r15+0] */ +#define PLT0_PIC_ENTRY_WORD4 0x04f78001 /* lwi r15, [r15+4] */ +#define PLT0_PIC_ENTRY_WORD5 0x4a003c00 /* jr r15 */ + +#define PLT_ENTRY_WORD0 0x46f00000 /* sethi r15, HI20(&got[n+3]) */ +#define PLT_ENTRY_WORD1 0x04f78000 /* lwi r15, r15, LO12(&got[n+3]) */ +#define PLT_ENTRY_WORD2 0x4a003c00 /* jr r15 */ +#define PLT_ENTRY_WORD3 0x45000000 /* movi r16, sizeof(RELA) * n */ +#define PLT_ENTRY_WORD4 0x48000000 /* j .plt0. */ + +#define PLT_PIC_ENTRY_WORD0 0x46f00000 /* sethi r15, HI20(got[n+3]@GOT) */ +#define PLT_PIC_ENTRY_WORD1 0x58f78000 /* ori r15, r15, LO12(got[n+3]@GOT) */ +#define PLT_PIC_ENTRY_WORD2 0x38febc02 /* lw r15, [gp+r15] */ +#define PLT_PIC_ENTRY_WORD3 0x4a003c00 /* jr r15 */ +#define PLT_PIC_ENTRY_WORD4 0x45000000 /* movi r16, sizeof(RELA) * n */ +#define PLT_PIC_ENTRY_WORD5 0x48000000 /* j .plt0 */ + +/* These are macros used to get the relocation accurate value. */ +#define ACCURATE_8BIT_S1 (0x100) +#define ACCURATE_U9BIT_S1 (0x400) +#define ACCURATE_12BIT_S1 (0x2000) +#define ACCURATE_14BIT_S1 (0x4000) +#define ACCURATE_19BIT (0x40000) + +/* These are macros used to get the relocation conservative value. */ +#define CONSERVATIVE_8BIT_S1 (0x100 - 4) +#define CONSERVATIVE_14BIT_S1 (0x4000 - 4) +#define CONSERVATIVE_16BIT_S1 (0x10000 - 4) +#define CONSERVATIVE_24BIT_S1 (0x1000000 - 4) +/* These must be more conservative because the address may be in + different segment. */ +#define CONSERVATIVE_15BIT (0x4000 - 0x1000) +#define CONSERVATIVE_15BIT_S1 (0x8000 - 0x1000) +#define CONSERVATIVE_15BIT_S2 (0x10000 - 0x1000) +#define CONSERVATIVE_19BIT (0x40000 - 0x1000) +#define CONSERVATIVE_20BIT (0x80000 - 0x1000) + +/* Size of small data/bss sections, used to calculate SDA_BASE. */ +static long got_size = 0; +static int is_SDA_BASE_set = 0; +static int is_ITB_BASE_set = 0; + +/* Convert ELF-VER in eflags to string for debugging purpose. */ +static const char *const nds32_elfver_strtab[] = +{ + "ELF-1.2", + "ELF-1.3", + "ELF-1.4", +}; + +/* The nds32 linker needs to keep track of the number of relocs that it + decides to copy in check_relocs for each symbol. This is so that + it can discard PC relative relocs if it doesn't need them when + linking with -Bsymbolic. We store the information in a field + extending the regular ELF linker hash table. */ + +/* This structure keeps track of the number of PC relative relocs we + have copied for a given symbol. */ + +struct elf_nds32_pcrel_relocs_copied +{ + /* Next section. */ + struct elf_nds32_pcrel_relocs_copied *next; + /* A section in dynobj. */ + asection *section; + /* Number of relocs copied in this section. */ + bfd_size_type count; +}; + +/* The sh linker needs to keep track of the number of relocs that it + decides to copy as dynamic relocs in check_relocs for each symbol. + This is so that it can later discard them if they are found to be + unnecessary. We store the information in a field extending the + regular ELF linker hash table. */ + +struct elf_nds32_dyn_relocs +{ + struct elf_nds32_dyn_relocs *next; + + /* The input section of the reloc. */ + asection *sec; + + /* Total number of relocs copied for the input section. */ + bfd_size_type count; + + /* Number of pc-relative relocs copied for the input section. */ + bfd_size_type pc_count; +}; + +/* Nds32 ELF linker hash entry. */ + +struct elf_nds32_link_hash_entry +{ + struct elf_link_hash_entry root; + + /* Track dynamic relocs copied for this symbol. */ + struct elf_nds32_dyn_relocs *dyn_relocs; + + /* For checking relocation type. */ +#define GOT_UNKNOWN 0 +#define GOT_NORMAL 1 +#define GOT_TLS_IE 2 + unsigned int tls_type; +}; + +/* Get the nds32 ELF linker hash table from a link_info structure. */ + +#define FP_BASE_NAME "_FP_BASE_" +static int check_start_export_sym = 0; +static size_t ex9_relax_size = 0; /* Save ex9 predicted reducing size. */ + +/* The offset for executable tls relaxation. */ +#define TP_OFFSET 0x0 + +struct elf_nds32_obj_tdata +{ + struct elf_obj_tdata root; + + /* tls_type for each local got entry. */ + char *local_got_tls_type; +}; + +#define elf_nds32_tdata(bfd) \ + ((struct elf_nds32_obj_tdata *) (bfd)->tdata.any) + +#define elf32_nds32_local_got_tls_type(bfd) \ + (elf_nds32_tdata (bfd)->local_got_tls_type) + +#define elf32_nds32_hash_entry(ent) ((struct elf_nds32_link_hash_entry *)(ent)) + +static bfd_boolean +nds32_elf_mkobject (bfd *abfd) +{ + return bfd_elf_allocate_object (abfd, sizeof (struct elf_nds32_obj_tdata), + NDS32_ELF_DATA); +} + +/* Relocations used for relocation. */ +static reloc_howto_type nds32_elf_howto_table[] = +{ + /* This reloc does nothing. */ + HOWTO (R_NDS32_NONE, /* type */ + 0, /* rightshift */ + 3, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_NONE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 16 bit absolute relocation. */ + HOWTO (R_NDS32_16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + nds32_elf_generic_reloc, /* special_function */ + "R_NDS32_16", /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 32 bit absolute relocation. */ + HOWTO (R_NDS32_32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + nds32_elf_generic_reloc, /* special_function */ + "R_NDS32_32", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 20 bit address. */ + HOWTO (R_NDS32_20, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + nds32_elf_generic_reloc, /* special_function */ + "R_NDS32_20", /* name */ + FALSE, /* partial_inplace */ + 0xfffff, /* src_mask */ + 0xfffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* An PC Relative 9-bit relocation, shifted by 2. + This reloc is complicated because relocations are relative to pc & -4. + i.e. branches in the right insn slot use the address of the left insn + slot for pc. */ + /* ??? It's not clear whether this should have partial_inplace set or not. + Branch relaxing in the assembler can store the addend in the insn, + and if bfd_install_relocation gets called the addend may get added + again. */ + HOWTO (R_NDS32_9_PCREL, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + nds32_elf_9_pcrel_reloc, /* special_function */ + "R_NDS32_9_PCREL", /* name */ + FALSE, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A relative 15 bit relocation, right shifted by 1. */ + HOWTO (R_NDS32_15_PCREL, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 14, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_15_PCREL", /* name */ + FALSE, /* partial_inplace */ + 0x3fff, /* src_mask */ + 0x3fff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A relative 17 bit relocation, right shifted by 1. */ + HOWTO (R_NDS32_17_PCREL, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_17_PCREL", /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A relative 25 bit relocation, right shifted by 1. */ + /* ??? It's not clear whether this should have partial_inplace set or not. + Branch relaxing in the assembler can store the addend in the insn, + and if bfd_install_relocation gets called the addend may get added + again. */ + HOWTO (R_NDS32_25_PCREL, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 24, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_25_PCREL", /* name */ + FALSE, /* partial_inplace */ + 0xffffff, /* src_mask */ + 0xffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* High 20 bits of address when lower 12 is or'd in. */ + HOWTO (R_NDS32_HI20, /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_hi20_reloc, /* special_function */ + "R_NDS32_HI20", /* name */ + FALSE, /* partial_inplace */ + 0x000fffff, /* src_mask */ + 0x000fffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Lower 12 bits of address. */ + HOWTO (R_NDS32_LO12S3, /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 9, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_lo12_reloc, /* special_function */ + "R_NDS32_LO12S3", /* name */ + FALSE, /* partial_inplace */ + 0x000001ff, /* src_mask */ + 0x000001ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Lower 12 bits of address. */ + HOWTO (R_NDS32_LO12S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 10, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_lo12_reloc, /* special_function */ + "R_NDS32_LO12S2", /* name */ + FALSE, /* partial_inplace */ + 0x000003ff, /* src_mask */ + 0x000003ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Lower 12 bits of address. */ + HOWTO (R_NDS32_LO12S1, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 11, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_lo12_reloc, /* special_function */ + "R_NDS32_LO12S1", /* name */ + FALSE, /* partial_inplace */ + 0x000007ff, /* src_mask */ + 0x000007ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Lower 12 bits of address. */ + HOWTO (R_NDS32_LO12S0, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_lo12_reloc, /* special_function */ + "R_NDS32_LO12S0", /* name */ + FALSE, /* partial_inplace */ + 0x00000fff, /* src_mask */ + 0x00000fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Small data area 15 bits offset. */ + HOWTO (R_NDS32_SDA15S3, /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + nds32_elf_sda15_reloc, /* special_function */ + "R_NDS32_SDA15S3", /* name */ + FALSE, /* partial_inplace */ + 0x00007fff, /* src_mask */ + 0x00007fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Small data area 15 bits offset. */ + HOWTO (R_NDS32_SDA15S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + nds32_elf_sda15_reloc, /* special_function */ + "R_NDS32_SDA15S2", /* name */ + FALSE, /* partial_inplace */ + 0x00007fff, /* src_mask */ + 0x00007fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Small data area 15 bits offset. */ + HOWTO (R_NDS32_SDA15S1, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + nds32_elf_sda15_reloc, /* special_function */ + "R_NDS32_SDA15S1", /* name */ + FALSE, /* partial_inplace */ + 0x00007fff, /* src_mask */ + 0x00007fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Small data area 15 bits offset. */ + HOWTO (R_NDS32_SDA15S0, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + nds32_elf_sda15_reloc, /* special_function */ + "R_NDS32_SDA15S0", /* name */ + FALSE, /* partial_inplace */ + 0x00007fff, /* src_mask */ + 0x00007fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* GNU extension to record C++ vtable hierarchy */ + HOWTO (R_NDS32_GNU_VTINHERIT, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + NULL, /* special_function */ + "R_NDS32_GNU_VTINHERIT", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* GNU extension to record C++ vtable member usage */ + HOWTO (R_NDS32_GNU_VTENTRY, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + _bfd_elf_rel_vtable_reloc_fn, /* special_function */ + "R_NDS32_GNU_VTENTRY", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 16 bit absolute relocation. */ + HOWTO (R_NDS32_16_RELA, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_16_RELA", /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 32 bit absolute relocation. */ + HOWTO (R_NDS32_32_RELA, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_32_RELA", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 20 bit address. */ + HOWTO (R_NDS32_20_RELA, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_20_RELA", /* name */ + FALSE, /* partial_inplace */ + 0xfffff, /* src_mask */ + 0xfffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_NDS32_9_PCREL_RELA, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_9_PCREL_RELA",/* name */ + FALSE, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A relative 15 bit relocation, right shifted by 1. */ + HOWTO (R_NDS32_15_PCREL_RELA, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 14, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_15_PCREL_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x3fff, /* src_mask */ + 0x3fff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A relative 17 bit relocation, right shifted by 1. */ + HOWTO (R_NDS32_17_PCREL_RELA, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_17_PCREL_RELA", /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A relative 25 bit relocation, right shifted by 2. */ + HOWTO (R_NDS32_25_PCREL_RELA, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 24, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_25_PCREL_RELA", /* name */ + FALSE, /* partial_inplace */ + 0xffffff, /* src_mask */ + 0xffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* High 20 bits of address when lower 16 is or'd in. */ + HOWTO (R_NDS32_HI20_RELA, /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_HI20_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x000fffff, /* src_mask */ + 0x000fffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Lower 12 bits of address. */ + HOWTO (R_NDS32_LO12S3_RELA, /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 9, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_LO12S3_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x000001ff, /* src_mask */ + 0x000001ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Lower 12 bits of address. */ + HOWTO (R_NDS32_LO12S2_RELA, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 10, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_LO12S2_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x000003ff, /* src_mask */ + 0x000003ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Lower 12 bits of address. */ + HOWTO (R_NDS32_LO12S1_RELA, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 11, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_LO12S1_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x000007ff, /* src_mask */ + 0x000007ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Lower 12 bits of address. */ + HOWTO (R_NDS32_LO12S0_RELA, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_LO12S0_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x00000fff, /* src_mask */ + 0x00000fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Small data area 15 bits offset. */ + HOWTO (R_NDS32_SDA15S3_RELA, /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_SDA15S3_RELA",/* name */ + FALSE, /* partial_inplace */ + 0x00007fff, /* src_mask */ + 0x00007fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Small data area 15 bits offset. */ + HOWTO (R_NDS32_SDA15S2_RELA, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_SDA15S2_RELA",/* name */ + FALSE, /* partial_inplace */ + 0x00007fff, /* src_mask */ + 0x00007fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_NDS32_SDA15S1_RELA, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_SDA15S1_RELA",/* name */ + FALSE, /* partial_inplace */ + 0x00007fff, /* src_mask */ + 0x00007fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_NDS32_SDA15S0_RELA, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_SDA15S0_RELA",/* name */ + FALSE, /* partial_inplace */ + 0x00007fff, /* src_mask */ + 0x00007fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* GNU extension to record C++ vtable hierarchy */ + HOWTO (R_NDS32_RELA_GNU_VTINHERIT, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + NULL, /* special_function */ + "R_NDS32_RELA_GNU_VTINHERIT", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* GNU extension to record C++ vtable member usage */ + HOWTO (R_NDS32_RELA_GNU_VTENTRY, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + _bfd_elf_rel_vtable_reloc_fn, /* special_function */ + "R_NDS32_RELA_GNU_VTENTRY", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Like R_NDS32_20, but referring to the GOT table entry for + the symbol. */ + HOWTO (R_NDS32_GOT20, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOT20", /* name */ + FALSE, /* partial_inplace */ + 0xfffff, /* src_mask */ + 0xfffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Like R_NDS32_PCREL, but referring to the procedure linkage table + entry for the symbol. */ + HOWTO (R_NDS32_25_PLTREL, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 24, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_25_PLTREL", /* name */ + FALSE, /* partial_inplace */ + 0xffffff, /* src_mask */ + 0xffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* This is used only by the dynamic linker. The symbol should exist + both in the object being run and in some shared library. The + dynamic linker copies the data addressed by the symbol from the + shared library into the object, because the object being + run has to have the data at some particular address. */ + HOWTO (R_NDS32_COPY, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_COPY", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Like R_NDS32_20, but used when setting global offset table + entries. */ + HOWTO (R_NDS32_GLOB_DAT, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GLOB_DAT", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Marks a procedure linkage table entry for a symbol. */ + HOWTO (R_NDS32_JMP_SLOT, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_JMP_SLOT", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Used only by the dynamic linker. When the object is run, this + longword is set to the load address of the object, plus the + addend. */ + HOWTO (R_NDS32_RELATIVE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_RELATIVE", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_NDS32_GOTOFF, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOTOFF", /* name */ + FALSE, /* partial_inplace */ + 0xfffff, /* src_mask */ + 0xfffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* An PC Relative 20-bit relocation used when setting PIC offset + table register. */ + HOWTO (R_NDS32_GOTPC20, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOTPC20", /* name */ + FALSE, /* partial_inplace */ + 0xfffff, /* src_mask */ + 0xfffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* Like R_NDS32_HI20, but referring to the GOT table entry for + the symbol. */ + HOWTO (R_NDS32_GOT_HI20, /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOT_HI20", /* name */ + FALSE, /* partial_inplace */ + 0x000fffff, /* src_mask */ + 0x000fffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_GOT_LO12, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOT_LO12", /* name */ + FALSE, /* partial_inplace */ + 0x00000fff, /* src_mask */ + 0x00000fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* An PC Relative relocation used when setting PIC offset table register. + Like R_NDS32_HI20, but referring to the GOT table entry for + the symbol. */ + HOWTO (R_NDS32_GOTPC_HI20, /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOTPC_HI20", /* name */ + FALSE, /* partial_inplace */ + 0x000fffff, /* src_mask */ + 0x000fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + HOWTO (R_NDS32_GOTPC_LO12, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOTPC_LO12", /* name */ + FALSE, /* partial_inplace */ + 0x00000fff, /* src_mask */ + 0x00000fff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_NDS32_GOTOFF_HI20, /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOTOFF_HI20", /* name */ + FALSE, /* partial_inplace */ + 0x000fffff, /* src_mask */ + 0x000fffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_GOTOFF_LO12, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOTOFF_LO12", /* name */ + FALSE, /* partial_inplace */ + 0x00000fff, /* src_mask */ + 0x00000fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Alignment hint for relaxable instruction. This is used with + R_NDS32_LABEL as a pair. Relax this instruction from 4 bytes to 2 + in order to make next label aligned on word boundary. */ + HOWTO (R_NDS32_INSN16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_INSN16", /* name */ + FALSE, /* partial_inplace */ + 0x00000fff, /* src_mask */ + 0x00000fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Alignment hint for label. */ + HOWTO (R_NDS32_LABEL, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_LABEL", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for unconditional call sequence */ + HOWTO (R_NDS32_LONGCALL1, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_LONGCALL1", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional call sequence. */ + HOWTO (R_NDS32_LONGCALL2, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_LONGCALL2", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional call sequence. */ + HOWTO (R_NDS32_LONGCALL3, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_LONGCALL3", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for unconditional branch sequence. */ + HOWTO (R_NDS32_LONGJUMP1, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_LONGJUMP1", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional branch sequence. */ + HOWTO (R_NDS32_LONGJUMP2, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_LONGJUMP2", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional branch sequence. */ + HOWTO (R_NDS32_LONGJUMP3, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_LONGJUMP3", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for load/store sequence. */ + HOWTO (R_NDS32_LOADSTORE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_LOADSTORE", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for load/store sequence. */ + HOWTO (R_NDS32_9_FIXED_RELA, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_9_FIXED_RELA",/* name */ + FALSE, /* partial_inplace */ + 0x000000ff, /* src_mask */ + 0x000000ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for load/store sequence. */ + HOWTO (R_NDS32_15_FIXED_RELA, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_15_FIXED_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x00003fff, /* src_mask */ + 0x00003fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for load/store sequence. */ + HOWTO (R_NDS32_17_FIXED_RELA, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_17_FIXED_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for load/store sequence. */ + HOWTO (R_NDS32_25_FIXED_RELA, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_25_FIXED_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x00ffffff, /* src_mask */ + 0x00ffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* High 20 bits of PLT symbol offset relative to PC. */ + HOWTO (R_NDS32_PLTREL_HI20, /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_PLTREL_HI20", /* name */ + FALSE, /* partial_inplace */ + 0x000fffff, /* src_mask */ + 0x000fffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Low 12 bits of PLT symbol offset relative to PC. */ + HOWTO (R_NDS32_PLTREL_LO12, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_PLTREL_LO12", /* name */ + FALSE, /* partial_inplace */ + 0x00000fff, /* src_mask */ + 0x00000fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* High 20 bits of PLT symbol offset relative to GOT (GP). */ + HOWTO (R_NDS32_PLT_GOTREL_HI20, /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_PLT_GOTREL_HI20", /* name */ + FALSE, /* partial_inplace */ + 0x000fffff, /* src_mask */ + 0x000fffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Low 12 bits of PLT symbol offset relative to GOT (GP). */ + HOWTO (R_NDS32_PLT_GOTREL_LO12, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_PLT_GOTREL_LO12", /* name */ + FALSE, /* partial_inplace */ + 0x00000fff, /* src_mask */ + 0x00000fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Small data area 12 bits offset. */ + HOWTO (R_NDS32_SDA12S2_DP_RELA, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_SDA12S2_DP_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x00000fff, /* src_mask */ + 0x00000fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Small data area 12 bits offset. */ + HOWTO (R_NDS32_SDA12S2_SP_RELA, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_SDA12S2_SP_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x00000fff, /* src_mask */ + 0x00000fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Lower 12 bits of address. */ + + HOWTO (R_NDS32_LO12S2_DP_RELA, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 10, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_LO12S2_DP_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x000003ff, /* src_mask */ + 0x000003ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Lower 12 bits of address. */ + HOWTO (R_NDS32_LO12S2_SP_RELA,/* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 10, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_LO12S2_SP_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x000003ff, /* src_mask */ + 0x000003ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Lower 12 bits of address. Special identity for or case. */ + HOWTO (R_NDS32_LO12S0_ORI_RELA, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_LO12S0_ORI_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x00000fff, /* src_mask */ + 0x00000fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Small data area 19 bits offset. */ + HOWTO (R_NDS32_SDA16S3_RELA, /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_SDA16S3_RELA",/* name */ + FALSE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Small data area 15 bits offset. */ + HOWTO (R_NDS32_SDA17S2_RELA, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 17, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_SDA17S2_RELA",/* name */ + FALSE, /* partial_inplace */ + 0x0001ffff, /* src_mask */ + 0x0001ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_NDS32_SDA18S1_RELA, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 18, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_SDA18S1_RELA",/* name */ + FALSE, /* partial_inplace */ + 0x0003ffff, /* src_mask */ + 0x0003ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_NDS32_SDA19S0_RELA, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 19, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_SDA19S0_RELA",/* name */ + FALSE, /* partial_inplace */ + 0x0007ffff, /* src_mask */ + 0x0007ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_DWARF2_OP1_RELA, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_DWARF2_OP1_RELA", /* name */ + FALSE, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_DWARF2_OP2_RELA, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_DWARF2_OP2_RELA", /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_DWARF2_LEB_RELA, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_DWARF2_LEB_RELA", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_UPDATE_TA_RELA,/* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_UPDATE_TA_RELA", /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Like R_NDS32_PCREL, but referring to the procedure linkage table + entry for the symbol. */ + HOWTO (R_NDS32_9_PLTREL, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_9_PLTREL", /* name */ + FALSE, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + TRUE), /* pcrel_offset */ + /* Low 20 bits of PLT symbol offset relative to GOT (GP). */ + HOWTO (R_NDS32_PLT_GOTREL_LO20, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_PLT_GOTREL_LO20", /* name */ + FALSE, /* partial_inplace */ + 0x000fffff, /* src_mask */ + 0x000fffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* low 15 bits of PLT symbol offset relative to GOT (GP) */ + HOWTO (R_NDS32_PLT_GOTREL_LO15, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_PLT_GOTREL_LO15", /* name */ + FALSE, /* partial_inplace */ + 0x00007fff, /* src_mask */ + 0x00007fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Low 19 bits of PLT symbol offset relative to GOT (GP). */ + HOWTO (R_NDS32_PLT_GOTREL_LO19, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 19, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_PLT_GOTREL_LO19", /* name */ + FALSE, /* partial_inplace */ + 0x0007ffff, /* src_mask */ + 0x0007ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_GOT_LO15, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOT_LO15", /* name */ + FALSE, /* partial_inplace */ + 0x00007fff, /* src_mask */ + 0x00007fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_GOT_LO19, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 19, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOT_LO19", /* name */ + FALSE, /* partial_inplace */ + 0x0007ffff, /* src_mask */ + 0x0007ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_GOTOFF_LO15, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOTOFF_LO15", /* name */ + FALSE, /* partial_inplace */ + 0x00007fff, /* src_mask */ + 0x00007fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_GOTOFF_LO19, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 19, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOTOFF_LO19", /* name */ + FALSE, /* partial_inplace */ + 0x0007ffff, /* src_mask */ + 0x0007ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* GOT 15 bits offset. */ + HOWTO (R_NDS32_GOT15S2_RELA, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOT15S2_RELA",/* name */ + FALSE, /* partial_inplace */ + 0x00007fff, /* src_mask */ + 0x00007fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* GOT 17 bits offset. */ + HOWTO (R_NDS32_GOT17S2_RELA, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 17, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_GOT17S2_RELA",/* name */ + FALSE, /* partial_inplace */ + 0x0001ffff, /* src_mask */ + 0x0001ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* A 5 bit address. */ + HOWTO (R_NDS32_5_RELA, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 5, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_5_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x1f, /* src_mask */ + 0x1f, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_10_UPCREL_RELA,/* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 9, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_10_UPCREL_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x1ff, /* src_mask */ + 0x1ff, /* dst_mask */ + TRUE), /* pcrel_offset */ + HOWTO (R_NDS32_SDA_FP7U2_RELA,/* type */ + 2, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 7, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_SDA_FP7U2_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x0000007f, /* src_mask */ + 0x0000007f, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_WORD_9_PCREL_RELA, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_WORD_9_PCREL_RELA", /* name */ + FALSE, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + TRUE), /* pcrel_offset */ + HOWTO (R_NDS32_25_ABS_RELA, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 24, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_25_ABS_RELA", /* name */ + FALSE, /* partial_inplace */ + 0xffffff, /* src_mask */ + 0xffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A relative 17 bit relocation for ifc, right shifted by 1. */ + HOWTO (R_NDS32_17IFC_PCREL_RELA, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_17IFC_PCREL_RELA", /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A relative unsigned 10 bit relocation for ifc, right shifted by 1. */ + HOWTO (R_NDS32_10IFCU_PCREL_RELA, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 9, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_10IFCU_PCREL_RELA", /* name */ + FALSE, /* partial_inplace */ + 0x1ff, /* src_mask */ + 0x1ff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* Like R_NDS32_HI20, but referring to the TLS entry for the symbol. */ + HOWTO (R_NDS32_TLS_LE_HI20, /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_LE_HI20", /* name */ + FALSE, /* partial_inplace */ + 0x000fffff, /* src_mask */ + 0x000fffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_LE_LO12, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_LE_LO12", /* name */ + FALSE, /* partial_inplace */ + 0x00000fff, /* src_mask */ + 0x00000fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Like R_NDS32_HI20, but referring to the TLS entry for the symbol. */ + HOWTO (R_NDS32_TLS_IE_HI20, /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_IE_HI20", /* name */ + FALSE, /* partial_inplace */ + 0x000fffff, /* src_mask */ + 0x000fffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_IE_LO12S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 10, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_IE_LO12S2", /* name */ + FALSE, /* partial_inplace */ + 0x000003ff, /* src_mask */ + 0x000003ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Mark a TLS IE entry in GOT. */ + HOWTO (R_NDS32_TLS_TPOFF, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_TPOFF", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* A 20 bit address. */ + HOWTO (R_NDS32_TLS_LE_20, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_LE_20", /* name */ + FALSE, /* partial_inplace */ + 0xfffff, /* src_mask */ + 0xfffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_LE_15S0, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_LE_15S0", /* name */ + FALSE, /* partial_inplace */ + 0x7fff, /* src_mask */ + 0x7fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_LE_15S1, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_LE_15S1", /* name */ + FALSE, /* partial_inplace */ + 0x7fff, /* src_mask */ + 0x7fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_LE_15S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_LE_15S2", /* name */ + FALSE, /* partial_inplace */ + 0x7fff, /* src_mask */ + 0x7fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for unconditional call sequence */ + HOWTO (R_NDS32_LONGCALL4, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGCALL4", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional call sequence. */ + HOWTO (R_NDS32_LONGCALL5, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGCALL5", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional call sequence. */ + HOWTO (R_NDS32_LONGCALL6, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGCALL6", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for unconditional branch sequence. */ + HOWTO (R_NDS32_LONGJUMP4, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGJUMP4", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional branch sequence. */ + HOWTO (R_NDS32_LONGJUMP5, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGJUMP5", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional branch sequence. */ + HOWTO (R_NDS32_LONGJUMP6, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGJUMP6", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional branch sequence. */ + HOWTO (R_NDS32_LONGJUMP7, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGJUMP7", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ +}; + +/* Relocations used for relaxation. */ +static reloc_howto_type nds32_elf_relax_howto_table[] = +{ + HOWTO (R_NDS32_RELAX_ENTRY, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_RELAX_ENTRY", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_GOT_SUFF, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_GOT_SUFF", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_GOTOFF_SUFF, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_GOTOFF_SUFF", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_PLT_GOT_SUFF, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_PLT_GOT_SUFF",/* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_MULCALL_SUFF, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_MULCALL_SUFF",/* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_PTR, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_PTR", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_PTR_COUNT, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_PTR_COUNT", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_PTR_RESOLVED, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_PTR_RESOLVED",/* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_PLTBLOCK, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_PLTBLOCK", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_RELAX_REGION_BEGIN, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_RELAX_REGION_BEGIN", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_RELAX_REGION_END, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_RELAX_REGION_END", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_MINUEND, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_MINUEND", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_SUBTRAHEND, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_SUBTRAHEND", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_DIFF8, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_DIFF8", /* name */ + FALSE, /* partial_inplace */ + 0x000000ff, /* src_mask */ + 0x000000ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_DIFF16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_DIFF16", /* name */ + FALSE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_DIFF32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_DIFF32", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_DIFF_ULEB128, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_DIFF_ULEB128",/* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_DATA, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_DATA", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TRAN, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + nds32_elf_ignore_reloc,/* special_function */ + "R_NDS32_TRAN", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_LE_ADD, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_TLS_LE_ADD", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_LE_LS, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_TLS_LE_LS", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_EMPTY, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_EMPTY", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ +}; + + +/* nds32_insertion_sort sorts an array with nmemb elements of size size. + This prototype is the same as qsort (). */ + +void +nds32_insertion_sort (void *base, size_t nmemb, size_t size, + int (*compar) (const void *lhs, const void *rhs)) +{ + char *ptr = (char *) base; + int i, j; + char *tmp = alloca (size); + + /* If i is less than j, i is inserted before j. + + |---- j ----- i --------------| + \ / \ / + sorted unsorted + */ + + for (i = 1; i < (int) nmemb; i++) + { + for (j = (i - 1); j >= 0; j--) + if (compar (ptr + i * size, ptr + j * size) >= 0) + break; + + j++; + + if (i == j) + continue; /* i is in order. */ + + memcpy (tmp, ptr + i * size, size); + memmove (ptr + (j + 1) * size, ptr + j * size, (i - j) * size); + memcpy (ptr + j * size, tmp, size); + } +} + +/* Sort relocation by r_offset. + + We didn't use qsort () in stdlib, because quick-sort is not a stable sorting + algorithm. Relocations at the same r_offset must keep their order. + For example, RELAX_ENTRY must be the very first relocation entry. + + Currently, this function implements insertion-sort. + + FIXME: If we already sort them in assembler, why bother sort them + here again? */ + +static int +compar_reloc (const void *lhs, const void *rhs) +{ + const Elf_Internal_Rela *l = (const Elf_Internal_Rela *) lhs; + const Elf_Internal_Rela *r = (const Elf_Internal_Rela *) rhs; + + if (l->r_offset > r->r_offset) + return 1; + else if (l->r_offset == r->r_offset) + return 0; + else + return -1; +} + +/* Functions listed below are only used for old relocs. + * nds32_elf_9_pcrel_reloc + * nds32_elf_do_9_pcrel_reloc + * nds32_elf_hi20_reloc + * nds32_elf_relocate_hi20 + * nds32_elf_lo12_reloc + * nds32_elf_sda15_reloc + * nds32_elf_generic_reloc + */ + +/* Handle the R_NDS32_9_PCREL & R_NDS32_9_PCREL_RELA reloc. */ + +static bfd_reloc_status_type +nds32_elf_9_pcrel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != NULL) + { + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_continue; + } + + return nds32_elf_do_9_pcrel_reloc (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + symbol->section, + (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +/* Utility to actually perform an R_NDS32_9_PCREL reloc. */ +#define N_ONES(n) (((((bfd_vma) 1 << ((n) - 1)) - 1) << 1) | 1) + +static bfd_reloc_status_type +nds32_elf_do_9_pcrel_reloc (bfd *abfd, reloc_howto_type *howto, + asection *input_section, bfd_byte *data, + bfd_vma offset, + asection *symbol_section ATTRIBUTE_UNUSED, + bfd_vma symbol_value, bfd_vma addend) +{ + bfd_signed_vma relocation; + unsigned short x; + bfd_reloc_status_type status; + + /* Sanity check the address (offset in section). */ + if (offset > bfd_get_section_limit (abfd, input_section)) + return bfd_reloc_outofrange; + + relocation = symbol_value + addend; + /* Make it pc relative. */ + relocation -= (input_section->output_section->vma + + input_section->output_offset); + /* These jumps mask off the lower two bits of the current address + before doing pcrel calculations. */ + relocation -= (offset & -(bfd_vma) 2); + + if (relocation < -ACCURATE_8BIT_S1 || relocation >= ACCURATE_8BIT_S1) + status = bfd_reloc_overflow; + else + status = bfd_reloc_ok; + + x = bfd_getb16 (data + offset); + + relocation >>= howto->rightshift; + relocation <<= howto->bitpos; + x = (x & ~howto->dst_mask) + | (((x & howto->src_mask) + relocation) & howto->dst_mask); + + bfd_putb16 ((bfd_vma) x, data + offset); + + return status; +} + +/* Handle the R_NDS32_HI20_[SU]LO relocs. + HI20_SLO is for the add3 and load/store with displacement instructions. + HI20 is for the or3 instruction. + For R_NDS32_HI20_SLO, the lower 16 bits are sign extended when added to + the high 16 bytes so if the lower 16 bits are negative (bit 15 == 1) then + we must add one to the high 16 bytes (which will get subtracted off when + the low 16 bits are added). + These relocs have to be done in combination with an R_NDS32_LO12 reloc + because there is a carry from the LO12 to the HI20. Here we just save + the information we need; we do the actual relocation when we see the LO12. + This code is copied from the elf32-mips.c. We also support an arbitrary + number of HI20 relocs to be associated with a single LO12 reloc. The + assembler sorts the relocs to ensure each HI20 immediately precedes its + LO12. However if there are multiple copies, the assembler may not find + the real LO12 so it picks the first one it finds. */ + +struct nds32_hi20 +{ + struct nds32_hi20 *next; + bfd_byte *addr; + bfd_vma addend; +}; + +static struct nds32_hi20 *nds32_hi20_list; + +static bfd_reloc_status_type +nds32_elf_hi20_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, + asymbol *symbol, void *data, asection *input_section, + bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) +{ + bfd_reloc_status_type ret; + bfd_vma relocation; + struct nds32_hi20 *n; + + /* This part is from bfd_elf_generic_reloc. + If we're relocating, and this an external symbol, we don't want + to change anything. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* Sanity check the address (offset in section). */ + if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) + return bfd_reloc_outofrange; + + ret = bfd_reloc_ok; + if (bfd_is_und_section (symbol->section) && output_bfd == (bfd *) NULL) + ret = bfd_reloc_undefined; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + + /* Save the information, and let LO12 do the actual relocation. */ + n = (struct nds32_hi20 *) bfd_malloc ((bfd_size_type) sizeof *n); + if (n == NULL) + return bfd_reloc_outofrange; + + n->addr = (bfd_byte *) data + reloc_entry->address; + n->addend = relocation; + n->next = nds32_hi20_list; + nds32_hi20_list = n; + + if (output_bfd != (bfd *) NULL) + reloc_entry->address += input_section->output_offset; + + return ret; +} + +/* Handle an NDS32 ELF HI20 reloc. */ + +static void +nds32_elf_relocate_hi20 (bfd *input_bfd ATTRIBUTE_UNUSED, + int type ATTRIBUTE_UNUSED, Elf_Internal_Rela *relhi, + Elf_Internal_Rela *rello, bfd_byte *contents, + bfd_vma addend) +{ + unsigned long insn; + bfd_vma addlo; + + insn = bfd_getb32 (contents + relhi->r_offset); + + addlo = bfd_getb32 (contents + rello->r_offset); + addlo &= 0xfff; + + addend += ((insn & 0xfffff) << 20) + addlo; + + insn = (insn & 0xfff00000) | ((addend >> 12) & 0xfffff); + bfd_putb32 (insn, contents + relhi->r_offset); +} + +/* Do an R_NDS32_LO12 relocation. This is a straightforward 12 bit + inplace relocation; this function exists in order to do the + R_NDS32_HI20_[SU]LO relocation described above. */ + +static bfd_reloc_status_type +nds32_elf_lo12_reloc (bfd *input_bfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, bfd *output_bfd, + char **error_message) +{ + /* This part is from bfd_elf_generic_reloc. + If we're relocating, and this an external symbol, we don't want + to change anything. */ + if (output_bfd != NULL && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (nds32_hi20_list != NULL) + { + struct nds32_hi20 *l; + + l = nds32_hi20_list; + while (l != NULL) + { + unsigned long insn; + unsigned long val; + unsigned long vallo; + struct nds32_hi20 *next; + + /* Do the HI20 relocation. Note that we actually don't need + to know anything about the LO12 itself, except where to + find the low 12 bits of the addend needed by the LO12. */ + insn = bfd_getb32 (l->addr); + vallo = bfd_getb32 ((bfd_byte *) data + reloc_entry->address); + vallo &= 0xfff; + switch (reloc_entry->howto->type) + { + case R_NDS32_LO12S3: + vallo <<= 3; + break; + + case R_NDS32_LO12S2: + vallo <<= 2; + break; + + case R_NDS32_LO12S1: + vallo <<= 1; + break; + + case R_NDS32_LO12S0: + vallo <<= 0; + break; + } + + val = ((insn & 0xfffff) << 12) + vallo; + val += l->addend; + + insn = (insn & ~(bfd_vma) 0xfffff) | ((val >> 12) & 0xfffff); + bfd_putb32 ((bfd_vma) insn, l->addr); + + next = l->next; + free (l); + l = next; + } + + nds32_hi20_list = NULL; + } + + /* Now do the LO12 reloc in the usual way. + ??? It would be nice to call bfd_elf_generic_reloc here, + but we have partial_inplace set. bfd_elf_generic_reloc will + pass the handling back to bfd_install_relocation which will install + a section relative addend which is wrong. */ + return nds32_elf_generic_reloc (input_bfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); +} + +/* Do generic partial_inplace relocation. + This is a local replacement for bfd_elf_generic_reloc. */ + +static bfd_reloc_status_type +nds32_elf_generic_reloc (bfd *input_bfd, arelent *reloc_entry, + asymbol *symbol, void *data, asection *input_section, + bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) +{ + bfd_reloc_status_type ret; + bfd_vma relocation; + bfd_byte *inplace_address; + + /* This part is from bfd_elf_generic_reloc. + If we're relocating, and this an external symbol, we don't want + to change anything. */ + if (output_bfd != NULL && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* Now do the reloc in the usual way. + ??? It would be nice to call bfd_elf_generic_reloc here, + but we have partial_inplace set. bfd_elf_generic_reloc will + pass the handling back to bfd_install_relocation which will install + a section relative addend which is wrong. */ + + /* Sanity check the address (offset in section). */ + if (reloc_entry->address > bfd_get_section_limit (input_bfd, input_section)) + return bfd_reloc_outofrange; + + ret = bfd_reloc_ok; + if (bfd_is_und_section (symbol->section) && output_bfd == (bfd *) NULL) + ret = bfd_reloc_undefined; + + if (bfd_is_com_section (symbol->section) || output_bfd != (bfd *) NULL) + relocation = 0; + else + relocation = symbol->value; + + /* Only do this for a final link. */ + if (output_bfd == (bfd *) NULL) + { + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + } + + relocation += reloc_entry->addend; + switch (reloc_entry->howto->type) + { + case R_NDS32_LO12S3: + relocation >>= 3; + break; + + case R_NDS32_LO12S2: + relocation >>= 2; + break; + + case R_NDS32_LO12S1: + relocation >>= 1; + break; + + case R_NDS32_LO12S0: + default: + relocation >>= 0; + break; + } + + inplace_address = (bfd_byte *) data + reloc_entry->address; + +#define DOIT(x) \ + x = ((x & ~reloc_entry->howto->dst_mask) | \ + (((x & reloc_entry->howto->src_mask) + relocation) & \ + reloc_entry->howto->dst_mask)) + + switch (reloc_entry->howto->size) + { + case 1: + { + short x = bfd_getb16 (inplace_address); + + DOIT (x); + bfd_putb16 ((bfd_vma) x, inplace_address); + } + break; + case 2: + { + unsigned long x = bfd_getb32 (inplace_address); + + DOIT (x); + bfd_putb32 ((bfd_vma) x, inplace_address); + } + break; + default: + BFD_ASSERT (0); + } + + if (output_bfd != (bfd *) NULL) + reloc_entry->address += input_section->output_offset; + + return ret; +} + +/* Handle the R_NDS32_SDA15 reloc. + This reloc is used to compute the address of objects in the small data area + and to perform loads and stores from that area. + The lower 15 bits are sign extended and added to the register specified + in the instruction, which is assumed to point to _SDA_BASE_. + + Since the lower 15 bits offset is left-shifted 0, 1 or 2 bits depending on + the access size, this must be taken care of. */ + +static bfd_reloc_status_type +nds32_elf_sda15_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, + asymbol *symbol, void *data ATTRIBUTE_UNUSED, + asection *input_section, bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != NULL) + { + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_continue; + } + + /* FIXME: not sure what to do here yet. But then again, the linker + may never call us. */ + abort (); +} + +/* nds32_elf_ignore_reloc is the special function for + relocation types which don't need to be relocated + like relaxation relocation types. + This function simply return bfd_reloc_ok when it is + invoked. */ + +static bfd_reloc_status_type +nds32_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, + asymbol *symbol ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED, asection *input_section, + bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) +{ + if (output_bfd != NULL) + reloc_entry->address += input_section->output_offset; + + return bfd_reloc_ok; +} + + +/* Map BFD reloc types to NDS32 ELF reloc types. */ + +struct nds32_reloc_map_entry +{ + bfd_reloc_code_real_type bfd_reloc_val; + unsigned char elf_reloc_val; +}; + +static const struct nds32_reloc_map_entry nds32_reloc_map[] = +{ + {BFD_RELOC_NONE, R_NDS32_NONE}, + {BFD_RELOC_16, R_NDS32_16_RELA}, + {BFD_RELOC_32, R_NDS32_32_RELA}, + {BFD_RELOC_NDS32_20, R_NDS32_20_RELA}, + {BFD_RELOC_NDS32_5, R_NDS32_5_RELA}, + {BFD_RELOC_NDS32_9_PCREL, R_NDS32_9_PCREL_RELA}, + {BFD_RELOC_NDS32_WORD_9_PCREL, R_NDS32_WORD_9_PCREL_RELA}, + {BFD_RELOC_NDS32_15_PCREL, R_NDS32_15_PCREL_RELA}, + {BFD_RELOC_NDS32_17_PCREL, R_NDS32_17_PCREL_RELA}, + {BFD_RELOC_NDS32_25_PCREL, R_NDS32_25_PCREL_RELA}, + {BFD_RELOC_NDS32_10_UPCREL, R_NDS32_10_UPCREL_RELA}, + {BFD_RELOC_NDS32_HI20, R_NDS32_HI20_RELA}, + {BFD_RELOC_NDS32_LO12S3, R_NDS32_LO12S3_RELA}, + {BFD_RELOC_NDS32_LO12S2, R_NDS32_LO12S2_RELA}, + {BFD_RELOC_NDS32_LO12S1, R_NDS32_LO12S1_RELA}, + {BFD_RELOC_NDS32_LO12S0, R_NDS32_LO12S0_RELA}, + {BFD_RELOC_NDS32_LO12S0_ORI, R_NDS32_LO12S0_ORI_RELA}, + {BFD_RELOC_NDS32_SDA15S3, R_NDS32_SDA15S3_RELA}, + {BFD_RELOC_NDS32_SDA15S2, R_NDS32_SDA15S2_RELA}, + {BFD_RELOC_NDS32_SDA15S1, R_NDS32_SDA15S1_RELA}, + {BFD_RELOC_NDS32_SDA15S0, R_NDS32_SDA15S0_RELA}, + {BFD_RELOC_VTABLE_INHERIT, R_NDS32_RELA_GNU_VTINHERIT}, + {BFD_RELOC_VTABLE_ENTRY, R_NDS32_RELA_GNU_VTENTRY}, + + {BFD_RELOC_NDS32_GOT20, R_NDS32_GOT20}, + {BFD_RELOC_NDS32_9_PLTREL, R_NDS32_9_PLTREL}, + {BFD_RELOC_NDS32_25_PLTREL, R_NDS32_25_PLTREL}, + {BFD_RELOC_NDS32_COPY, R_NDS32_COPY}, + {BFD_RELOC_NDS32_GLOB_DAT, R_NDS32_GLOB_DAT}, + {BFD_RELOC_NDS32_JMP_SLOT, R_NDS32_JMP_SLOT}, + {BFD_RELOC_NDS32_RELATIVE, R_NDS32_RELATIVE}, + {BFD_RELOC_NDS32_GOTOFF, R_NDS32_GOTOFF}, + {BFD_RELOC_NDS32_GOTPC20, R_NDS32_GOTPC20}, + {BFD_RELOC_NDS32_GOT_HI20, R_NDS32_GOT_HI20}, + {BFD_RELOC_NDS32_GOT_LO12, R_NDS32_GOT_LO12}, + {BFD_RELOC_NDS32_GOT_LO15, R_NDS32_GOT_LO15}, + {BFD_RELOC_NDS32_GOT_LO19, R_NDS32_GOT_LO19}, + {BFD_RELOC_NDS32_GOTPC_HI20, R_NDS32_GOTPC_HI20}, + {BFD_RELOC_NDS32_GOTPC_LO12, R_NDS32_GOTPC_LO12}, + {BFD_RELOC_NDS32_GOTOFF_HI20, R_NDS32_GOTOFF_HI20}, + {BFD_RELOC_NDS32_GOTOFF_LO12, R_NDS32_GOTOFF_LO12}, + {BFD_RELOC_NDS32_GOTOFF_LO15, R_NDS32_GOTOFF_LO15}, + {BFD_RELOC_NDS32_GOTOFF_LO19, R_NDS32_GOTOFF_LO19}, + {BFD_RELOC_NDS32_INSN16, R_NDS32_INSN16}, + {BFD_RELOC_NDS32_LABEL, R_NDS32_LABEL}, + {BFD_RELOC_NDS32_LONGCALL1, R_NDS32_LONGCALL1}, + {BFD_RELOC_NDS32_LONGCALL2, R_NDS32_LONGCALL2}, + {BFD_RELOC_NDS32_LONGCALL3, R_NDS32_LONGCALL3}, + {BFD_RELOC_NDS32_LONGCALL4, R_NDS32_LONGCALL4}, + {BFD_RELOC_NDS32_LONGCALL5, R_NDS32_LONGCALL5}, + {BFD_RELOC_NDS32_LONGCALL6, R_NDS32_LONGCALL6}, + {BFD_RELOC_NDS32_LONGJUMP1, R_NDS32_LONGJUMP1}, + {BFD_RELOC_NDS32_LONGJUMP2, R_NDS32_LONGJUMP2}, + {BFD_RELOC_NDS32_LONGJUMP3, R_NDS32_LONGJUMP3}, + {BFD_RELOC_NDS32_LONGJUMP4, R_NDS32_LONGJUMP4}, + {BFD_RELOC_NDS32_LONGJUMP5, R_NDS32_LONGJUMP5}, + {BFD_RELOC_NDS32_LONGJUMP6, R_NDS32_LONGJUMP6}, + {BFD_RELOC_NDS32_LONGJUMP7, R_NDS32_LONGJUMP7}, + {BFD_RELOC_NDS32_LOADSTORE, R_NDS32_LOADSTORE}, + {BFD_RELOC_NDS32_9_FIXED, R_NDS32_9_FIXED_RELA}, + {BFD_RELOC_NDS32_15_FIXED, R_NDS32_15_FIXED_RELA}, + {BFD_RELOC_NDS32_17_FIXED, R_NDS32_17_FIXED_RELA}, + {BFD_RELOC_NDS32_25_FIXED, R_NDS32_25_FIXED_RELA}, + {BFD_RELOC_NDS32_PLTREL_HI20, R_NDS32_PLTREL_HI20}, + {BFD_RELOC_NDS32_PLTREL_LO12, R_NDS32_PLTREL_LO12}, + {BFD_RELOC_NDS32_PLT_GOTREL_HI20, R_NDS32_PLT_GOTREL_HI20}, + {BFD_RELOC_NDS32_PLT_GOTREL_LO12, R_NDS32_PLT_GOTREL_LO12}, + {BFD_RELOC_NDS32_PLT_GOTREL_LO15, R_NDS32_PLT_GOTREL_LO15}, + {BFD_RELOC_NDS32_PLT_GOTREL_LO19, R_NDS32_PLT_GOTREL_LO19}, + {BFD_RELOC_NDS32_PLT_GOTREL_LO20, R_NDS32_PLT_GOTREL_LO20}, + {BFD_RELOC_NDS32_SDA12S2_DP, R_NDS32_SDA12S2_DP_RELA}, + {BFD_RELOC_NDS32_SDA12S2_SP, R_NDS32_SDA12S2_SP_RELA}, + {BFD_RELOC_NDS32_LO12S2_DP, R_NDS32_LO12S2_DP_RELA}, + {BFD_RELOC_NDS32_LO12S2_SP, R_NDS32_LO12S2_SP_RELA}, + {BFD_RELOC_NDS32_SDA16S3, R_NDS32_SDA16S3_RELA}, + {BFD_RELOC_NDS32_SDA17S2, R_NDS32_SDA17S2_RELA}, + {BFD_RELOC_NDS32_SDA18S1, R_NDS32_SDA18S1_RELA}, + {BFD_RELOC_NDS32_SDA19S0, R_NDS32_SDA19S0_RELA}, + {BFD_RELOC_NDS32_SDA_FP7U2_RELA, R_NDS32_SDA_FP7U2_RELA}, + {BFD_RELOC_NDS32_DWARF2_OP1, R_NDS32_DWARF2_OP1_RELA}, + {BFD_RELOC_NDS32_DWARF2_OP2, R_NDS32_DWARF2_OP2_RELA}, + {BFD_RELOC_NDS32_DWARF2_LEB, R_NDS32_DWARF2_LEB_RELA}, + {BFD_RELOC_NDS32_UPDATE_TA, R_NDS32_UPDATE_TA_RELA}, + {BFD_RELOC_NDS32_GOT_SUFF, R_NDS32_GOT_SUFF}, + {BFD_RELOC_NDS32_GOTOFF_SUFF, R_NDS32_GOTOFF_SUFF}, + {BFD_RELOC_NDS32_GOT15S2, R_NDS32_GOT15S2_RELA}, + {BFD_RELOC_NDS32_GOT17S2, R_NDS32_GOT17S2_RELA}, + {BFD_RELOC_NDS32_PTR, R_NDS32_PTR}, + {BFD_RELOC_NDS32_PTR_COUNT, R_NDS32_PTR_COUNT}, + {BFD_RELOC_NDS32_PLT_GOT_SUFF, R_NDS32_PLT_GOT_SUFF}, + {BFD_RELOC_NDS32_PTR_RESOLVED, R_NDS32_PTR_RESOLVED}, + {BFD_RELOC_NDS32_RELAX_ENTRY, R_NDS32_RELAX_ENTRY}, + {BFD_RELOC_NDS32_MULCALL_SUFF, R_NDS32_MULCALL_SUFF}, + {BFD_RELOC_NDS32_PLTBLOCK, R_NDS32_PLTBLOCK}, + {BFD_RELOC_NDS32_RELAX_REGION_BEGIN, R_NDS32_RELAX_REGION_BEGIN}, + {BFD_RELOC_NDS32_RELAX_REGION_END, R_NDS32_RELAX_REGION_END}, + {BFD_RELOC_NDS32_MINUEND, R_NDS32_MINUEND}, + {BFD_RELOC_NDS32_SUBTRAHEND, R_NDS32_SUBTRAHEND}, + {BFD_RELOC_NDS32_EMPTY, R_NDS32_EMPTY}, + + {BFD_RELOC_NDS32_DIFF8, R_NDS32_DIFF8}, + {BFD_RELOC_NDS32_DIFF16, R_NDS32_DIFF16}, + {BFD_RELOC_NDS32_DIFF32, R_NDS32_DIFF32}, + {BFD_RELOC_NDS32_DIFF_ULEB128, R_NDS32_DIFF_ULEB128}, + {BFD_RELOC_NDS32_25_ABS, R_NDS32_25_ABS_RELA}, + {BFD_RELOC_NDS32_DATA, R_NDS32_DATA}, + {BFD_RELOC_NDS32_TRAN, R_NDS32_TRAN}, + {BFD_RELOC_NDS32_17IFC_PCREL, R_NDS32_17IFC_PCREL_RELA}, + {BFD_RELOC_NDS32_10IFCU_PCREL, R_NDS32_10IFCU_PCREL_RELA}, + {BFD_RELOC_NDS32_TLS_LE_HI20, R_NDS32_TLS_LE_HI20}, + {BFD_RELOC_NDS32_TLS_LE_LO12, R_NDS32_TLS_LE_LO12}, + {BFD_RELOC_NDS32_TLS_LE_ADD, R_NDS32_TLS_LE_ADD}, + {BFD_RELOC_NDS32_TLS_LE_LS, R_NDS32_TLS_LE_LS}, + {BFD_RELOC_NDS32_TLS_IE_HI20, R_NDS32_TLS_IE_HI20}, + {BFD_RELOC_NDS32_TLS_IE_LO12S2, R_NDS32_TLS_IE_LO12S2}, + {BFD_RELOC_NDS32_TLS_TPOFF, R_NDS32_TLS_TPOFF}, + {BFD_RELOC_NDS32_TLS_LE_20, R_NDS32_TLS_LE_20}, + {BFD_RELOC_NDS32_TLS_LE_15S0, R_NDS32_TLS_LE_15S0}, + {BFD_RELOC_NDS32_TLS_LE_15S1, R_NDS32_TLS_LE_15S1}, + {BFD_RELOC_NDS32_TLS_LE_15S2, R_NDS32_TLS_LE_15S2}, +}; + +/* Patch tag. */ + +static reloc_howto_type * +bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE (nds32_elf_howto_table); i++) + if (nds32_elf_howto_table[i].name != NULL + && strcasecmp (nds32_elf_howto_table[i].name, r_name) == 0) + return &nds32_elf_howto_table[i]; + + for (i = 0; i < ARRAY_SIZE (nds32_elf_relax_howto_table); i++) + if (nds32_elf_relax_howto_table[i].name != NULL + && strcasecmp (nds32_elf_relax_howto_table[i].name, r_name) == 0) + return &nds32_elf_relax_howto_table[i]; + + return NULL; +} + +static reloc_howto_type * +bfd_elf32_bfd_reloc_type_table_lookup (enum elf_nds32_reloc_type code) +{ + if (code < R_NDS32_RELAX_ENTRY) + { + BFD_ASSERT (code < ARRAY_SIZE (nds32_elf_howto_table)); + return &nds32_elf_howto_table[code]; + } + else + { + BFD_ASSERT ((size_t) (code - R_NDS32_RELAX_ENTRY) + < ARRAY_SIZE (nds32_elf_relax_howto_table)); + return &nds32_elf_relax_howto_table[code - R_NDS32_RELAX_ENTRY]; + } +} + +static reloc_howto_type * +bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE (nds32_reloc_map); i++) + { + if (nds32_reloc_map[i].bfd_reloc_val == code) + return bfd_elf32_bfd_reloc_type_table_lookup + (nds32_reloc_map[i].elf_reloc_val); + } + + return NULL; +} + +/* Set the howto pointer for an NDS32 ELF reloc. */ + +static void +nds32_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, + Elf_Internal_Rela *dst) +{ + enum elf_nds32_reloc_type r_type; + + r_type = ELF32_R_TYPE (dst->r_info); + if (r_type > R_NDS32_GNU_VTENTRY) + { + _bfd_error_handler (_("%B: invalid NDS32 reloc number: %d"), abfd, r_type); + r_type = 0; + } + cache_ptr->howto = bfd_elf32_bfd_reloc_type_table_lookup (r_type); +} + +static void +nds32_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, + Elf_Internal_Rela *dst) +{ + BFD_ASSERT ((ELF32_R_TYPE (dst->r_info) == R_NDS32_NONE) + || ((ELF32_R_TYPE (dst->r_info) > R_NDS32_GNU_VTENTRY) + && (ELF32_R_TYPE (dst->r_info) < R_NDS32_max))); + cache_ptr->howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (dst->r_info)); +} + +/* Support for core dump NOTE sections. + Reference to include/linux/elfcore.h in Linux. */ + +static bfd_boolean +nds32_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) +{ + int offset; + size_t size; + + switch (note->descsz) + { + case 0x114: + /* Linux/NDS32 32-bit, ABI1 */ + + /* pr_cursig */ + elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); + + /* pr_pid */ + elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 24); + + /* pr_reg */ + offset = 72; + size = 200; + break; + + case 0xfc: + /* Linux/NDS32 32-bit */ + + /* pr_cursig */ + elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); + + /* pr_pid */ + elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 24); + + /* pr_reg */ + offset = 72; + size = 176; + break; + + default: + return FALSE; + } + + /* Make a ".reg" section. */ + return _bfd_elfcore_make_pseudosection (abfd, ".reg", + size, note->descpos + offset); +} + +static bfd_boolean +nds32_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) +{ + switch (note->descsz) + { + case 124: + /* Linux/NDS32 */ + + /* __kernel_uid_t, __kernel_gid_t are short on NDS32 platform. */ + elf_tdata (abfd)->core->program = + _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); + elf_tdata (abfd)->core->command = + _bfd_elfcore_strndup (abfd, note->descdata + 44, 80); + + default: + return FALSE; + } + + /* Note that for some reason, a spurious space is tacked + onto the end of the args in some (at least one anyway) + implementations, so strip it off if it exists. */ + { + char *command = elf_tdata (abfd)->core->command; + int n = strlen (command); + + if (0 < n && command[n - 1] == ' ') + command[n - 1] = '\0'; + } + + return TRUE; +} + +/* Hook called by the linker routine which adds symbols from an object + file. We must handle the special NDS32 section numbers here. + We also keep watching for whether we need to create the sdata special + linker sections. */ + +static bfd_boolean +nds32_elf_add_symbol_hook (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + Elf_Internal_Sym *sym, + const char **namep ATTRIBUTE_UNUSED, + flagword *flagsp ATTRIBUTE_UNUSED, + asection **secp, bfd_vma *valp) +{ + switch (sym->st_shndx) + { + case SHN_COMMON: + /* Common symbols less than the GP size are automatically + treated as SHN_MIPS_SCOMMON symbols. */ + if (sym->st_size > elf_gp_size (abfd) + || ELF_ST_TYPE (sym->st_info) == STT_TLS) + break; + + /* st_value is the alignemnt constraint. + That might be its actual size if it is an array or structure. */ + switch (sym->st_value) + { + case 1: + *secp = bfd_make_section_old_way (abfd, ".scommon_b"); + break; + case 2: + *secp = bfd_make_section_old_way (abfd, ".scommon_h"); + break; + case 4: + *secp = bfd_make_section_old_way (abfd, ".scommon_w"); + break; + case 8: + *secp = bfd_make_section_old_way (abfd, ".scommon_d"); + break; + default: + return TRUE; + } + + (*secp)->flags |= SEC_IS_COMMON; + *valp = sym->st_size; + break; + } + + return TRUE; +} + + +/* This function can figure out the best location for a base register to access + data relative to this base register + INPUT: + sda_d0: size of first DOUBLE WORD data section + sda_w0: size of first WORD data section + sda_h0: size of first HALF WORD data section + sda_b : size of BYTE data section + sda_hi: size of second HALF WORD data section + sda_w1: size of second WORD data section + sda_d1: size of second DOUBLE WORD data section + OUTPUT: + offset (always positive) from the beginning of sda_d0 if OK + a negative error value if fail + NOTE: + these 7 sections have to be located back to back if exist + a pass in 0 value for non-existing section */ + +/* Due to the interpretation of simm15 field of load/store depending on + data accessing size, the organization of base register relative data shall + like the following figure + ------------------------------------------- + | DOUBLE WORD sized data (range +/- 128K) + ------------------------------------------- + | WORD sized data (range +/- 64K) + ------------------------------------------- + | HALF WORD sized data (range +/- 32K) + ------------------------------------------- + | BYTE sized data (range +/- 16K) + ------------------------------------------- + | HALF WORD sized data (range +/- 32K) + ------------------------------------------- + | WORD sized data (range +/- 64K) + ------------------------------------------- + | DOUBLE WORD sized data (range +/- 128K) + ------------------------------------------- + Its base register shall be set to access these data freely. */ + +/* We have to figure out the SDA_BASE value, so that we can adjust the + symbol value correctly. We look up the symbol _SDA_BASE_ in the output + BFD. If we can't find it, we're stuck. We cache it in the ELF + target data. We don't need to adjust the symbol value for an + external symbol if we are producing relocatable output. */ + +static asection *sda_rela_sec = NULL; + +#define SDA_SECTION_NUM 10 + +static bfd_reloc_status_type +nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info, + bfd_vma *psb, bfd_boolean add_symbol) +{ + int relax_fp_as_gp; + struct elf_nds32_link_hash_table *table; + struct bfd_link_hash_entry *h, *h2; + long unsigned int total = 0; + + h = bfd_link_hash_lookup (info->hash, "_SDA_BASE_", FALSE, FALSE, TRUE); + if (!h || (h->type != bfd_link_hash_defined && h->type != bfd_link_hash_defweak)) + { + asection *first = NULL, *final = NULL, *temp; + bfd_vma sda_base; + /* The first section must be 4-byte aligned to promise _SDA_BASE_ being + 4 byte-aligned. Therefore, it has to set the first section ".data" + 4 byte-aligned. */ + static const char sec_name[SDA_SECTION_NUM][10] = + { + ".data", ".got", ".sdata_d", ".sdata_w", ".sdata_h", ".sdata_b", + ".sbss_b", ".sbss_h", ".sbss_w", ".sbss_d" + }; + size_t i = 0; + + if (output_bfd->sections == NULL) + { + *psb = elf_gp (output_bfd); + return bfd_reloc_ok; + } + + /* Get the first and final section. */ + while (i < sizeof (sec_name) / sizeof (sec_name [0])) + { + temp = bfd_get_section_by_name (output_bfd, sec_name[i]); + if (temp && !first && (temp->size != 0 || temp->rawsize != 0)) + first = temp; + if (temp && (temp->size != 0 || temp->rawsize != 0)) + final = temp; + + /* Summarize the sections in order to check if joining .bss. */ + if (temp && temp->size != 0) + total += temp->size; + else if (temp && temp->rawsize != 0) + total += temp->rawsize; + + i++; + } + + /* Check .bss size. */ + temp = bfd_get_section_by_name (output_bfd, ".bss"); + if (temp) + { + if (temp->size != 0) + total += temp->size; + else if (temp->rawsize != 0) + total += temp->rawsize; + + if (total < 0x80000) + { + if (!first && (temp->size != 0 || temp->rawsize != 0)) + first = temp; + if ((temp->size != 0 || temp->rawsize != 0)) + final = temp; + } + } + + if (first && final) + { + /* The middle of data region. */ + sda_base = final->vma / 2 + final->rawsize / 2 + first->vma / 2; + + /* Find the section sda_base located. */ + i = 0; + while (i < sizeof (sec_name) / sizeof (sec_name [0])) + { + final = bfd_get_section_by_name (output_bfd, sec_name[i]); + if (final && (final->size != 0 || final->rawsize != 0) + && sda_base >= final->vma) + { + first = final; + i++; + } + else + break; + } + } + else + { + /* There is not any data section in output bfd, and set _SDA_BASE_ in + first output section. */ + first = output_bfd->sections; + while (first && first->size == 0 && first->rawsize == 0) + first = first->next; + if (!first) + { + *psb = elf_gp (output_bfd); + return bfd_reloc_ok; + } + sda_base = first->vma + first->rawsize; + } + + sda_base -= first->vma; + sda_base = sda_base & (~7); + + if (!_bfd_generic_link_add_one_symbol + (info, output_bfd, "_SDA_BASE_", BSF_GLOBAL | BSF_WEAK, first, + (bfd_vma) sda_base, (const char *) NULL, FALSE, + get_elf_backend_data (output_bfd)->collect, &h)) + return FALSE; + + sda_rela_sec = first; + + table = nds32_elf_hash_table (info); + relax_fp_as_gp = table->relax_fp_as_gp; + if (relax_fp_as_gp) + { + h2 = bfd_link_hash_lookup (info->hash, FP_BASE_NAME, + FALSE, FALSE, FALSE); + /* Define a weak FP_BASE_NAME here to prevent the undefined symbol. + And set FP equal to SDA_BASE to do relaxation for + la $fp, _FP_BASE_. */ + if (!_bfd_generic_link_add_one_symbol + (info, output_bfd, FP_BASE_NAME, BSF_GLOBAL | BSF_WEAK, + first, (bfd_vma) sda_base, (const char *) NULL, + FALSE, get_elf_backend_data (output_bfd)->collect, &h2)) + return FALSE; + } + } + + if (add_symbol == TRUE) + { + if (h) + { + /* Now set gp. */ + elf_gp (output_bfd) = (h->u.def.value + + h->u.def.section->output_section->vma + + h->u.def.section->output_offset); + } + else + { + (*_bfd_error_handler) (_("error: Can't find symbol: _SDA_BASE_.")); + return bfd_reloc_dangerous; + } + } + + *psb = h->u.def.value + h->u.def.section->output_section->vma + + h->u.def.section->output_offset; + return bfd_reloc_ok; +} + + +/* Return size of a PLT entry. */ +#define elf_nds32_sizeof_plt(info) PLT_ENTRY_SIZE + + +/* Create an entry in an nds32 ELF linker hash table. */ + +static struct bfd_hash_entry * +nds32_elf_link_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string) +{ + struct elf_nds32_link_hash_entry *ret; + + ret = (struct elf_nds32_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == NULL) + ret = (struct elf_nds32_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct elf_nds32_link_hash_entry)); + + if (ret == NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = (struct elf_nds32_link_hash_entry *) + _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, table, string); + + if (ret != NULL) + { + struct elf_nds32_link_hash_entry *eh; + + eh = (struct elf_nds32_link_hash_entry *) ret; + eh->dyn_relocs = NULL; + eh->tls_type = GOT_UNKNOWN; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Create an nds32 ELF linker hash table. */ + +static struct bfd_link_hash_table * +nds32_elf_link_hash_table_create (bfd *abfd) +{ + struct elf_nds32_link_hash_table *ret; + + bfd_size_type amt = sizeof (struct elf_nds32_link_hash_table); + + ret = (struct elf_nds32_link_hash_table *) bfd_zmalloc (amt); + if (ret == NULL) + return NULL; + + /* patch tag. */ + if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, + nds32_elf_link_hash_newfunc, + sizeof (struct elf_nds32_link_hash_entry), + NDS32_ELF_DATA)) + { + free (ret); + return NULL; + } + + ret->sgot = NULL; + ret->sgotplt = NULL; + ret->srelgot = NULL; + ret->splt = NULL; + ret->srelplt = NULL; + ret->sdynbss = NULL; + ret->srelbss = NULL; + ret->sym_ld_script = NULL; + ret->ex9_export_file = NULL; + ret->ex9_import_file = NULL; + + return &ret->root.root; +} + +/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up + shortcuts to them in our hash table. */ + +static bfd_boolean +create_got_section (bfd *dynobj, struct bfd_link_info *info) +{ + struct elf_nds32_link_hash_table *htab; + + if (!_bfd_elf_create_got_section (dynobj, info)) + return FALSE; + + htab = nds32_elf_hash_table (info); + htab->sgot = bfd_get_section_by_name (dynobj, ".got"); + htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt"); + if (!htab->sgot || !htab->sgotplt) + abort (); + + /* _bfd_elf_create_got_section will create it for us. */ + htab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + if (htab->srelgot == NULL + || !bfd_set_section_flags (dynobj, htab->srelgot, + (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS + | SEC_IN_MEMORY | SEC_LINKER_CREATED + | SEC_READONLY)) + || !bfd_set_section_alignment (dynobj, htab->srelgot, 2)) + return FALSE; + + return TRUE; +} + +/* Create dynamic sections when linking against a dynamic object. */ + +static bfd_boolean +nds32_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) +{ + struct elf_nds32_link_hash_table *htab; + flagword flags, pltflags; + register asection *s; + const struct elf_backend_data *bed; + int ptralign = 2; /* 32-bit */ + + bed = get_elf_backend_data (abfd); + + htab = nds32_elf_hash_table (info); + + /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and + .rel[a].bss sections. */ + + flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED); + + pltflags = flags; + pltflags |= SEC_CODE; + if (bed->plt_not_loaded) + pltflags &= ~(SEC_LOAD | SEC_HAS_CONTENTS); + if (bed->plt_readonly) + pltflags |= SEC_READONLY; + + s = bfd_make_section (abfd, ".plt"); + htab->splt = s; + if (s == NULL + || !bfd_set_section_flags (abfd, s, pltflags) + || !bfd_set_section_alignment (abfd, s, bed->plt_alignment)) + return FALSE; + + if (bed->want_plt_sym) + { + /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the + .plt section. */ + struct bfd_link_hash_entry *bh = NULL; + struct elf_link_hash_entry *h; + + if (!(_bfd_generic_link_add_one_symbol + (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, + (bfd_vma) 0, (const char *) NULL, FALSE, + get_elf_backend_data (abfd)->collect, &bh))) + return FALSE; + + h = (struct elf_link_hash_entry *) bh; + h->def_regular = 1; + h->type = STT_OBJECT; + + if (info->shared && !bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + s = bfd_make_section (abfd, + bed->default_use_rela_p ? ".rela.plt" : ".rel.plt"); + htab->srelplt = s; + if (s == NULL + || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || !bfd_set_section_alignment (abfd, s, ptralign)) + return FALSE; + + if (htab->sgot == NULL && !create_got_section (abfd, info)) + return FALSE; + + { + const char *secname; + char *relname; + flagword secflags; + asection *sec; + + for (sec = abfd->sections; sec; sec = sec->next) + { + secflags = bfd_get_section_flags (abfd, sec); + if ((secflags & (SEC_DATA | SEC_LINKER_CREATED)) + || ((secflags & SEC_HAS_CONTENTS) != SEC_HAS_CONTENTS)) + continue; + secname = bfd_get_section_name (abfd, sec); + relname = (char *) bfd_malloc ((bfd_size_type) strlen (secname) + 6); + strcpy (relname, ".rela"); + strcat (relname, secname); + if (bfd_get_section_by_name (abfd, secname)) + continue; + s = bfd_make_section (abfd, relname); + if (s == NULL + || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || !bfd_set_section_alignment (abfd, s, ptralign)) + return FALSE; + } + } + + if (bed->want_dynbss) + { + /* The .dynbss section is a place to put symbols which are defined + by dynamic objects, are referenced by regular objects, and are + not functions. We must allocate space for them in the process + image and use a R_*_COPY reloc to tell the dynamic linker to + initialize them at run time. The linker script puts the .dynbss + section into the .bss section of the final image. */ + s = bfd_make_section (abfd, ".dynbss"); + htab->sdynbss = s; + if (s == NULL + || !bfd_set_section_flags (abfd, s, SEC_ALLOC | SEC_LINKER_CREATED)) + return FALSE; + /* The .rel[a].bss section holds copy relocs. This section is not + normally needed. We need to create it here, though, so that the + linker will map it to an output section. We can't just create it + only if we need it, because we will not know whether we need it + until we have seen all the input files, and the first time the + main linker code calls BFD after examining all the input files + (size_dynamic_sections) the input sections have already been + mapped to the output sections. If the section turns out not to + be needed, we can discard it later. We will never need this + section when generating a shared object, since they do not use + copy relocs. */ + if (!info->shared) + { + s = bfd_make_section (abfd, (bed->default_use_rela_p + ? ".rela.bss" : ".rel.bss")); + htab->srelbss = s; + if (s == NULL + || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || !bfd_set_section_alignment (abfd, s, ptralign)) + return FALSE; + } + } + + return TRUE; +} + +/* Copy the extra info we tack onto an elf_link_hash_entry. */ +static void +nds32_elf_copy_indirect_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *dir, + struct elf_link_hash_entry *ind) +{ + struct elf_nds32_link_hash_entry *edir, *eind; + + edir = (struct elf_nds32_link_hash_entry *) dir; + eind = (struct elf_nds32_link_hash_entry *) ind; + + if (eind->dyn_relocs != NULL) + { + if (edir->dyn_relocs != NULL) + { + struct elf_nds32_dyn_relocs **pp; + struct elf_nds32_dyn_relocs *p; + + if (ind->root.type == bfd_link_hash_indirect) + abort (); + + /* Add reloc counts against the weak sym to the strong sym + list. Merge any entries against the same section. */ + for (pp = &eind->dyn_relocs; (p = *pp) != NULL;) + { + struct elf_nds32_dyn_relocs *q; + + for (q = edir->dyn_relocs; q != NULL; q = q->next) + if (q->sec == p->sec) + { + q->pc_count += p->pc_count; + q->count += p->count; + *pp = p->next; + break; + } + if (q == NULL) + pp = &p->next; + } + *pp = edir->dyn_relocs; + } + + edir->dyn_relocs = eind->dyn_relocs; + eind->dyn_relocs = NULL; + } + + _bfd_elf_link_hash_copy_indirect (info, dir, ind); +} + + +/* Adjust a symbol defined by a dynamic object and referenced by a + regular object. The current definition is in some section of the + dynamic object, but we're not including those sections. We have to + change the definition to something the rest of the link can + understand. */ + +static bfd_boolean +nds32_elf_adjust_dynamic_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h) +{ + struct elf_nds32_link_hash_table *htab; + struct elf_nds32_link_hash_entry *eh; + struct elf_nds32_dyn_relocs *p; + bfd *dynobj; + asection *s; + unsigned int power_of_two; + + dynobj = elf_hash_table (info)->dynobj; + + /* Make sure we know what is going on here. */ + BFD_ASSERT (dynobj != NULL + && (h->needs_plt + || h->u.weakdef != NULL + || (h->def_dynamic && h->ref_regular && !h->def_regular))); + + + /* If this is a function, put it in the procedure linkage table. We + will fill in the contents of the procedure linkage table later, + when we know the address of the .got section. */ + if (h->type == STT_FUNC || h->needs_plt) + { + if (!info->shared + && !h->def_dynamic + && !h->ref_dynamic + && h->root.type != bfd_link_hash_undefweak + && h->root.type != bfd_link_hash_undefined) + { + /* This case can occur if we saw a PLT reloc in an input + file, but the symbol was never referred to by a dynamic + object. In such a case, we don't actually need to build + a procedure linkage table, and we can just do a PCREL + reloc instead. */ + h->plt.offset = (bfd_vma) - 1; + h->needs_plt = 0; + } + + return TRUE; + } + else + h->plt.offset = (bfd_vma) - 1; + + /* If this is a weak symbol, and there is a real definition, the + processor independent code will have arranged for us to see the + real definition first, and we can just use the same value. */ + if (h->u.weakdef != NULL) + { + BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined + || h->u.weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->u.weakdef->root.u.def.section; + h->root.u.def.value = h->u.weakdef->root.u.def.value; + return TRUE; + } + + /* This is a reference to a symbol defined by a dynamic object which + is not a function. */ + + /* If we are creating a shared library, we must presume that the + only references to the symbol are via the global offset table. + For such cases we need not do anything here; the relocations will + be handled correctly by relocate_section. */ + if (info->shared) + return TRUE; + + /* If there are no references to this symbol that do not use the + GOT, we don't need to generate a copy reloc. */ + if (!h->non_got_ref) + return TRUE; + + /* If -z nocopyreloc was given, we won't generate them either. */ + if (info->nocopyreloc) + { + h->non_got_ref = 0; + return TRUE; + } + + eh = (struct elf_nds32_link_hash_entry *) h; + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + s = p->sec->output_section; + if (s != NULL && (s->flags & (SEC_READONLY | SEC_HAS_CONTENTS)) != 0) + break; + } + + /* If we didn't find any dynamic relocs in sections which needs the + copy reloc, then we'll be keeping the dynamic relocs and avoiding + the copy reloc. */ + if (p == NULL) + { + h->non_got_ref = 0; + return TRUE; + } + + /* We must allocate the symbol in our .dynbss section, which will + become part of the .bss section of the executable. There will be + an entry for this symbol in the .dynsym section. The dynamic + object will contain position independent code, so all references + from the dynamic object to this symbol will go through the global + offset table. The dynamic linker will use the .dynsym entry to + determine the address it must put in the global offset table, so + both the dynamic object and the regular object will refer to the + same memory location for the variable. */ + + htab = nds32_elf_hash_table (info); + s = htab->sdynbss; + BFD_ASSERT (s != NULL); + + /* We must generate a R_NDS32_COPY reloc to tell the dynamic linker + to copy the initial value out of the dynamic object and into the + runtime process image. We need to remember the offset into the + .rela.bss section we are going to use. */ + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) + { + asection *srel; + + srel = htab->srelbss; + BFD_ASSERT (srel != NULL); + srel->size += sizeof (Elf32_External_Rela); + h->needs_copy = 1; + } + + /* We need to figure out the alignment required for this symbol. I + have no idea how ELF linkers handle this. */ + power_of_two = bfd_log2 (h->size); + if (power_of_two > 3) + power_of_two = 3; + + /* Apply the required alignment. */ + s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two)); + if (power_of_two > bfd_get_section_alignment (dynobj, s)) + { + if (!bfd_set_section_alignment (dynobj, s, power_of_two)) + return FALSE; + } + + /* Define the symbol as being at this point in the section. */ + h->root.u.def.section = s; + h->root.u.def.value = s->size; + + /* Increment the section size to make room for the symbol. */ + s->size += h->size; + + return TRUE; +} + +/* Allocate space in .plt, .got and associated reloc sections for + dynamic relocs. */ + +static bfd_boolean +allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) +{ + struct bfd_link_info *info; + struct elf_nds32_link_hash_table *htab; + struct elf_nds32_link_hash_entry *eh; + struct elf_nds32_dyn_relocs *p; + + if (h->root.type == bfd_link_hash_indirect) + return TRUE; + + if (h->root.type == bfd_link_hash_warning) + /* When warning symbols are created, they **replace** the "real" + entry in the hash table, thus we never get to see the real + symbol in a hash traversal. So look at it now. */ + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + info = (struct bfd_link_info *) inf; + htab = nds32_elf_hash_table (info); + + eh = (struct elf_nds32_link_hash_entry *) h; + + if (htab->root.dynamic_sections_created && h->plt.refcount > 0) + { + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 && !h->forced_local) + { + if (!bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h)) + { + asection *s = htab->splt; + + /* If this is the first .plt entry, make room for the special + first entry. */ + if (s->size == 0) + s->size += PLT_ENTRY_SIZE; + + h->plt.offset = s->size; + + /* If this symbol is not defined in a regular file, and we are + not generating a shared library, then set the symbol to this + location in the .plt. This is required to make function + pointers compare as equal between the normal executable and + the shared library. */ + if (!info->shared && !h->def_regular) + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } + + /* Make room for this entry. */ + s->size += PLT_ENTRY_SIZE; + + /* We also need to make an entry in the .got.plt section, which + will be placed in the .got section by the linker script. */ + htab->sgotplt->size += 4; + + /* We also need to make an entry in the .rel.plt section. */ + htab->srelplt->size += sizeof (Elf32_External_Rela); + } + else + { + h->plt.offset = (bfd_vma) - 1; + h->needs_plt = 0; + } + } + else + { + h->plt.offset = (bfd_vma) - 1; + h->needs_plt = 0; + } + + if (h->got.refcount > 0) + { + asection *s; + bfd_boolean dyn; + int tls_type = elf32_nds32_hash_entry (h)->tls_type; + + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 && !h->forced_local) + { + if (!bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + s = htab->sgot; + h->got.offset = s->size; + + if (tls_type == GOT_UNKNOWN) + abort (); + else if (tls_type == GOT_NORMAL + || tls_type == GOT_TLS_IE) + /* Need a GOT slot. */ + s->size += 4; + + dyn = htab->root.dynamic_sections_created; + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)) + htab->srelgot->size += sizeof (Elf32_External_Rela); + } + else + h->got.offset = (bfd_vma) - 1; + + if (eh->dyn_relocs == NULL) + return TRUE; + + /* In the shared -Bsymbolic case, discard space allocated for + dynamic pc-relative relocs against symbols which turn out to be + defined in regular objects. For the normal shared case, discard + space for pc-relative relocs that have become local due to symbol + visibility changes. */ + + if (info->shared) + { + if (h->def_regular && (h->forced_local || info->symbolic)) + { + struct elf_nds32_dyn_relocs **pp; + + for (pp = &eh->dyn_relocs; (p = *pp) != NULL;) + { + p->count -= p->pc_count; + p->pc_count = 0; + if (p->count == 0) + *pp = p->next; + else + pp = &p->next; + } + } + } + else + { + /* For the non-shared case, discard space for relocs against + symbols which turn out to need copy relocs or are not dynamic. */ + + if (!h->non_got_ref + && ((h->def_dynamic + && !h->def_regular) + || (htab->root.dynamic_sections_created + && (h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined)))) + { + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 && !h->forced_local) + { + if (!bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + /* If that succeeded, we know we'll be keeping all the + relocs. */ + if (h->dynindx != -1) + goto keep; + } + + eh->dyn_relocs = NULL; + + keep:; + } + + /* Finally, allocate space. */ + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + asection *sreloc = elf_section_data (p->sec)->sreloc; + sreloc->size += p->count * sizeof (Elf32_External_Rela); + } + + return TRUE; +} + +/* Find any dynamic relocs that apply to read-only sections. */ + +static bfd_boolean +readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) +{ + struct elf_nds32_link_hash_entry *eh; + struct elf_nds32_dyn_relocs *p; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + eh = (struct elf_nds32_link_hash_entry *) h; + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + asection *s = p->sec->output_section; + + if (s != NULL && (s->flags & SEC_READONLY) != 0) + { + struct bfd_link_info *info = (struct bfd_link_info *) inf; + + info->flags |= DF_TEXTREL; + + /* Not an error, just cut short the traversal. */ + return FALSE; + } + } + return TRUE; +} + +/* Set the sizes of the dynamic sections. */ + +static bfd_boolean +nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) +{ + struct elf_nds32_link_hash_table *htab; + bfd *dynobj; + asection *s; + bfd_boolean relocs; + bfd *ibfd; + + htab = nds32_elf_hash_table (info); + dynobj = htab->root.dynobj; + BFD_ASSERT (dynobj != NULL); + + if (htab->root.dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (!info->shared) + { + s = bfd_get_section_by_name (dynobj, ".interp"); + BFD_ASSERT (s != NULL); + s->size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + } + } + + /* Set up .got offsets for local syms, and space for local dynamic + relocs. */ + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + bfd_signed_vma *local_got; + bfd_signed_vma *end_local_got; + bfd_size_type locsymcount; + Elf_Internal_Shdr *symtab_hdr; + asection *srel; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) + continue; + + for (s = ibfd->sections; s != NULL; s = s->next) + { + struct elf_nds32_dyn_relocs *p; + + for (p = ((struct elf_nds32_dyn_relocs *) + elf_section_data (s)->local_dynrel); + p != NULL; p = p->next) + { + if (!bfd_is_abs_section (p->sec) + && bfd_is_abs_section (p->sec->output_section)) + { + /* Input section has been discarded, either because + it is a copy of a linkonce section or due to + linker script /DISCARD/, so we'll be discarding + the relocs too. */ + } + else if (p->count != 0) + { + srel = elf_section_data (p->sec)->sreloc; + srel->size += p->count * sizeof (Elf32_External_Rela); + if ((p->sec->output_section->flags & SEC_READONLY) != 0) + info->flags |= DF_TEXTREL; + } + } + } + + local_got = elf_local_got_refcounts (ibfd); + if (!local_got) + continue; + + symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; + locsymcount = symtab_hdr->sh_info; + end_local_got = local_got + locsymcount; + s = htab->sgot; + srel = htab->srelgot; + for (; local_got < end_local_got; ++local_got) + { + if (*local_got > 0) + { + *local_got = s->size; + s->size += 4; + if (info->shared) + srel->size += sizeof (Elf32_External_Rela); + } + else + *local_got = (bfd_vma) - 1; + } + } + + /* Allocate global sym .plt and .got entries, and space for global + sym dynamic relocs. */ + elf_link_hash_traverse (&htab->root, allocate_dynrelocs, (void *) info); + + /* We now have determined the sizes of the various dynamic sections. + Allocate memory for them. */ + relocs = FALSE; + for (s = dynobj->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_LINKER_CREATED) == 0) + continue; + + if (s == htab->splt) + { + /* Strip this section if we don't need it; see the + comment below. */ + } + else if (s == htab->sgot) + { + got_size += s->size; + } + else if (s == htab->sgotplt) + { + got_size += s->size; + } + else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0) + { + if (s->size != 0 && s != htab->srelplt) + relocs = TRUE; + + /* We use the reloc_count field as a counter if we need + to copy relocs into the output file. */ + s->reloc_count = 0; + } + else + { + /* It's not one of our sections, so don't allocate space. */ + continue; + } + + if (s->size == 0) + { + /* If we don't need this section, strip it from the + output file. This is mostly to handle .rela.bss and + .rela.plt. We must create both sections in + create_dynamic_sections, because they must be created + before the linker maps input sections to output + sections. The linker does that before + adjust_dynamic_symbol is called, and it is that + function which decides whether anything needs to go + into these sections. */ + s->flags |= SEC_EXCLUDE; + continue; + } + + /* Allocate memory for the section contents. We use bfd_zalloc + here in case unused entries are not reclaimed before the + section's contents are written out. This should not happen, + but this way if it does, we get a R_NDS32_NONE reloc instead + of garbage. */ + s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); + if (s->contents == NULL) + return FALSE; + } + + + if (htab->root.dynamic_sections_created) + { + /* Add some entries to the .dynamic section. We fill in the + values later, in nds32_elf_finish_dynamic_sections, but we + must add the entries now so that we get the correct size for + the .dynamic section. The DT_DEBUG entry is filled in by the + dynamic linker and used by the debugger. */ +#define add_dynamic_entry(TAG, VAL) \ + _bfd_elf_add_dynamic_entry (info, TAG, VAL) + + if (!info->shared) + { + if (!add_dynamic_entry (DT_DEBUG, 0)) + return FALSE; + } + + if (htab->splt->size != 0) + { + if (!add_dynamic_entry (DT_PLTGOT, 0) + || !add_dynamic_entry (DT_PLTRELSZ, 0) + || !add_dynamic_entry (DT_PLTREL, DT_RELA) + || !add_dynamic_entry (DT_JMPREL, 0)) + return FALSE; + } + + if (relocs) + { + if (!add_dynamic_entry (DT_RELA, 0) + || !add_dynamic_entry (DT_RELASZ, 0) + || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) + return FALSE; + + /* If any dynamic relocs apply to a read-only section, + then we need a DT_TEXTREL entry. */ + if ((info->flags & DF_TEXTREL) == 0) + elf_link_hash_traverse (&htab->root, readonly_dynrelocs, + (void *) info); + + if ((info->flags & DF_TEXTREL) != 0) + { + if (!add_dynamic_entry (DT_TEXTREL, 0)) + return FALSE; + } + } + } +#undef add_dynamic_entry + + return TRUE; +} + +static bfd_reloc_status_type +nds32_relocate_contents (reloc_howto_type *howto, bfd *input_bfd, + bfd_vma relocation, bfd_byte *location) +{ + int size; + bfd_vma x = 0; + bfd_reloc_status_type flag; + unsigned int rightshift = howto->rightshift; + unsigned int bitpos = howto->bitpos; + + /* If the size is negative, negate RELOCATION. This isn't very + general. */ + if (howto->size < 0) + relocation = -relocation; + + /* Get the value we are going to relocate. */ + size = bfd_get_reloc_size (howto); + switch (size) + { + default: + abort (); + break; + case 0: + return bfd_reloc_ok; + case 2: + x = bfd_getb16 (location); + break; + case 4: + x = bfd_getb32 (location); + break; + } + + /* Check for overflow. FIXME: We may drop bits during the addition + which we don't check for. We must either check at every single + operation, which would be tedious, or we must do the computations + in a type larger than bfd_vma, which would be inefficient. */ + flag = bfd_reloc_ok; + if (howto->complain_on_overflow != complain_overflow_dont) + { + bfd_vma addrmask, fieldmask, signmask, ss; + bfd_vma a, b, sum; + + /* Get the values to be added together. For signed and unsigned + relocations, we assume that all values should be truncated to + the size of an address. For bitfields, all the bits matter. + See also bfd_check_overflow. */ + fieldmask = N_ONES (howto->bitsize); + signmask = ~fieldmask; + addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask; + a = (relocation & addrmask) >> rightshift; + b = (x & howto->src_mask & addrmask) >> bitpos; + + switch (howto->complain_on_overflow) + { + case complain_overflow_signed: + /* If any sign bits are set, all sign bits must be set. + That is, A must be a valid negative address after + shifting. */ + signmask = ~(fieldmask >> 1); + /* Fall through. */ + + case complain_overflow_bitfield: + /* Much like the signed check, but for a field one bit + wider. We allow a bitfield to represent numbers in the + range -2**n to 2**n-1, where n is the number of bits in the + field. Note that when bfd_vma is 32 bits, a 32-bit reloc + can't overflow, which is exactly what we want. */ + ss = a & signmask; + if (ss != 0 && ss != ((addrmask >> rightshift) & signmask)) + flag = bfd_reloc_overflow; + + /* We only need this next bit of code if the sign bit of B + is below the sign bit of A. This would only happen if + SRC_MASK had fewer bits than BITSIZE. Note that if + SRC_MASK has more bits than BITSIZE, we can get into + trouble; we would need to verify that B is in range, as + we do for A above. */ + ss = ((~howto->src_mask) >> 1) & howto->src_mask; + ss >>= bitpos; + + /* Set all the bits above the sign bit. */ + b = (b ^ ss) - ss; + + /* Now we can do the addition. */ + sum = a + b; + + /* See if the result has the correct sign. Bits above the + sign bit are junk now; ignore them. If the sum is + positive, make sure we did not have all negative inputs; + if the sum is negative, make sure we did not have all + positive inputs. The test below looks only at the sign + bits, and it really just + SIGN (A) == SIGN (B) && SIGN (A) != SIGN (SUM) + + We mask with addrmask here to explicitly allow an address + wrap-around. The Linux kernel relies on it, and it is + the only way to write assembler code which can run when + loaded at a location 0x80000000 away from the location at + which it is linked. */ + if (((~(a ^ b)) & (a ^ sum)) & signmask & addrmask) + flag = bfd_reloc_overflow; + + break; + + case complain_overflow_unsigned: + /* Checking for an unsigned overflow is relatively easy: + trim the addresses and add, and trim the result as well. + Overflow is normally indicated when the result does not + fit in the field. However, we also need to consider the + case when, e.g., fieldmask is 0x7fffffff or smaller, an + input is 0x80000000, and bfd_vma is only 32 bits; then we + will get sum == 0, but there is an overflow, since the + inputs did not fit in the field. Instead of doing a + separate test, we can check for this by or-ing in the + operands when testing for the sum overflowing its final + field. */ + sum = (a + b) & addrmask; + if ((a | b | sum) & signmask) + flag = bfd_reloc_overflow; + break; + + default: + abort (); + } + } + + /* Put RELOCATION in the right bits. */ + relocation >>= (bfd_vma) rightshift; + relocation <<= (bfd_vma) bitpos; + + /* Add RELOCATION to the right bits of X. */ + /* FIXME : 090616 + Because the relaxation may generate duplicate relocation at one address, + an addition to immediate in the instruction may cause the relocation added + several times. + This bug should be fixed in assembler, but a check is also needed here. */ + if (howto->partial_inplace) + x = ((x & ~howto->dst_mask) + | (((x & howto->src_mask) + relocation) & howto->dst_mask)); + else + x = ((x & ~howto->dst_mask) | ((relocation) & howto->dst_mask)); + + + /* Put the relocated value back in the object file. */ + switch (size) + { + default: + case 0: + case 1: + case 8: + abort (); + break; + case 2: + bfd_putb16 (x, location); + break; + case 4: + bfd_putb32 (x, location); + break; + } + + return flag; +} + +static bfd_reloc_status_type +nds32_elf_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd, + asection *input_section, bfd_byte *contents, + bfd_vma address, bfd_vma value, bfd_vma addend) +{ + bfd_vma relocation; + + /* Sanity check the address. */ + if (address > bfd_get_section_limit (input_bfd, input_section)) + return bfd_reloc_outofrange; + + /* This function assumes that we are dealing with a basic relocation + against a symbol. We want to compute the value of the symbol to + relocate to. This is just VALUE, the value of the symbol, plus + ADDEND, any addend associated with the reloc. */ + relocation = value + addend; + + /* If the relocation is PC relative, we want to set RELOCATION to + the distance between the symbol (currently in RELOCATION) and the + location we are relocating. Some targets (e.g., i386-aout) + arrange for the contents of the section to be the negative of the + offset of the location within the section; for such targets + pcrel_offset is FALSE. Other targets (e.g., m88kbcs or ELF) + simply leave the contents of the section as zero; for such + targets pcrel_offset is TRUE. If pcrel_offset is FALSE we do not + need to subtract out the offset of the location within the + section (which is just ADDRESS). */ + if (howto->pc_relative) + { + relocation -= (input_section->output_section->vma + + input_section->output_offset); + if (howto->pcrel_offset) + relocation -= address; + } + + return nds32_relocate_contents (howto, input_bfd, relocation, + contents + address); +} + +static bfd_boolean +nds32_elf_output_symbol_hook (struct bfd_link_info *info, + const char *name, + Elf_Internal_Sym *elfsym ATTRIBUTE_UNUSED, + asection *input_sec, + struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) +{ + const char *source; + FILE *sym_ld_script = NULL; + struct elf_nds32_link_hash_table *table; + + table = nds32_elf_hash_table (info); + sym_ld_script = table->sym_ld_script; + if (!sym_ld_script) + return TRUE; + + if (!h || !name || *name == '\0') + return TRUE; + + if (input_sec->flags & SEC_EXCLUDE) + return TRUE; + + if (!check_start_export_sym) + { + fprintf (sym_ld_script, "SECTIONS\n{\n"); + check_start_export_sym = 1; + } + + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + if (!h->root.u.def.section->output_section) + return TRUE; + + if (bfd_is_const_section (input_sec)) + source = input_sec->name; + else + source = input_sec->owner->filename; + + fprintf (sym_ld_script, "\t%s = 0x%08lx;\t /* %s */\n", + h->root.root.string, + (long) (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset), source); + } + + return TRUE; +} + +/* Relocate an NDS32/D ELF section. + There is some attempt to make this function usable for many architectures, + both for RELA and REL type relocs, if only to serve as a learning tool. + + The RELOCATE_SECTION function is called by the new ELF backend linker + to handle the relocations for a section. + + The relocs are always passed as Rela structures; if the section + actually uses Rel structures, the r_addend field will always be + zero. + + This function is responsible for adjust the section contents as + necessary, and (if using Rela relocs and generating a + relocatable output file) adjusting the reloc addend as + necessary. + + This function does not have to worry about setting the reloc + address or the reloc symbol index. + + LOCAL_SYMS is a pointer to the swapped in local symbols. + + LOCAL_SECTIONS is an array giving the section in the input file + corresponding to the st_shndx field of each local symbol. + + The global hash table entry for the global symbols can be found + via elf_sym_hashes (input_bfd). + + When generating relocatable output, this function must handle + STB_LOCAL/STT_SECTION symbols specially. The output symbol is + going to be the section symbol corresponding to the output + section, which means that the addend must be adjusted + accordingly. */ + +static bfd_vma +dtpoff_base (struct bfd_link_info *info) +{ + /* If tls_sec is NULL, we should have signalled an error already. */ + if (elf_hash_table (info)->tls_sec == NULL) + return 0; + return elf_hash_table (info)->tls_sec->vma; +} + +static bfd_boolean +nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info * info, + bfd * input_bfd, + asection * input_section, + bfd_byte * contents, + Elf_Internal_Rela * relocs, + Elf_Internal_Sym * local_syms, + asection ** local_sections) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + Elf_Internal_Rela *rel, *relend; + bfd_boolean ret = TRUE; /* Assume success. */ + int align = 0; + bfd_reloc_status_type r; + const char *errmsg = NULL; + bfd_vma gp; + struct elf_nds32_link_hash_table *htab; + bfd *dynobj; + bfd_vma *local_got_offsets; + asection *sgot, *splt, *sreloc; + bfd_vma high_address; + struct elf_nds32_link_hash_table *table; + int eliminate_gc_relocs; + bfd_vma fpbase_addr; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + htab = nds32_elf_hash_table (info); + high_address = bfd_get_section_limit (input_bfd, input_section); + + dynobj = htab->root.dynobj; + local_got_offsets = elf_local_got_offsets (input_bfd); + + sgot = htab->sgot; + splt = htab->splt; + sreloc = NULL; + + rel = relocs; + relend = relocs + input_section->reloc_count; + + table = nds32_elf_hash_table (info); + eliminate_gc_relocs = table->eliminate_gc_relocs; + /* By this time, we can adjust the value of _SDA_BASE_. */ + if ((!info->relocatable)) + { + is_SDA_BASE_set = 1; + r = nds32_elf_final_sda_base (output_bfd, info, &gp, TRUE); + if (r != bfd_reloc_ok) + return FALSE; + } + + if (is_ITB_BASE_set == 0) + { + /* Set the _ITB_BASE_. */ + if (!nds32_elf_ex9_itb_base (info)) + { + (*_bfd_error_handler) (_("%B: error: Cannot set _ITB_BASE_"), + output_bfd); + bfd_set_error (bfd_error_bad_value); + } + } + + if (table->target_optimize & NDS32_RELAX_JUMP_IFC_ON) + if (!nds32_elf_ifc_reloc ()) + (*_bfd_error_handler) (_("error: IFC relocation error.")); + + /* Relocation for .ex9.itable. */ + if (table->target_optimize & NDS32_RELAX_EX9_ON + || (table->ex9_import_file && table->update_ex9_table)) + nds32_elf_ex9_reloc_jmp (info); + + /* Use gp as fp to prevent truncated fit. Because in relaxation time + the fp value is set as gp, and it has be reverted for instruction + setting fp. */ + fpbase_addr = elf_gp (output_bfd); + + for (rel = relocs; rel < relend; rel++) + { + enum elf_nds32_reloc_type r_type; + reloc_howto_type *howto = NULL; + unsigned long r_symndx; + struct elf_link_hash_entry *h = NULL; + Elf_Internal_Sym *sym = NULL; + asection *sec; + bfd_vma relocation; + + /* We can't modify r_addend here as elf_link_input_bfd has an assert to + ensure it's zero (we use REL relocs, not RELA). Therefore this + should be assigning zero to `addend', but for clarity we use + `r_addend'. */ + + bfd_vma addend = rel->r_addend; + bfd_vma offset = rel->r_offset; + + r_type = ELF32_R_TYPE (rel->r_info); + if (r_type >= R_NDS32_max) + { + (*_bfd_error_handler) (_("%B: error: unknown relocation type %d."), + input_bfd, r_type); + bfd_set_error (bfd_error_bad_value); + ret = FALSE; + continue; + } + + if (r_type == R_NDS32_GNU_VTENTRY + || r_type == R_NDS32_GNU_VTINHERIT + || r_type == R_NDS32_NONE + || r_type == R_NDS32_RELA_GNU_VTENTRY + || r_type == R_NDS32_RELA_GNU_VTINHERIT + || (r_type >= R_NDS32_INSN16 && r_type <= R_NDS32_25_FIXED_RELA) + || r_type == R_NDS32_DATA + || r_type == R_NDS32_TRAN + || (r_type >= R_NDS32_LONGCALL4 && r_type <= R_NDS32_LONGJUMP7)) + continue; + + /* If we enter the fp-as-gp region. Resolve the address + of best fp-base. */ + if (ELF32_R_TYPE (rel->r_info) == R_NDS32_RELAX_REGION_BEGIN + && (rel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG)) + { + int dist; + + /* Distance to relocation of best fp-base is encoded in R_SYM. */ + dist = rel->r_addend >> 16; + fpbase_addr = calculate_memory_address (input_bfd, rel + dist, + local_syms, symtab_hdr); + } + else if (ELF32_R_TYPE (rel->r_info) == R_NDS32_RELAX_REGION_END + && (rel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG)) + { + fpbase_addr = elf_gp (output_bfd); + } + + if (((r_type >= R_NDS32_DWARF2_OP1_RELA + && r_type <= R_NDS32_DWARF2_LEB_RELA) + || r_type >= R_NDS32_RELAX_ENTRY) && !info->relocatable) + continue; + + howto = bfd_elf32_bfd_reloc_type_table_lookup (r_type); + r_symndx = ELF32_R_SYM (rel->r_info); + + /* This is a final link. */ + sym = NULL; + sec = NULL; + h = NULL; + + if (r_symndx < symtab_hdr->sh_info) + { + /* Local symbol. */ + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + + relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + addend = rel->r_addend; + } + else + { + /* External symbol. */ + bfd_boolean warned, ignored, unresolved_reloc; + int symndx = r_symndx - symtab_hdr->sh_info; + + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, + r_symndx, symtab_hdr, sym_hashes, h, sec, + relocation, unresolved_reloc, warned, + ignored); + + /* la $fp, _FP_BASE_ is per-function (region). + Handle it specially. */ + switch ((int) r_type) + { + case R_NDS32_SDA19S0_RELA: + case R_NDS32_SDA15S0_RELA: + case R_NDS32_20_RELA: + if (strcmp (elf_sym_hashes (input_bfd)[symndx]->root.root.string, + FP_BASE_NAME) == 0) + { + relocation = fpbase_addr; + break; + } + } + + } + + if (info->relocatable) + { + /* This is a relocatable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) + rel->r_addend += sec->output_offset + sym->st_value; + + continue; + } + + /* Sanity check the address. */ + if (offset > high_address) + { + r = bfd_reloc_outofrange; + goto check_reloc; + } + + if ((r_type >= R_NDS32_DWARF2_OP1_RELA + && r_type <= R_NDS32_DWARF2_LEB_RELA) + || r_type >= R_NDS32_RELAX_ENTRY) + continue; + + switch ((int) r_type) + { + case R_NDS32_GOTOFF: + /* Relocation is relative to the start of the global offset + table (for ld24 rx, #uimm24), e.g. access at label+addend + + ld24 rx. #label@GOTOFF + addend + sub rx, r12. */ + case R_NDS32_GOTOFF_HI20: + case R_NDS32_GOTOFF_LO12: + case R_NDS32_GOTOFF_LO15: + case R_NDS32_GOTOFF_LO19: + BFD_ASSERT (sgot != NULL); + + relocation -= elf_gp (output_bfd); + break; + + case R_NDS32_9_PLTREL: + case R_NDS32_25_PLTREL: + /* Relocation is to the entry for this symbol in the + procedure linkage table. */ + + /* The native assembler will generate a 25_PLTREL reloc + for a local symbol if you assemble a call from one + section to another when using -K pic. */ + if (h == NULL) + break; + + if (h->forced_local) + break; + + /* We didn't make a PLT entry for this symbol. This + happens when statically linking PIC code, or when + using -Bsymbolic. */ + if (h->plt.offset == (bfd_vma) - 1) + break; + + relocation = (splt->output_section->vma + + splt->output_offset + h->plt.offset); + break; + + case R_NDS32_PLT_GOTREL_HI20: + case R_NDS32_PLT_GOTREL_LO12: + case R_NDS32_PLT_GOTREL_LO15: + case R_NDS32_PLT_GOTREL_LO19: + case R_NDS32_PLT_GOTREL_LO20: + if (h == NULL || h->forced_local || h->plt.offset == (bfd_vma) - 1) + { + /* We didn't make a PLT entry for this symbol. This + happens when statically linking PIC code, or when + using -Bsymbolic. */ + relocation -= elf_gp (output_bfd); + break; + } + + relocation = (splt->output_section->vma + + splt->output_offset + h->plt.offset); + + relocation -= elf_gp (output_bfd); + break; + + case R_NDS32_PLTREL_HI20: + case R_NDS32_PLTREL_LO12: + + /* Relocation is to the entry for this symbol in the + procedure linkage table. */ + + /* The native assembler will generate a 25_PLTREL reloc + for a local symbol if you assemble a call from one + section to another when using -K pic. */ + if (h == NULL) + break; + + if (h->forced_local) + break; + + if (h->plt.offset == (bfd_vma) - 1) + /* We didn't make a PLT entry for this symbol. This + happens when statically linking PIC code, or when + using -Bsymbolic. */ + break; + + if (splt == NULL) + break; + + relocation = (splt->output_section->vma + + splt->output_offset + + h->plt.offset + 4) + - (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset); + + break; + + case R_NDS32_GOTPC20: + /* .got(_GLOBAL_OFFSET_TABLE_) - pc relocation + ld24 rx,#_GLOBAL_OFFSET_TABLE_ */ + relocation = elf_gp (output_bfd); + break; + + case R_NDS32_GOTPC_HI20: + case R_NDS32_GOTPC_LO12: + { + /* .got(_GLOBAL_OFFSET_TABLE_) - pc relocation + bl .+4 + seth rx,#high(_GLOBAL_OFFSET_TABLE_) + or3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4) + or + bl .+4 + seth rx,#shigh(_GLOBAL_OFFSET_TABLE_) + add3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4) + */ + relocation = elf_gp (output_bfd); + relocation -= (input_section->output_section->vma + + input_section->output_offset + rel->r_offset); + break; + } + + case R_NDS32_GOT20: + /* Fall through. */ + case R_NDS32_GOT_HI20: + case R_NDS32_GOT_LO12: + case R_NDS32_GOT_LO15: + case R_NDS32_GOT_LO19: + /* Relocation is to the entry for this symbol in the global + offset table. */ + BFD_ASSERT (sgot != NULL); + + if (h != NULL) + { + bfd_boolean dyn; + bfd_vma off; + + off = h->got.offset; + BFD_ASSERT (off != (bfd_vma) - 1); + dyn = htab->root.dynamic_sections_created; + if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) + || (info->shared + && (info->symbolic + || h->dynindx == -1 + || h->forced_local) && h->def_regular)) + { + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally, or the symbol was forced to be local + because of a version file. We must initialize + this entry in the global offset table. Since the + offset must always be a multiple of 4, we use the + least significant bit to record whether we have + initialized it already. + + When doing a dynamic link, we create a .rela.got + relocation entry to initialize the value. This + is done in the finish_dynamic_symbol routine. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, sgot->contents + off); + h->got.offset |= 1; + } + } + relocation = sgot->output_section->vma + sgot->output_offset + off + - elf_gp (output_bfd); + } + else + { + bfd_vma off; + bfd_byte *loc; + + BFD_ASSERT (local_got_offsets != NULL + && local_got_offsets[r_symndx] != (bfd_vma) - 1); + + off = local_got_offsets[r_symndx]; + + /* The offset must always be a multiple of 4. We use + the least significant bit to record whether we have + already processed this entry. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, sgot->contents + off); + + if (info->shared) + { + asection *srelgot; + Elf_Internal_Rela outrel; + + /* We need to generate a R_NDS32_RELATIVE reloc + for the dynamic linker. */ + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (srelgot != NULL); + + outrel.r_offset = (elf_gp (output_bfd) + + sgot->output_offset + off); + outrel.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE); + outrel.r_addend = relocation; + loc = srelgot->contents; + loc += + srelgot->reloc_count * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + ++srelgot->reloc_count; + } + local_got_offsets[r_symndx] |= 1; + } + relocation = sgot->output_section->vma + sgot->output_offset + off + - elf_gp (output_bfd); + } + + break; + + case R_NDS32_16_RELA: + case R_NDS32_20_RELA: + case R_NDS32_5_RELA: + case R_NDS32_32_RELA: + case R_NDS32_9_PCREL_RELA: + case R_NDS32_WORD_9_PCREL_RELA: + case R_NDS32_10_UPCREL_RELA: + case R_NDS32_15_PCREL_RELA: + case R_NDS32_17_PCREL_RELA: + case R_NDS32_25_PCREL_RELA: + case R_NDS32_HI20_RELA: + case R_NDS32_LO12S3_RELA: + case R_NDS32_LO12S2_RELA: + case R_NDS32_LO12S2_DP_RELA: + case R_NDS32_LO12S2_SP_RELA: + case R_NDS32_LO12S1_RELA: + case R_NDS32_LO12S0_RELA: + case R_NDS32_LO12S0_ORI_RELA: + if (info->shared && r_symndx != 0 + && (input_section->flags & SEC_ALLOC) != 0 + && (eliminate_gc_relocs == 0 + || (sec && (sec->flags & SEC_EXCLUDE) == 0)) + && ((r_type != R_NDS32_9_PCREL_RELA + && r_type != R_NDS32_WORD_9_PCREL_RELA + && r_type != R_NDS32_10_UPCREL_RELA + && r_type != R_NDS32_15_PCREL_RELA + && r_type != R_NDS32_17_PCREL_RELA + && r_type != R_NDS32_25_PCREL_RELA + && !(r_type == R_NDS32_32_RELA + && strcmp (input_section->name, ".eh_frame") == 0)) + || (h != NULL && h->dynindx != -1 + && (!info->symbolic || !h->def_regular)))) + { + Elf_Internal_Rela outrel; + bfd_boolean skip, relocate; + bfd_byte *loc; + + /* When generating a shared object, these relocations + are copied into the output file to be resolved at run + time. */ + + if (sreloc == NULL) + { + const char *name; + + name = bfd_elf_string_from_elf_section + (input_bfd, elf_elfheader (input_bfd)->e_shstrndx, + elf_section_data (input_section)->rela.hdr->sh_name); + if (name == NULL) + return FALSE; + + BFD_ASSERT (strncmp (name, ".rela", 5) == 0 + && strcmp (bfd_get_section_name (input_bfd, + input_section), + name + 5) == 0); + + sreloc = bfd_get_section_by_name (dynobj, name); + BFD_ASSERT (sreloc != NULL); + } + + skip = FALSE; + relocate = FALSE; + + outrel.r_offset = _bfd_elf_section_offset (output_bfd, + info, + input_section, + rel->r_offset); + if (outrel.r_offset == (bfd_vma) - 1) + skip = TRUE; + else if (outrel.r_offset == (bfd_vma) - 2) + skip = TRUE, relocate = TRUE; + outrel.r_offset += (input_section->output_section->vma + + input_section->output_offset); + + if (skip) + memset (&outrel, 0, sizeof outrel); + else if (r_type == R_NDS32_17_PCREL_RELA + || r_type == R_NDS32_15_PCREL_RELA + || r_type == R_NDS32_25_PCREL_RELA) + { + BFD_ASSERT (h != NULL && h->dynindx != -1); + outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); + outrel.r_addend = rel->r_addend; + } + else + { + /* h->dynindx may be -1 if this symbol was marked to + become local. */ + if (h == NULL + || ((info->symbolic || h->dynindx == -1) + && h->def_regular)) + { + relocate = TRUE; + outrel.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE); + outrel.r_addend = relocation + rel->r_addend; + } + else + { + BFD_ASSERT (h->dynindx != -1); + outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); + outrel.r_addend = rel->r_addend; + } + } + + loc = sreloc->contents; + loc += sreloc->reloc_count * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + ++sreloc->reloc_count; + + /* If this reloc is against an external symbol, we do + not want to fiddle with the addend. Otherwise, we + need to include the symbol value so that it becomes + an addend for the dynamic reloc. */ + if (!relocate) + continue; + } + break; + + case R_NDS32_25_ABS_RELA: + if (info->shared) + { + (*_bfd_error_handler) + (_("%s: warning: cannot deal R_NDS32_25_ABS_RELA in shared " + "mode."), bfd_get_filename (input_bfd)); + return FALSE; + } + break; + + case R_NDS32_9_PCREL: + r = nds32_elf_do_9_pcrel_reloc (input_bfd, howto, input_section, + contents, offset, + sec, relocation, addend); + goto check_reloc; + + case R_NDS32_HI20: + { + Elf_Internal_Rela *lorel; + + /* We allow an arbitrary number of HI20 relocs before the + LO12 reloc. This permits gcc to emit the HI and LO relocs + itself. */ + for (lorel = rel + 1; + (lorel < relend + && ELF32_R_TYPE (lorel->r_info) == R_NDS32_HI20); lorel++) + continue; + if (lorel < relend + && (ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S3 + || ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S2 + || ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S1 + || ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S0)) + { + nds32_elf_relocate_hi20 (input_bfd, r_type, rel, lorel, + contents, relocation + addend); + r = bfd_reloc_ok; + } + else + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, offset, relocation, + addend); + } + + goto check_reloc; + + case R_NDS32_GOT17S2_RELA: + case R_NDS32_GOT15S2_RELA: + { + bfd_vma off; + + BFD_ASSERT (sgot != NULL); + + if (h != NULL) + { + bfd_boolean dyn; + + off = h->got.offset; + BFD_ASSERT (off != (bfd_vma) - 1); + + dyn = htab->root.dynamic_sections_created; + if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL + (dyn, info->shared, h) || (info->shared + && (info->symbolic + || h->dynindx == -1 + || h->forced_local) + && h->def_regular)) + { + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally, or the symbol was forced to be local + because of a version file. We must initialize + this entry in the global offset table. Since the + offset must always be a multiple of 4, we use the + least significant bit to record whether we have + initialized it already. + + When doing a dynamic link, we create a .rela.got + relocation entry to initialize the value. This + is done in the finish_dynamic_symbol routine. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, + sgot->contents + off); + h->got.offset |= 1; + } + } + } + else + { + bfd_byte *loc; + + BFD_ASSERT (local_got_offsets != NULL + && local_got_offsets[r_symndx] != (bfd_vma) - 1); + + off = local_got_offsets[r_symndx]; + + /* The offset must always be a multiple of 4. We use + the least significant bit to record whether we have + already processed this entry. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, sgot->contents + off); + + if (info->shared) + { + asection *srelgot; + Elf_Internal_Rela outrel; + + /* We need to generate a R_NDS32_RELATIVE reloc + for the dynamic linker. */ + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (srelgot != NULL); + + outrel.r_offset = (elf_gp (output_bfd) + + sgot->output_offset + off); + outrel.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE); + outrel.r_addend = relocation; + loc = srelgot->contents; + loc += + srelgot->reloc_count * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + ++srelgot->reloc_count; + } + local_got_offsets[r_symndx] |= 1; + } + } + relocation = sgot->output_section->vma + sgot->output_offset + off + - elf_gp (output_bfd); + } + if (relocation & align) + { + /* Incorrect alignment. */ + (*_bfd_error_handler) + (_("%B: warning: unaligned access to GOT entry."), input_bfd); + ret = FALSE; + r = bfd_reloc_dangerous; + goto check_reloc; + } + break; + + case R_NDS32_SDA16S3_RELA: + case R_NDS32_SDA15S3_RELA: + case R_NDS32_SDA15S3: + align = 0x7; + goto handle_sda; + + case R_NDS32_SDA17S2_RELA: + case R_NDS32_SDA15S2_RELA: + case R_NDS32_SDA12S2_SP_RELA: + case R_NDS32_SDA12S2_DP_RELA: + case R_NDS32_SDA15S2: + case R_NDS32_SDA_FP7U2_RELA: + align = 0x3; + goto handle_sda; + + case R_NDS32_SDA18S1_RELA: + case R_NDS32_SDA15S1_RELA: + case R_NDS32_SDA15S1: + align = 0x1; + goto handle_sda; + + case R_NDS32_SDA19S0_RELA: + case R_NDS32_SDA15S0_RELA: + case R_NDS32_SDA15S0: + { + align = 0x0; +handle_sda: + BFD_ASSERT (sec != NULL); + + /* If the symbol is in the abs section, the out_bfd will be null. + This happens when the relocation has a symbol@GOTOFF. */ + r = nds32_elf_final_sda_base (output_bfd, info, &gp, FALSE); + if (r != bfd_reloc_ok) + { + (*_bfd_error_handler) + (_("%B: warning: relocate SDA_BASE failed."), input_bfd); + ret = FALSE; + goto check_reloc; + } + + /* At this point `relocation' contains the object's + address. */ + if (r_type == R_NDS32_SDA_FP7U2_RELA) + { + relocation -= fpbase_addr; + } + else + relocation -= gp; + /* Now it contains the offset from _SDA_BASE_. */ + + /* Make sure alignment is correct. */ + + if (relocation & align) + { + /* Incorrect alignment. */ + (*_bfd_error_handler) + (_("%B(%A): warning: unaligned small data access of type %d."), + input_bfd, input_section, r_type); + ret = FALSE; + goto check_reloc; + } + } + + break; + case R_NDS32_17IFC_PCREL_RELA: + case R_NDS32_10IFCU_PCREL_RELA: + /* do nothing */ + break; + + case R_NDS32_TLS_LE_HI20: + case R_NDS32_TLS_LE_LO12: + case R_NDS32_TLS_LE_20: + case R_NDS32_TLS_LE_15S0: + case R_NDS32_TLS_LE_15S1: + case R_NDS32_TLS_LE_15S2: + if (elf_hash_table (info)->tls_sec != NULL) + relocation -= (elf_hash_table (info)->tls_sec->vma + TP_OFFSET); + break; + case R_NDS32_TLS_IE_HI20: + case R_NDS32_TLS_IE_LO12S2: + { + /* Relocation is to the entry for this symbol in the global + offset table. */ + unsigned int tls_type; + asection *srelgot; + Elf_Internal_Rela outrel; + bfd_vma off; + bfd_byte *loc; + int indx = 0; + + BFD_ASSERT (sgot != NULL); + if (h != NULL) + { + bfd_boolean dyn; + + off = h->got.offset; + BFD_ASSERT (off != (bfd_vma) - 1); + dyn = htab->root.dynamic_sections_created; + tls_type = ((struct elf_nds32_link_hash_entry *) h)->tls_type; + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) + && (!info->shared + || !SYMBOL_REFERENCES_LOCAL (info, h))) + indx = h->dynindx; + } + else + { + /* Never happen currently. */ + BFD_ASSERT (local_got_offsets != NULL + && local_got_offsets[r_symndx] != (bfd_vma) - 1); + + off = local_got_offsets[r_symndx]; + + tls_type = elf32_nds32_local_got_tls_type (input_bfd)[r_symndx]; + } + relocation = sgot->output_section->vma + sgot->output_offset + off; + + if (r_type == R_NDS32_TLS_IE_LO12S2) + break; + + /* The offset must always be a multiple of 4. We use + the least significant bit to record whether we have + already processed this entry. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_boolean need_relocs = FALSE; + srelgot = htab->srelgot; + if ((info->shared || indx != 0) + && (h == NULL + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak)) + { + need_relocs = TRUE; + BFD_ASSERT (srelgot != NULL); + } + if (tls_type & GOT_TLS_IE) + { + if (need_relocs) + { + if (h->dynindx == 0) + outrel.r_addend = relocation - dtpoff_base (info); + else + outrel.r_addend = 0; + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + off); + outrel.r_info = + ELF32_R_INFO (h->dynindx, R_NDS32_TLS_TPOFF); + + loc = srelgot->contents; + loc += + srelgot->reloc_count * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + ++srelgot->reloc_count; + } + else + bfd_put_32 (output_bfd, h->root.u.def.value - TP_OFFSET, + sgot->contents + off); + } + } + } + break; + + /* DON'T fall through. */ + + default: + /* OLD_NDS32_RELOC. */ + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, offset, relocation, addend); + goto check_reloc; + } + + switch ((int) r_type) + { + case R_NDS32_20_RELA: + case R_NDS32_5_RELA: + case R_NDS32_9_PCREL_RELA: + case R_NDS32_WORD_9_PCREL_RELA: + case R_NDS32_10_UPCREL_RELA: + case R_NDS32_15_PCREL_RELA: + case R_NDS32_17_PCREL_RELA: + case R_NDS32_25_PCREL_RELA: + case R_NDS32_25_ABS_RELA: + case R_NDS32_HI20_RELA: + case R_NDS32_LO12S3_RELA: + case R_NDS32_LO12S2_RELA: + case R_NDS32_LO12S2_DP_RELA: + case R_NDS32_LO12S2_SP_RELA: + case R_NDS32_LO12S1_RELA: + case R_NDS32_LO12S0_RELA: + case R_NDS32_LO12S0_ORI_RELA: + case R_NDS32_SDA16S3_RELA: + case R_NDS32_SDA17S2_RELA: + case R_NDS32_SDA18S1_RELA: + case R_NDS32_SDA19S0_RELA: + case R_NDS32_SDA15S3_RELA: + case R_NDS32_SDA15S2_RELA: + case R_NDS32_SDA12S2_DP_RELA: + case R_NDS32_SDA12S2_SP_RELA: + case R_NDS32_SDA15S1_RELA: + case R_NDS32_SDA15S0_RELA: + case R_NDS32_SDA_FP7U2_RELA: + case R_NDS32_9_PLTREL: + case R_NDS32_25_PLTREL: + case R_NDS32_GOT20: + case R_NDS32_GOT_HI20: + case R_NDS32_GOT_LO12: + case R_NDS32_GOT_LO15: + case R_NDS32_GOT_LO19: + case R_NDS32_GOT15S2_RELA: + case R_NDS32_GOT17S2_RELA: + case R_NDS32_GOTPC20: + case R_NDS32_GOTPC_HI20: + case R_NDS32_GOTPC_LO12: + case R_NDS32_GOTOFF: + case R_NDS32_GOTOFF_HI20: + case R_NDS32_GOTOFF_LO12: + case R_NDS32_GOTOFF_LO15: + case R_NDS32_GOTOFF_LO19: + case R_NDS32_PLTREL_HI20: + case R_NDS32_PLTREL_LO12: + case R_NDS32_PLT_GOTREL_HI20: + case R_NDS32_PLT_GOTREL_LO12: + case R_NDS32_PLT_GOTREL_LO15: + case R_NDS32_PLT_GOTREL_LO19: + case R_NDS32_PLT_GOTREL_LO20: + case R_NDS32_17IFC_PCREL_RELA: + case R_NDS32_10IFCU_PCREL_RELA: + case R_NDS32_TLS_LE_HI20: + case R_NDS32_TLS_LE_LO12: + case R_NDS32_TLS_IE_HI20: + case R_NDS32_TLS_IE_LO12S2: + case R_NDS32_TLS_LE_20: + case R_NDS32_TLS_LE_15S0: + case R_NDS32_TLS_LE_15S1: + case R_NDS32_TLS_LE_15S2: + /* Instruction related relocs must handle endian properly. */ + /* NOTE: PIC IS NOT HANDLE YET; DO IT LATER. */ + r = nds32_elf_final_link_relocate (howto, input_bfd, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + + default: + /* All other relocs can use default handler. */ + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + } + +check_reloc: + + if (r != bfd_reloc_ok) + { + /* FIXME: This should be generic enough to go in a utility. */ + const char *name; + + if (h != NULL) + name = h->root.root.string; + else + { + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); + if (name == NULL || *name == '\0') + name = bfd_section_name (input_bfd, sec); + } + + if (errmsg != NULL) + goto common_error; + + switch (r) + { + case bfd_reloc_overflow: + if (!((*info->callbacks->reloc_overflow) + (info, (h ? &h->root : NULL), name, howto->name, + (bfd_vma) 0, input_bfd, input_section, offset))) + return FALSE; + break; + + case bfd_reloc_undefined: + if (!((*info->callbacks->undefined_symbol) + (info, name, input_bfd, input_section, offset, TRUE))) + return FALSE; + break; + + case bfd_reloc_outofrange: + errmsg = _("internal error: out of range error"); + goto common_error; + + case bfd_reloc_notsupported: + errmsg = _("internal error: unsupported relocation error"); + goto common_error; + + case bfd_reloc_dangerous: + errmsg = _("internal error: dangerous error"); + goto common_error; + + default: + errmsg = _("internal error: unknown error"); + /* Fall through. */ + +common_error: + if (!((*info->callbacks->warning) + (info, errmsg, name, input_bfd, input_section, offset))) + return FALSE; + break; + } + } + } + + return ret; +} + +/* Finish up dynamic symbol handling. We set the contents of various + dynamic sections here. */ + +static bfd_boolean +nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, + struct elf_link_hash_entry *h, Elf_Internal_Sym *sym) +{ + struct elf_nds32_link_hash_table *htab; + bfd_byte *loc; + + htab = nds32_elf_hash_table (info); + + if (h->plt.offset != (bfd_vma) - 1) + { + asection *splt; + asection *sgot; + asection *srela; + + bfd_vma plt_index; + bfd_vma got_offset; + bfd_vma local_plt_offset; + Elf_Internal_Rela rela; + + /* This symbol has an entry in the procedure linkage table. Set + it up. */ + + BFD_ASSERT (h->dynindx != -1); + + splt = htab->splt; + sgot = htab->sgotplt; + srela = htab->srelplt; + BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL); + + /* Get the index in the procedure linkage table which + corresponds to this symbol. This is the index of this symbol + in all the symbols for which we are making plt entries. The + first entry in the procedure linkage table is reserved. */ + plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; + + /* Get the offset into the .got table of the entry that + corresponds to this function. Each .got entry is 4 bytes. + The first three are reserved. */ + got_offset = (plt_index + 3) * 4; + + /* Fill in the entry in the procedure linkage table. */ + if (!info->shared) + { + unsigned long insn; + + insn = PLT_ENTRY_WORD0 + (((sgot->output_section->vma + + sgot->output_offset + got_offset) >> 12) + & 0xfffff); + bfd_putb32 (insn, splt->contents + h->plt.offset); + + insn = PLT_ENTRY_WORD1 + (((sgot->output_section->vma + + sgot->output_offset + got_offset) & 0x0fff) + >> 2); + bfd_putb32 (insn, splt->contents + h->plt.offset + 4); + + insn = PLT_ENTRY_WORD2; + bfd_putb32 (insn, splt->contents + h->plt.offset + 8); + + insn = PLT_ENTRY_WORD3 + (plt_index & 0x7ffff); + bfd_putb32 (insn, splt->contents + h->plt.offset + 12); + + insn = PLT_ENTRY_WORD4 + + (((unsigned int) ((-(h->plt.offset + 16)) >> 1)) & 0xffffff); + bfd_putb32 (insn, splt->contents + h->plt.offset + 16); + local_plt_offset = 12; + } + else + { + /* sda_base must be set at this time. */ + unsigned long insn; + long offset; + + /* FIXME, sda_base is 65536, it will damage opcode. */ + /* insn = PLT_PIC_ENTRY_WORD0 + (((got_offset - sda_base) >> 2) & 0x7fff); */ + offset = sgot->output_section->vma + sgot->output_offset + got_offset + - elf_gp (output_bfd); + insn = PLT_PIC_ENTRY_WORD0 + ((offset >> 12) & 0xfffff); + bfd_putb32 (insn, splt->contents + h->plt.offset); + + insn = PLT_PIC_ENTRY_WORD1 + (offset & 0xfff); + bfd_putb32 (insn, splt->contents + h->plt.offset + 4); + + insn = PLT_PIC_ENTRY_WORD2; + bfd_putb32 (insn, splt->contents + h->plt.offset + 8); + + insn = PLT_PIC_ENTRY_WORD3; + bfd_putb32 (insn, splt->contents + h->plt.offset + 12); + + insn = PLT_PIC_ENTRY_WORD4 + (plt_index & 0x7fffff); + bfd_putb32 (insn, splt->contents + h->plt.offset + 16); + + insn = PLT_PIC_ENTRY_WORD5 + + (((unsigned int) ((-(h->plt.offset + 20)) >> 1)) & 0xffffff); + bfd_putb32 (insn, splt->contents + h->plt.offset + 20); + + local_plt_offset = 16; + } + + /* Fill in the entry in the global offset table, + so it will fall through to the next instruction for the first time. */ + bfd_put_32 (output_bfd, + (splt->output_section->vma + splt->output_offset + + h->plt.offset + local_plt_offset), + sgot->contents + got_offset); + + /* Fill in the entry in the .rela.plt section. */ + rela.r_offset = (sgot->output_section->vma + + sgot->output_offset + got_offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_NDS32_JMP_SLOT); + rela.r_addend = 0; + loc = srela->contents; + loc += plt_index * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + + if (!h->def_regular) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value alone. */ + sym->st_shndx = SHN_UNDEF; + if (!h->ref_regular_nonweak) + sym->st_value = 0; + } + } + + if (h->got.offset != (bfd_vma) - 1) + { + asection *sgot; + asection *srela; + Elf_Internal_Rela rela; + + /* This symbol has an entry in the global offset table. + Set it up. */ + + sgot = htab->sgot; + srela = htab->srelgot; + BFD_ASSERT (sgot != NULL && srela != NULL); + + rela.r_offset = (sgot->output_section->vma + + sgot->output_offset + (h->got.offset & ~1)); + + /* If this is a -Bsymbolic link, and the symbol is defined + locally, we just want to emit a RELATIVE reloc. Likewise if + the symbol was forced to be local because of a version file. + The entry in the global offset table will already have been + initialized in the relocate_section function. */ + if (info->shared + && (info->symbolic + || h->dynindx == -1 || h->forced_local) && h->def_regular) + { + rela.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE); + rela.r_addend = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + } + else + { + BFD_ASSERT ((h->got.offset & 1) == 0); + bfd_put_32 (output_bfd, (bfd_vma) 0, + sgot->contents + h->got.offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_NDS32_GLOB_DAT); + rela.r_addend = 0; + } + + loc = srela->contents; + loc += srela->reloc_count * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + ++srela->reloc_count; + } + + if (h->needs_copy) + { + asection *s; + Elf_Internal_Rela rela; + + /* This symbols needs a copy reloc. Set it up. */ + + BFD_ASSERT (h->dynindx != -1 + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)); + + s = bfd_get_section_by_name (h->root.u.def.section->owner, ".rela.bss"); + BFD_ASSERT (s != NULL); + + rela.r_offset = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_NDS32_COPY); + rela.r_addend = 0; + loc = s->contents; + loc += s->reloc_count * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + ++s->reloc_count; + } + + /* Mark some specially defined symbols as absolute. */ + if (strcmp (h->root.root.string, "_DYNAMIC") == 0 + || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) + sym->st_shndx = SHN_ABS; + + return TRUE; +} + + +/* Finish up the dynamic sections. */ + +static bfd_boolean +nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) +{ + struct elf_nds32_link_hash_table *htab; + bfd *dynobj; + asection *sdyn; + asection *sgot; + + htab = nds32_elf_hash_table (info); + dynobj = htab->root.dynobj; + + sgot = htab->sgotplt; + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + + if (htab->root.dynamic_sections_created) + { + asection *splt; + Elf32_External_Dyn *dyncon, *dynconend; + + BFD_ASSERT (sgot != NULL && sdyn != NULL); + + dyncon = (Elf32_External_Dyn *) sdyn->contents; + dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); + + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + asection *s; + + bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + default: + break; + + case DT_PLTGOT: + /* name = ".got"; */ + s = htab->sgot->output_section; + goto get_vma; + case DT_JMPREL: + s = htab->srelplt->output_section; + get_vma: + BFD_ASSERT (s != NULL); + dyn.d_un.d_ptr = s->vma; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_PLTRELSZ: + s = htab->srelplt->output_section; + BFD_ASSERT (s != NULL); + dyn.d_un.d_val = s->size; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_RELASZ: + /* My reading of the SVR4 ABI indicates that the + procedure linkage table relocs (DT_JMPREL) should be + included in the overall relocs (DT_RELA). This is + what Solaris does. However, UnixWare can not handle + that case. Therefore, we override the DT_RELASZ entry + here to make it not include the JMPREL relocs. Since + the linker script arranges for .rela.plt to follow all + other relocation sections, we don't have to worry + about changing the DT_RELA entry. */ + if (htab->srelplt != NULL) + { + s = htab->srelplt->output_section; + dyn.d_un.d_val -= s->size; + } + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + } + } + + /* Fill in the first entry in the procedure linkage table. */ + splt = htab->splt; + if (splt && splt->size > 0) + { + if (info->shared) + { + unsigned long insn; + long offset; + + /* FIXME, sda_base is 65536, it will damage opcode. */ + /* insn = PLT_PIC_ENTRY_WORD0 + (((got_offset - sda_base) >> 2) & 0x7fff); */ + offset = sgot->output_section->vma + sgot->output_offset + 4 + - elf_gp (output_bfd); + insn = PLT0_PIC_ENTRY_WORD0 | ((offset >> 12) & 0xfffff); + bfd_putb32 (insn, splt->contents); + + /* insn = PLT0_PIC_ENTRY_WORD0 | (((8 - sda_base) >> 2) & 0x7fff) ; */ + /* here has a typo? */ + insn = PLT0_PIC_ENTRY_WORD1 | (offset & 0xfff); + bfd_putb32 (insn, splt->contents + 4); + + insn = PLT0_PIC_ENTRY_WORD2; + bfd_putb32 (insn, splt->contents + 8); + + insn = PLT0_PIC_ENTRY_WORD3; + bfd_putb32 (insn, splt->contents + 12); + + insn = PLT0_PIC_ENTRY_WORD4; + bfd_putb32 (insn, splt->contents + 16); + + insn = PLT0_PIC_ENTRY_WORD5; + bfd_putb32 (insn, splt->contents + 20); + } + else + { + unsigned long insn; + unsigned long addr; + + /* addr = .got + 4 */ + addr = sgot->output_section->vma + sgot->output_offset + 4; + insn = PLT0_ENTRY_WORD0 | ((addr >> 12) & 0xfffff); + bfd_putb32 (insn, splt->contents); + + insn = PLT0_ENTRY_WORD1 | (addr & 0x0fff); + bfd_putb32 (insn, splt->contents + 4); + + insn = PLT0_ENTRY_WORD2; + bfd_putb32 (insn, splt->contents + 8); + + insn = PLT0_ENTRY_WORD3; + bfd_putb32 (insn, splt->contents + 12); + + insn = PLT0_ENTRY_WORD4; + bfd_putb32 (insn, splt->contents + 16); + } + + elf_section_data (splt->output_section)->this_hdr.sh_entsize = + PLT_ENTRY_SIZE; + } + } + + /* Fill in the first three entries in the global offset table. */ + if (sgot && sgot->size > 0) + { + if (sdyn == NULL) + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); + else + bfd_put_32 (output_bfd, + sdyn->output_section->vma + sdyn->output_offset, + sgot->contents); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); + + elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; + } + + return TRUE; +} + + +/* Set the right machine number. */ + +static bfd_boolean +nds32_elf_object_p (bfd *abfd) +{ + static unsigned int cur_arch = 0; + + if (E_N1_ARCH != (elf_elfheader (abfd)->e_flags & EF_NDS_ARCH)) + { + /* E_N1_ARCH is a wild card, so it is set only when no others exist. */ + cur_arch = (elf_elfheader (abfd)->e_flags & EF_NDS_ARCH); + } + + switch (cur_arch) + { + default: + case E_N1_ARCH: + bfd_default_set_arch_mach (abfd, bfd_arch_nds32, bfd_mach_n1); + break; + case E_N1H_ARCH: + bfd_default_set_arch_mach (abfd, bfd_arch_nds32, bfd_mach_n1h); + break; + case E_NDS_ARCH_STAR_V2_0: + bfd_default_set_arch_mach (abfd, bfd_arch_nds32, bfd_mach_n1h_v2); + break; + case E_NDS_ARCH_STAR_V3_0: + bfd_default_set_arch_mach (abfd, bfd_arch_nds32, bfd_mach_n1h_v3); + break; + case E_NDS_ARCH_STAR_V3_M: + bfd_default_set_arch_mach (abfd, bfd_arch_nds32, bfd_mach_n1h_v3m); + break; + } + + return TRUE; +} + +/* Store the machine number in the flags field. */ + +static void +nds32_elf_final_write_processing (bfd *abfd, + bfd_boolean linker ATTRIBUTE_UNUSED) +{ + unsigned long val; + static unsigned int cur_mach = 0; + + if (bfd_mach_n1 != bfd_get_mach (abfd)) + { + cur_mach = bfd_get_mach (abfd); + } + + switch (cur_mach) + { + case bfd_mach_n1: + /* Only happen when object is empty, since the case is abandon. */ + val = E_N1_ARCH; + val |= E_NDS_ABI_AABI; + val |= E_NDS32_ELF_VER_1_4; + break; + case bfd_mach_n1h: + val = E_N1H_ARCH; + break; + case bfd_mach_n1h_v2: + val = E_NDS_ARCH_STAR_V2_0; + break; + case bfd_mach_n1h_v3: + val = E_NDS_ARCH_STAR_V3_0; + break; + case bfd_mach_n1h_v3m: + val = E_NDS_ARCH_STAR_V3_M; + break; + default: + val = 0; + break; + } + + elf_elfheader (abfd)->e_flags &= ~EF_NDS_ARCH; + elf_elfheader (abfd)->e_flags |= val; +} + +/* Function to keep NDS32 specific file flags. */ + +static bfd_boolean +nds32_elf_set_private_flags (bfd *abfd, flagword flags) +{ + BFD_ASSERT (!elf_flags_init (abfd) + || elf_elfheader (abfd)->e_flags == flags); + + elf_elfheader (abfd)->e_flags = flags; + elf_flags_init (abfd) = TRUE; + return TRUE; +} + +static unsigned int +convert_e_flags (unsigned int e_flags, unsigned int arch) +{ + if ((e_flags & EF_NDS_ARCH) == E_NDS_ARCH_STAR_V0_9) + { + /* From 0.9 to 1.0. */ + e_flags = (e_flags & (~EF_NDS_ARCH)) | E_NDS_ARCH_STAR_V1_0; + + /* Invert E_NDS32_HAS_NO_MAC_INST. */ + e_flags ^= E_NDS32_HAS_NO_MAC_INST; + if (arch == E_NDS_ARCH_STAR_V1_0) + { + /* Done. */ + return e_flags; + } + } + + /* From 1.0 to 2.0. */ + e_flags = (e_flags & (~EF_NDS_ARCH)) | E_NDS_ARCH_STAR_V2_0; + + /* Clear E_NDS32_HAS_MFUSR_PC_INST. */ + e_flags &= ~E_NDS32_HAS_MFUSR_PC_INST; + + /* Invert E_NDS32_HAS_NO_MAC_INST. */ + e_flags ^= E_NDS32_HAS_NO_MAC_INST; + return e_flags; +} + +static bfd_boolean +nds32_check_vec_size (bfd *ibfd) +{ + static unsigned int nds32_vec_size = 0; + + asection *sec_t = NULL; + bfd_byte *contents = NULL; + + sec_t = bfd_get_section_by_name (ibfd, ".nds32_e_flags"); + + if (sec_t && sec_t->size >= 4) + { + /* Get vec_size in file. */ + unsigned int flag_t; + + nds32_get_section_contents (ibfd, sec_t, &contents, TRUE); + flag_t = bfd_get_32 (ibfd, contents); + + /* The value could only be 4 or 16. */ + + if (!nds32_vec_size) + /* Set if not set yet. */ + nds32_vec_size = (flag_t & 0x3); + else if (nds32_vec_size != (flag_t & 0x3)) + { + (*_bfd_error_handler) (_("%B: ISR vector size mismatch" + " with previous modules, previous %u-byte, current %u-byte"), + ibfd, + nds32_vec_size == 1 ? 4 : nds32_vec_size == 2 ? 16 : 0xffffffff, + (flag_t & 0x3) == 1 ? 4 : (flag_t & 0x3) == 2 ? 16 : 0xffffffff); + return FALSE; + } + else + /* Only keep the first vec_size section. */ + sec_t->flags |= SEC_EXCLUDE; + } + + return TRUE; +} + +/* Merge backend specific data from an object file to the output + object file when linking. */ + +static bfd_boolean +nds32_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) +{ + flagword out_flags; + flagword in_flags; + flagword out_16regs; + flagword in_no_mac; + flagword out_no_mac; + flagword in_16regs; + flagword out_version; + flagword in_version; + flagword out_fpu_config; + flagword in_fpu_config; + + /* TODO: Revise to use object-attributes instead. */ + if (!nds32_check_vec_size (ibfd)) + return FALSE; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return TRUE; + + if (bfd_little_endian (ibfd) != bfd_little_endian (obfd)) + { + (*_bfd_error_handler) + (_("%B: warning: Endian mismatch with previous modules."), ibfd); + + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + in_version = elf_elfheader (ibfd)->e_flags & EF_NDS32_ELF_VERSION; + if (in_version == E_NDS32_ELF_VER_1_2) + { + (*_bfd_error_handler) + (_("%B: warning: Older version of object file encountered, " + "Please recompile with current tool chain."), ibfd); + } + + /* We may need to merge V1 and V2 arch object files to V2. */ + if ((elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH) + != (elf_elfheader (obfd)->e_flags & EF_NDS_ARCH)) + { + /* Need to convert version. */ + if ((elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH) + == E_NDS_ARCH_STAR_RESERVED) + { + elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; + } + else if ((elf_elfheader (obfd)->e_flags & EF_NDS_ARCH) == E_NDS_ARCH_STAR_V0_9 + || (elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH) + > (elf_elfheader (obfd)->e_flags & EF_NDS_ARCH)) + { + elf_elfheader (obfd)->e_flags = + convert_e_flags (elf_elfheader (obfd)->e_flags, + (elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH)); + } + else + { + elf_elfheader (ibfd)->e_flags = + convert_e_flags (elf_elfheader (ibfd)->e_flags, + (elf_elfheader (obfd)->e_flags & EF_NDS_ARCH)); + } + } + + /* Extract some flags. */ + in_flags = elf_elfheader (ibfd)->e_flags + & (~(E_NDS32_HAS_REDUCED_REGS | EF_NDS32_ELF_VERSION + | E_NDS32_HAS_NO_MAC_INST | E_NDS32_FPU_REG_CONF)); + + /* The following flags need special treatment. */ + in_16regs = elf_elfheader (ibfd)->e_flags & E_NDS32_HAS_REDUCED_REGS; + in_no_mac = elf_elfheader (ibfd)->e_flags & E_NDS32_HAS_NO_MAC_INST; + in_fpu_config = elf_elfheader (ibfd)->e_flags & E_NDS32_FPU_REG_CONF; + + /* Extract some flags. */ + out_flags = elf_elfheader (obfd)->e_flags + & (~(E_NDS32_HAS_REDUCED_REGS | EF_NDS32_ELF_VERSION + | E_NDS32_HAS_NO_MAC_INST | E_NDS32_FPU_REG_CONF)); + + /* The following flags need special treatment. */ + out_16regs = elf_elfheader (obfd)->e_flags & E_NDS32_HAS_REDUCED_REGS; + out_no_mac = elf_elfheader (obfd)->e_flags & E_NDS32_HAS_NO_MAC_INST; + out_fpu_config = elf_elfheader (obfd)->e_flags & E_NDS32_FPU_REG_CONF; + out_version = elf_elfheader (obfd)->e_flags & EF_NDS32_ELF_VERSION; + if (!elf_flags_init (obfd)) + { + /* If the input is the default architecture 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 + unitialised values, which surprise surprise, correspond + to the default values. */ + if (bfd_get_arch_info (ibfd)->the_default) + return TRUE; + + elf_flags_init (obfd) = TRUE; + elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; + + if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) + && bfd_get_arch_info (obfd)->the_default) + { + return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), + bfd_get_mach (ibfd)); + } + + return TRUE; + } + + /* Check flag compatibility. */ + if ((in_flags & EF_NDS_ABI) != (out_flags & EF_NDS_ABI)) + { + (*_bfd_error_handler) + (_("%B: error: ABI mismatch with previous modules."), ibfd); + + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + if ((in_flags & EF_NDS_ARCH) != (out_flags & EF_NDS_ARCH)) + { + if (((in_flags & EF_NDS_ARCH) != E_N1_ARCH)) + { + (*_bfd_error_handler) + (_("%B: error: Instruction set mismatch with previous modules."), ibfd); + + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + } + + /* When linking with V1.2 and V1.3 objects together the output is V1.2. + and perf ext1 and DIV are mergerd to perf ext1. */ + if (in_version == E_NDS32_ELF_VER_1_2 || out_version == E_NDS32_ELF_VER_1_2) + { + elf_elfheader (obfd)->e_flags = + (in_flags & (~(E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST))) + | (out_flags & (~(E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST))) + | (((in_flags & (E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST))) + ? E_NDS32_HAS_EXT_INST : 0) + | (((out_flags & (E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST))) + ? E_NDS32_HAS_EXT_INST : 0) + | (in_16regs & out_16regs) | (in_no_mac & out_no_mac) + | ((in_version > out_version) ? out_version : in_version); + } + else + { + if (in_version != out_version) + (*_bfd_error_handler) (_("%B: warning: Incompatible elf-versions %s and %s."), + ibfd, nds32_elfver_strtab[out_version], + nds32_elfver_strtab[in_version]); + + elf_elfheader (obfd)->e_flags = in_flags | out_flags + | (in_16regs & out_16regs) | (in_no_mac & out_no_mac) + | (in_fpu_config > out_fpu_config ? in_fpu_config : out_fpu_config) + | (in_version > out_version ? out_version : in_version); + } + + return TRUE; +} + +/* Display the flags field. */ + +static bfd_boolean +nds32_elf_print_private_bfd_data (bfd *abfd, void *ptr) +{ + FILE *file = (FILE *) ptr; + + BFD_ASSERT (abfd != NULL && ptr != NULL); + + _bfd_elf_print_private_bfd_data (abfd, ptr); + + fprintf (file, _("private flags = %lx"), elf_elfheader (abfd)->e_flags); + + switch (elf_elfheader (abfd)->e_flags & EF_NDS_ARCH) + { + default: + case E_N1_ARCH: + fprintf (file, _(": n1 instructions")); + break; + case E_N1H_ARCH: + fprintf (file, _(": n1h instructions")); + break; + } + + fputc ('\n', file); + + return TRUE; +} + +static unsigned int +nds32_elf_action_discarded (asection *sec) +{ + + if (strncmp + (".gcc_except_table", sec->name, sizeof (".gcc_except_table") - 1) == 0) + return 0; + + return _bfd_elf_default_action_discarded (sec); +} + +static asection * +nds32_elf_gc_mark_hook (asection *sec, struct bfd_link_info *info, + Elf_Internal_Rela *rel, struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) +{ + if (h != NULL) + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_NDS32_GNU_VTINHERIT: + case R_NDS32_GNU_VTENTRY: + case R_NDS32_RELA_GNU_VTINHERIT: + case R_NDS32_RELA_GNU_VTENTRY: + return NULL; + } + + return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); +} + +static bfd_boolean +nds32_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, asection *sec, + const Elf_Internal_Rela *relocs) +{ + /* Update the got entry reference counts for the section being removed. */ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_signed_vma *local_got_refcounts; + const Elf_Internal_Rela *rel, *relend; + + elf_section_data (sec)->local_dynrel = NULL; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + local_got_refcounts = elf_local_got_refcounts (abfd); + + relend = relocs + sec->reloc_count; + for (rel = relocs; rel < relend; rel++) + { + unsigned long r_symndx; + struct elf_link_hash_entry *h = NULL; + + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx >= symtab_hdr->sh_info) + { + /* External symbol. */ + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + } + + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_NDS32_GOT_HI20: + case R_NDS32_GOT_LO12: + case R_NDS32_GOT_LO15: + case R_NDS32_GOT_LO19: + case R_NDS32_GOT17S2_RELA: + case R_NDS32_GOT15S2_RELA: + case R_NDS32_GOTOFF: + case R_NDS32_GOTOFF_HI20: + case R_NDS32_GOTOFF_LO12: + case R_NDS32_GOTOFF_LO15: + case R_NDS32_GOTOFF_LO19: + case R_NDS32_GOT20: + case R_NDS32_GOTPC_HI20: + case R_NDS32_GOTPC_LO12: + case R_NDS32_GOTPC20: + if (h != NULL) + { + if (h->got.refcount > 0) + h->got.refcount--; + } + else + { + if (local_got_refcounts && local_got_refcounts[r_symndx] > 0) + local_got_refcounts[r_symndx]--; + } + break; + + case R_NDS32_16_RELA: + case R_NDS32_20_RELA: + case R_NDS32_5_RELA: + case R_NDS32_32_RELA: + case R_NDS32_HI20_RELA: + case R_NDS32_LO12S3_RELA: + case R_NDS32_LO12S2_RELA: + case R_NDS32_LO12S2_DP_RELA: + case R_NDS32_LO12S2_SP_RELA: + case R_NDS32_LO12S1_RELA: + case R_NDS32_LO12S0_RELA: + case R_NDS32_LO12S0_ORI_RELA: + case R_NDS32_SDA16S3_RELA: + case R_NDS32_SDA17S2_RELA: + case R_NDS32_SDA18S1_RELA: + case R_NDS32_SDA19S0_RELA: + case R_NDS32_SDA15S3_RELA: + case R_NDS32_SDA15S2_RELA: + case R_NDS32_SDA12S2_DP_RELA: + case R_NDS32_SDA12S2_SP_RELA: + case R_NDS32_SDA15S1_RELA: + case R_NDS32_SDA15S0_RELA: + case R_NDS32_SDA_FP7U2_RELA: + case R_NDS32_15_PCREL_RELA: + case R_NDS32_17_PCREL_RELA: + case R_NDS32_25_PCREL_RELA: + if (h != NULL) + { + struct elf_nds32_link_hash_entry *eh; + struct elf_nds32_dyn_relocs **pp; + struct elf_nds32_dyn_relocs *p; + + if (!info->shared && h->plt.refcount > 0) + h->plt.refcount -= 1; + + eh = (struct elf_nds32_link_hash_entry *) h; + + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) + if (p->sec == sec) + { + if (ELF32_R_TYPE (rel->r_info) == R_NDS32_15_PCREL_RELA + || ELF32_R_TYPE (rel->r_info) == R_NDS32_17_PCREL_RELA + || ELF32_R_TYPE (rel->r_info) == R_NDS32_25_PCREL_RELA) + p->pc_count -= 1; + p->count -= 1; + if (p->count == 0) + *pp = p->next; + break; + } + } + break; + + case R_NDS32_9_PLTREL: + case R_NDS32_25_PLTREL: + if (h != NULL) + { + if (h->plt.refcount > 0) + h->plt.refcount--; + } + break; + + default: + break; + } + } + + return TRUE; +} + +/* Look through the relocs for a section during the first phase. + Since we don't do .gots or .plts, we just need to consider the + virtual table relocs for gc. */ + +static bfd_boolean +nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, + asection *sec, const Elf_Internal_Rela *relocs) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + struct elf_nds32_link_hash_table *htab; + bfd *dynobj; + asection *sreloc = NULL; + + if (info->relocatable) + return TRUE; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + sym_hashes_end = + sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym); + if (!elf_bad_symtab (abfd)) + sym_hashes_end -= symtab_hdr->sh_info; + + htab = nds32_elf_hash_table (info); + dynobj = htab->root.dynobj; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + enum elf_nds32_reloc_type r_type; + struct elf_link_hash_entry *h; + unsigned long r_symndx; + int tls_type, old_tls_type; + + r_symndx = ELF32_R_SYM (rel->r_info); + r_type = ELF32_R_TYPE (rel->r_info); + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + } + + /* Some relocs require a global offset table. We create + got section here, since these relocation need got section + and it is not created yet. */ + if (htab->sgot == NULL) + { + switch (r_type) + { + case R_NDS32_GOT_HI20: + case R_NDS32_GOT_LO12: + case R_NDS32_GOT_LO15: + case R_NDS32_GOT_LO19: + case R_NDS32_GOT17S2_RELA: + case R_NDS32_GOT15S2_RELA: + case R_NDS32_GOTOFF: + case R_NDS32_GOTOFF_HI20: + case R_NDS32_GOTOFF_LO12: + case R_NDS32_GOTOFF_LO15: + case R_NDS32_GOTOFF_LO19: + case R_NDS32_GOTPC20: + case R_NDS32_GOTPC_HI20: + case R_NDS32_GOTPC_LO12: + case R_NDS32_GOT20: + case R_NDS32_TLS_IE_HI20: + case R_NDS32_TLS_IE_LO12S2: + if (dynobj == NULL) + htab->root.dynobj = dynobj = abfd; + if (!create_got_section (dynobj, info)) + return FALSE; + break; + + default: + break; + } + } + + switch ((int) r_type) + { + case R_NDS32_GOT_HI20: + case R_NDS32_GOT_LO12: + case R_NDS32_GOT_LO15: + case R_NDS32_GOT_LO19: + case R_NDS32_GOT20: + case R_NDS32_TLS_IE_HI20: + case R_NDS32_TLS_IE_LO12S2: + switch (r_type) + { + case R_NDS32_TLS_IE_HI20: + case R_NDS32_TLS_IE_LO12S2: + tls_type = GOT_TLS_IE; + break; + default: + tls_type = GOT_NORMAL; + break; + } + if (h != NULL) + { + old_tls_type = elf32_nds32_hash_entry (h)->tls_type; + h->got.refcount += 1; + } + else + { + bfd_signed_vma *local_got_refcounts; + + /* This is a global offset table entry for a local + symbol. */ + local_got_refcounts = elf_local_got_refcounts (abfd); + if (local_got_refcounts == NULL) + { + bfd_size_type size; + + size = symtab_hdr->sh_info; + size *= sizeof (bfd_signed_vma); + local_got_refcounts = (bfd_signed_vma *) bfd_zalloc (abfd, size); + if (local_got_refcounts == NULL) + return FALSE; + elf_local_got_refcounts (abfd) = local_got_refcounts; + } + local_got_refcounts[r_symndx] += 1; + old_tls_type = elf32_nds32_local_got_tls_type (abfd)[r_symndx]; + } + + /* We will already have issued an error message if there + is a TLS/non-TLS mismatch, based on the symbol + type. So just combine any TLS types needed. */ + if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL + && tls_type != GOT_NORMAL) + tls_type |= old_tls_type; + + if (old_tls_type != tls_type) + { + if (h != NULL) + elf32_nds32_hash_entry (h)->tls_type = tls_type; + else + elf32_nds32_local_got_tls_type (abfd)[r_symndx] = tls_type; + } + break; + case R_NDS32_9_PLTREL: + case R_NDS32_25_PLTREL: + case R_NDS32_PLTREL_HI20: + case R_NDS32_PLTREL_LO12: + case R_NDS32_PLT_GOTREL_HI20: + case R_NDS32_PLT_GOTREL_LO12: + case R_NDS32_PLT_GOTREL_LO15: + case R_NDS32_PLT_GOTREL_LO19: + case R_NDS32_PLT_GOTREL_LO20: + + /* This symbol requires a procedure linkage table entry. We + actually build the entry in adjust_dynamic_symbol, + because this might be a case of linking PIC code without + linking in any dynamic objects, in which case we don't + need to generate a procedure linkage table after all. */ + + /* If this is a local symbol, we resolve it directly without + creating a procedure linkage table entry. */ + if (h == NULL) + continue; + + if (h->forced_local) + break; + + elf32_nds32_hash_entry (h)->tls_type = GOT_NORMAL; + h->needs_plt = 1; + h->plt.refcount += 1; + break; + + case R_NDS32_16_RELA: + case R_NDS32_20_RELA: + case R_NDS32_5_RELA: + case R_NDS32_32_RELA: + case R_NDS32_HI20_RELA: + case R_NDS32_LO12S3_RELA: + case R_NDS32_LO12S2_RELA: + case R_NDS32_LO12S2_DP_RELA: + case R_NDS32_LO12S2_SP_RELA: + case R_NDS32_LO12S1_RELA: + case R_NDS32_LO12S0_RELA: + case R_NDS32_LO12S0_ORI_RELA: + case R_NDS32_SDA16S3_RELA: + case R_NDS32_SDA17S2_RELA: + case R_NDS32_SDA18S1_RELA: + case R_NDS32_SDA19S0_RELA: + case R_NDS32_SDA15S3_RELA: + case R_NDS32_SDA15S2_RELA: + case R_NDS32_SDA12S2_DP_RELA: + case R_NDS32_SDA12S2_SP_RELA: + case R_NDS32_SDA15S1_RELA: + case R_NDS32_SDA15S0_RELA: + case R_NDS32_SDA_FP7U2_RELA: + case R_NDS32_15_PCREL_RELA: + case R_NDS32_17_PCREL_RELA: + case R_NDS32_25_PCREL_RELA: + + if (h != NULL && !info->shared) + { + h->non_got_ref = 1; + h->plt.refcount += 1; + } + + /* If we are creating a shared library, and this is a reloc against + a global symbol, or a non PC relative reloc against a local + symbol, then we need to copy the reloc into the shared library. + However, if we are linking with -Bsymbolic, we do not need to + copy a reloc against a global symbol which is defined in an + object we are including in the link (i.e., DEF_REGULAR is set). + At this point we have not seen all the input files, so it is + possible that DEF_REGULAR is not set now but will be set later + (it is never cleared). We account for that possibility below by + storing information in the dyn_relocs field of the hash table + entry. A similar situation occurs when creating shared libraries + and symbol visibility changes render the symbol local. + + If on the other hand, we are creating an executable, we may need + to keep relocations for symbols satisfied by a dynamic library + if we manage to avoid copy relocs for the symbol. */ + if ((info->shared + && (sec->flags & SEC_ALLOC) != 0 + && ((r_type != R_NDS32_25_PCREL_RELA + && r_type != R_NDS32_15_PCREL_RELA + && r_type != R_NDS32_17_PCREL_RELA + && !(r_type == R_NDS32_32_RELA + && strcmp (sec->name, ".eh_frame") == 0)) + || (h != NULL + && (!info->symbolic + || h->root.type == bfd_link_hash_defweak + || !h->def_regular)))) + || (!info->shared + && (sec->flags & SEC_ALLOC) != 0 + && h != NULL + && (h->root.type == bfd_link_hash_defweak + || !h->def_regular))) + { + struct elf_nds32_dyn_relocs *p; + struct elf_nds32_dyn_relocs **head; + + if (dynobj == NULL) + htab->root.dynobj = dynobj = abfd; + + /* When creating a shared object, we must copy these + relocs into the output file. We create a reloc + section in dynobj and make room for the reloc. */ + if (sreloc == NULL) + { + const char *name; + + name = bfd_elf_string_from_elf_section + (abfd, elf_elfheader (abfd)->e_shstrndx, + elf_section_data (sec)->rela.hdr->sh_name); + if (name == NULL) + return FALSE; + + BFD_ASSERT (strncmp (name, ".rela", 5) == 0 + && strcmp (bfd_get_section_name (abfd, sec), + name + 5) == 0); + + sreloc = bfd_get_section_by_name (dynobj, name); + if (sreloc == NULL) + { + flagword flags; + + sreloc = bfd_make_section (dynobj, name); + flags = (SEC_HAS_CONTENTS | SEC_READONLY + | SEC_IN_MEMORY | SEC_LINKER_CREATED); + if ((sec->flags & SEC_ALLOC) != 0) + flags |= SEC_ALLOC | SEC_LOAD; + if (sreloc == NULL + || !bfd_set_section_flags (dynobj, sreloc, flags) + || !bfd_set_section_alignment (dynobj, sreloc, 2)) + return FALSE; + + elf_section_type (sreloc) = SHT_RELA; + } + elf_section_data (sec)->sreloc = sreloc; + } + + /* If this is a global symbol, we count the number of + relocations we need for this symbol. */ + if (h != NULL) + head = &((struct elf_nds32_link_hash_entry *) h)->dyn_relocs; + else + { + asection *s; + + Elf_Internal_Sym *isym; + isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, r_symndx); + if (isym == NULL) + return FALSE; + + /* Track dynamic relocs needed for local syms too. */ + s = bfd_section_from_elf_index (abfd, isym->st_shndx); + if (s == NULL) + return FALSE; + + head = ((struct elf_nds32_dyn_relocs **) + &elf_section_data (s)->local_dynrel); + } + + p = *head; + if (p == NULL || p->sec != sec) + { + bfd_size_type amt = sizeof (*p); + p = (struct elf_nds32_dyn_relocs *) bfd_alloc (dynobj, amt); + if (p == NULL) + return FALSE; + p->next = *head; + *head = p; + p->sec = sec; + p->count = 0; + p->pc_count = 0; + } + + p->count += 1; + if (ELF32_R_TYPE (rel->r_info) == R_NDS32_25_PCREL_RELA + || ELF32_R_TYPE (rel->r_info) == R_NDS32_15_PCREL_RELA + || ELF32_R_TYPE (rel->r_info) == R_NDS32_17_PCREL_RELA) + p->pc_count += 1; + } + break; + + /* This relocation describes the C++ object vtable hierarchy. + Reconstruct it for later use during GC. */ + case R_NDS32_RELA_GNU_VTINHERIT: + case R_NDS32_GNU_VTINHERIT: + if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) + return FALSE; + break; + + /* This relocation describes which C++ vtable entries are actually + used. Record for later use during GC. */ + case R_NDS32_GNU_VTENTRY: + if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) + return FALSE; + break; + case R_NDS32_RELA_GNU_VTENTRY: + if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) + return FALSE; + break; + } + } + + return TRUE; +} + +/* Write VAL in uleb128 format to P, returning a pointer to the + following byte. + This code is copied from elf-attr.c. */ + +static bfd_byte * +write_uleb128 (bfd_byte *p, unsigned int val) +{ + bfd_byte c; + do + { + c = val & 0x7f; + val >>= 7; + if (val) + c |= 0x80; + *(p++) = c; + } + while (val); + return p; +} + +static bfd_signed_vma +calculate_offset (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Sym *isymbuf, Elf_Internal_Shdr *symtab_hdr, + int *pic_ext_target) +{ + bfd_signed_vma foff; + bfd_vma symval, addend; + asection *sym_sec; + + /* Get the value of the symbol referred to by the reloc. */ + if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) + { + Elf_Internal_Sym *isym; + + /* A local symbol. */ + isym = isymbuf + ELF32_R_SYM (irel->r_info); + + if (isym->st_shndx == SHN_UNDEF) + sym_sec = bfd_und_section_ptr; + else if (isym->st_shndx == SHN_ABS) + sym_sec = bfd_abs_section_ptr; + else if (isym->st_shndx == SHN_COMMON) + sym_sec = bfd_com_section_ptr; + else + sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); + symval = isym->st_value + sym_sec->output_section->vma + + sym_sec->output_offset; + } + else + { + unsigned long indx; + struct elf_link_hash_entry *h; + bfd *owner; + + /* An external symbol. */ + indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + BFD_ASSERT (h != NULL); + + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + /* This appears to be a reference to an undefined + symbol. Just ignore it--it will be caught by the + regular reloc processing. */ + return 0; + owner = h->root.u.def.section->owner; + if (owner && (elf_elfheader (owner)->e_flags & E_NDS32_HAS_PIC)) + *pic_ext_target = 1; + + if (h->root.u.def.section->flags & SEC_MERGE) + { + sym_sec = h->root.u.def.section; + symval = _bfd_merged_section_offset (abfd, &sym_sec, + elf_section_data (sym_sec)->sec_info, + h->root.u.def.value); + symval = symval + sym_sec->output_section->vma + + sym_sec->output_offset; + } + else + symval = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + } + + addend = irel->r_addend; + + foff = (symval + addend + - (irel->r_offset + sec->output_section->vma + sec->output_offset)); + return foff; +} + +static bfd_vma +calculate_plt_memory_address (bfd *abfd, struct bfd_link_info *link_info, + Elf_Internal_Sym *isymbuf, + Elf_Internal_Rela *irel, + Elf_Internal_Shdr *symtab_hdr) +{ + bfd_vma symval; + + if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) + { + Elf_Internal_Sym *isym; + asection *sym_sec; + /* A local symbol. */ + isym = isymbuf + ELF32_R_SYM (irel->r_info); + + if (isym->st_shndx == SHN_UNDEF) + sym_sec = bfd_und_section_ptr; + else if (isym->st_shndx == SHN_ABS) + sym_sec = bfd_abs_section_ptr; + else if (isym->st_shndx == SHN_COMMON) + sym_sec = bfd_com_section_ptr; + else + sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); + symval = isym->st_value + sym_sec->output_section->vma + + sym_sec->output_offset; + } + else + { + unsigned long indx; + struct elf_link_hash_entry *h; + struct elf_nds32_link_hash_table *htab; + asection *splt; + + /* An external symbol. */ + indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + BFD_ASSERT (h != NULL); + htab = nds32_elf_hash_table (link_info); + splt = htab->splt; + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (h->plt.offset == (bfd_vma) - 1) + { + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + /* This appears to be a reference to an undefined + * symbol. Just ignore it--it will be caught by the + * regular reloc processing. */ + return 0; + symval = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + } + else + symval = splt->output_section->vma + h->plt.offset; + } + + return symval; +} + +static bfd_signed_vma +calculate_plt_offset (bfd *abfd, asection *sec, struct bfd_link_info *link_info, + Elf_Internal_Sym *isymbuf, Elf_Internal_Rela *irel, + Elf_Internal_Shdr *symtab_hdr) +{ + bfd_vma foff; + if ((foff = calculate_plt_memory_address (abfd, link_info, isymbuf, irel, + symtab_hdr)) == 0) + return 0; + else + return foff - (irel->r_offset + + sec->output_section->vma + sec->output_offset); +} + +/* Convert a 32-bit instruction to 16-bit one. + INSN is the input 32-bit instruction, INSN16 is the output 16-bit + instruction. If INSN_TYPE is not NULL, it the CGEN instruction + type of INSN16. Return 1 if successful. */ + +static int +nds32_convert_32_to_16_alu1 (bfd *abfd, uint32_t insn, uint16_t *pinsn16, + int *pinsn_type) +{ + uint16_t insn16 = 0; + int insn_type; + unsigned long mach = bfd_get_mach (abfd); + + if (N32_SH5 (insn) != 0) + return 0; + + switch (N32_SUB5 (insn)) + { + case N32_ALU1_ADD_SLLI: + case N32_ALU1_ADD_SRLI: + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) && N32_IS_RB3 (insn)) + { + insn16 = N16_TYPE333 (ADD333, N32_RT5 (insn), N32_RA5 (insn), + N32_RB5 (insn)); + insn_type = NDS32_INSN_ADD333; + } + else if (N32_IS_RT4 (insn)) + { + if (N32_RT5 (insn) == N32_RA5 (insn)) + insn16 = N16_TYPE45 (ADD45, N32_RT54 (insn), N32_RB5 (insn)); + else if (N32_RT5 (insn) == N32_RB5 (insn)) + insn16 = N16_TYPE45 (ADD45, N32_RT54 (insn), N32_RA5 (insn)); + insn_type = NDS32_INSN_ADD45; + } + break; + + case N32_ALU1_SUB_SLLI: + case N32_ALU1_SUB_SRLI: + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) && N32_IS_RB3 (insn)) + { + insn16 = N16_TYPE333 (SUB333, N32_RT5 (insn), N32_RA5 (insn), + N32_RB5 (insn)); + insn_type = NDS32_INSN_SUB333; + } + else if (N32_IS_RT4 (insn) && N32_RT5 (insn) == N32_RA5 (insn)) + { + insn16 = N16_TYPE45 (SUB45, N32_RT54 (insn), N32_RB5 (insn)); + insn_type = NDS32_INSN_SUB45; + } + break; + + case N32_ALU1_AND_SLLI: + case N32_ALU1_AND_SRLI: + /* and $rt, $rt, $rb -> and33 for v3, v3m. */ + if (mach >= MACH_V3 && N32_IS_RT3 (insn) && N32_IS_RA3 (insn) + && N32_IS_RB3 (insn)) + { + if (N32_RT5 (insn) == N32_RA5 (insn)) + insn16 = N16_MISC33 (AND33, N32_RT5 (insn), N32_RB5 (insn)); + else if (N32_RT5 (insn) == N32_RB5 (insn)) + insn16 = N16_MISC33 (AND33, N32_RT5 (insn), N32_RA5 (insn)); + if (insn16) + insn_type = NDS32_INSN_AND33; + } + break; + + case N32_ALU1_XOR_SLLI: + case N32_ALU1_XOR_SRLI: + /* xor $rt, $rt, $rb -> xor33 for v3, v3m. */ + if (mach >= MACH_V3 && N32_IS_RT3 (insn) && N32_IS_RA3 (insn) + && N32_IS_RB3 (insn)) + { + if (N32_RT5 (insn) == N32_RA5 (insn)) + insn16 = N16_MISC33 (XOR33, N32_RT5 (insn), N32_RB5 (insn)); + else if (N32_RT5 (insn) == N32_RB5 (insn)) + insn16 = N16_MISC33 (XOR33, N32_RT5 (insn), N32_RA5 (insn)); + if (insn16) + insn_type = NDS32_INSN_XOR33; + } + break; + + case N32_ALU1_OR_SLLI: + case N32_ALU1_OR_SRLI: + /* or $rt, $rt, $rb -> or33 for v3, v3m. */ + if (mach >= MACH_V3 && N32_IS_RT3 (insn) && N32_IS_RA3 (insn) + && N32_IS_RB3 (insn)) + { + if (N32_RT5 (insn) == N32_RA5 (insn)) + insn16 = N16_MISC33 (OR33, N32_RT5 (insn), N32_RB5 (insn)); + else if (N32_RT5 (insn) == N32_RB5 (insn)) + insn16 = N16_MISC33 (OR33, N32_RT5 (insn), N32_RA5 (insn)); + if (insn16) + insn_type = NDS32_INSN_OR33; + } + break; + case N32_ALU1_NOR: + /* nor $rt, $ra, $ra -> not33 for v3, v3m. */ + if (mach >= MACH_V3 && N32_IS_RT3 (insn) && N32_IS_RB3 (insn) + && N32_RA5 (insn) == N32_RB5 (insn)) + { + insn16 = N16_MISC33 (NOT33, N32_RT5 (insn), N32_RA5 (insn)); + insn_type = NDS32_INSN_NOT33; + } + break; + case N32_ALU1_SRAI: + if (N32_IS_RT4 (insn) && N32_RT5 (insn) == N32_RA5 (insn)) + { + insn16 = N16_TYPE45 (SRAI45, N32_RT54 (insn), N32_UB5 (insn)); + insn_type = NDS32_INSN_SRAI45; + } + break; + + case N32_ALU1_SRLI: + if (N32_IS_RT4 (insn) && N32_RT5 (insn) == N32_RA5 (insn)) + { + insn16 = N16_TYPE45 (SRLI45, N32_RT54 (insn), N32_UB5 (insn)); + insn_type = NDS32_INSN_SRLI45; + } + break; + + case N32_ALU1_SLLI: + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) && N32_UB5 (insn) < 8) + { + insn16 = N16_TYPE333 (SLLI333, N32_RT5 (insn), N32_RA5 (insn), + N32_UB5 (insn)); + insn_type = NDS32_INSN_SLLI333; + } + break; + + case N32_ALU1_ZEH: + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn)) + { + insn16 = N16_BFMI333 (ZEH33, N32_RT5 (insn), N32_RA5 (insn)); + insn_type = NDS32_INSN_ZEH33; + } + break; + + case N32_ALU1_SEB: + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn)) + { + insn16 = N16_BFMI333 (SEB33, N32_RT5 (insn), N32_RA5 (insn)); + insn_type = NDS32_INSN_SEB33; + } + break; + + case N32_ALU1_SEH: + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn)) + { + insn16 = N16_BFMI333 (SEH33, N32_RT5 (insn), N32_RA5 (insn)); + insn_type = NDS32_INSN_SEH33; + } + break; + + case N32_ALU1_SLT: + if (N32_RT5 (insn) == REG_R15 && N32_IS_RA4 (insn)) + { + /* Implicit r15. */ + insn16 = N16_TYPE45 (SLT45, N32_RA54 (insn), N32_RB5 (insn)); + insn_type = NDS32_INSN_SLT45; + } + break; + + case N32_ALU1_SLTS: + if (N32_RT5 (insn) == REG_R15 && N32_IS_RA4 (insn)) + { + /* Implicit r15. */ + insn16 = N16_TYPE45 (SLTS45, N32_RA54 (insn), N32_RB5 (insn)); + insn_type = NDS32_INSN_SLTS45; + } + break; + } + + if ((insn16 & 0x8000) == 0) + return 0; + + if (pinsn16) + *pinsn16 = insn16; + if (pinsn_type) + *pinsn_type = insn_type; + return 1; +} + +static int +nds32_convert_32_to_16_alu2 (bfd *abfd, uint32_t insn, uint16_t *pinsn16, + int *pinsn_type) +{ + uint16_t insn16 = 0; + int insn_type; + unsigned long mach = bfd_get_mach (abfd); + + /* TODO: bset, bclr, btgl, btst. */ + if (__GF (insn, 6, 4) != 0) + return 0; + + switch (N32_IMMU (insn, 6)) + { + case N32_ALU2_MUL: + if (mach >= MACH_V3 && N32_IS_RT3 (insn) && N32_IS_RA3 (insn) + && N32_IS_RB3 (insn)) + { + if (N32_RT5 (insn) == N32_RA5 (insn)) + insn16 = N16_MISC33 (MUL33, N32_RT5 (insn), N32_RB5 (insn)); + else if (N32_RT5 (insn) == N32_RB5 (insn)) + insn16 = N16_MISC33 (MUL33, N32_RT5 (insn), N32_RA5 (insn)); + if (insn16) + insn_type = NDS32_INSN_MUL33; + } + } + + if ((insn16 & 0x8000) == 0) + return 0; + + if (pinsn16) + *pinsn16 = insn16; + if (pinsn_type) + *pinsn_type = insn_type; + return 1; +} + +int +nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16, + int *pinsn_type) +{ + int op6; + uint16_t insn16 = 0; + int insn_type; + unsigned long mach = bfd_get_mach (abfd); + + /* Decode 32-bit instruction. */ + if (insn & 0x80000000) + { + /* Not 32-bit insn. */ + return 0; + } + + op6 = N32_OP6 (insn); + + /* Convert it to 16-bit instruction. */ + switch (op6) + { + case N32_OP6_MOVI: + if (IS_WITHIN_S (N32_IMM20S (insn), 5)) + { + insn16 = N16_TYPE55 (MOVI55, N32_RT5 (insn), N32_IMM20S (insn)); + insn_type = NDS32_INSN_MOVI55; + } + else if (mach >= MACH_V3 && N32_IMM20S (insn) >= 16 + && N32_IMM20S (insn) < 48 && N32_IS_RT4 (insn)) + { + insn16 = N16_TYPE45 (MOVPI45, N32_RT54 (insn), + N32_IMM20S (insn) - 16); + insn_type = NDS32_INSN_MOVPI45; + } + break; + + case N32_OP6_ADDI: + if (N32_IMM15S (insn) == 0) + { + /* Do not convert `addi $sp, $sp, 0' to `mov55 $sp, $sp', + because `mov55 $sp, $sp' is ifret16 in V3 ISA. */ + if (mach <= MACH_V2 + || N32_RT5 (insn) != REG_SP || N32_RA5 (insn) != REG_SP) + { + insn16 = N16_TYPE55 (MOV55, N32_RT5 (insn), N32_RA5 (insn)); + insn_type = NDS32_INSN_MOV55; + } + } + else if (N32_IMM15S (insn) > 0) + { + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) && N32_IMM15S (insn) < 8) + { + insn16 = N16_TYPE333 (ADDI333, N32_RT5 (insn), N32_RA5 (insn), + N32_IMM15S (insn)); + insn_type = NDS32_INSN_ADDI333; + } + else if (N32_IS_RT4 (insn) && N32_RT5 (insn) == N32_RA5 (insn) + && N32_IMM15S (insn) < 32) + { + insn16 = N16_TYPE45 (ADDI45, N32_RT54 (insn), N32_IMM15S (insn)); + insn_type = NDS32_INSN_ADDI45; + } + else if (mach >= MACH_V2 && N32_RT5 (insn) == REG_SP + && N32_RT5 (insn) == N32_RA5 (insn) + && N32_IMM15S (insn) < 512) + { + insn16 = N16_TYPE10 (ADDI10S, N32_IMM15S (insn)); + insn_type = NDS32_INSN_ADDI10_SP; + } + else if (mach >= MACH_V3 && N32_IS_RT3 (insn) + && N32_RA5 (insn) == REG_SP && N32_IMM15S (insn) < 256 + && (N32_IMM15S (insn) % 4 == 0)) + { + insn16 = N16_TYPE36 (ADDRI36_SP, N32_RT5 (insn), + N32_IMM15S (insn) >> 2); + insn_type = NDS32_INSN_ADDRI36_SP; + } + } + else + { + /* Less than 0. */ + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) && N32_IMM15S (insn) > -8) + { + insn16 = N16_TYPE333 (SUBI333, N32_RT5 (insn), N32_RA5 (insn), + 0 - N32_IMM15S (insn)); + insn_type = NDS32_INSN_SUBI333; + } + else if (N32_IS_RT4 (insn) && N32_RT5 (insn) == N32_RA5 (insn) + && N32_IMM15S (insn) > -32) + { + insn16 = N16_TYPE45 (SUBI45, N32_RT54 (insn), + 0 - N32_IMM15S (insn)); + insn_type = NDS32_INSN_SUBI45; + } + else if (mach >= MACH_V2 && N32_RT5 (insn) == REG_SP + && N32_RT5 (insn) == N32_RA5 (insn) + && N32_IMM15S (insn) >= -512) + { + insn16 = N16_TYPE10 (ADDI10S, N32_IMM15S (insn)); + insn_type = NDS32_INSN_ADDI10_SP; + } + } + break; + + case N32_OP6_ORI: + if (N32_IMM15S (insn) == 0) + { + /* Do not convert `ori $sp, $sp, 0' to `mov55 $sp, $sp', + because `mov55 $sp, $sp' is ifret16 in V3 ISA. */ + if (mach <= MACH_V2 + || N32_RT5 (insn) != REG_SP || N32_RA5 (insn) != REG_SP) + { + insn16 = N16_TYPE55 (MOV55, N32_RT5 (insn), N32_RA5 (insn)); + insn_type = NDS32_INSN_MOV55; + } + } + break; + + case N32_OP6_SUBRI: + if (mach >= MACH_V3 && N32_IS_RT3 (insn) + && N32_IS_RA3 (insn) && N32_IMM15S (insn) == 0) + { + insn16 = N16_MISC33 (NEG33, N32_RT5 (insn), N32_RA5 (insn)); + insn_type = NDS32_INSN_NEG33; + } + break; + + case N32_OP6_ANDI: + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn)) + { + if (N32_IMM15U (insn) == 1) + { + insn16 = N16_BFMI333 (XLSB33, N32_RT5 (insn), N32_RA5 (insn)); + insn_type = NDS32_INSN_XLSB33; + } + else if (N32_IMM15U (insn) == 0x7ff) + { + insn16 = N16_BFMI333 (X11B33, N32_RT5 (insn), N32_RA5 (insn)); + insn_type = NDS32_INSN_X11B33; + } + else if (N32_IMM15U (insn) == 0xff) + { + insn16 = N16_BFMI333 (ZEB33, N32_RT5 (insn), N32_RA5 (insn)); + insn_type = NDS32_INSN_ZEB33; + } + else if (mach >= MACH_V3 && N32_RT5 (insn) == N32_RA5 (insn) + && N32_IMM15U (insn) < 256) + { + int imm15u = N32_IMM15U (insn); + + if (__builtin_popcount (imm15u) == 1) + { + /* BMSKI33 */ + int imm3u = __builtin_ctz (imm15u); + + insn16 = N16_BFMI333 (BMSKI33, N32_RT5 (insn), imm3u); + insn_type = NDS32_INSN_BMSKI33; + } + else if (imm15u != 0 && __builtin_popcount (imm15u + 1) == 1) + { + /* FEXTI33 */ + int imm3u = __builtin_ctz (imm15u + 1) - 1; + + insn16 = N16_BFMI333 (FEXTI33, N32_RT5 (insn), imm3u); + insn_type = NDS32_INSN_FEXTI33; + } + } + } + break; + + case N32_OP6_SLTI: + if (N32_RT5 (insn) == REG_R15 && N32_IS_RA4 (insn) + && IS_WITHIN_U (N32_IMM15S (insn), 5)) + { + insn16 = N16_TYPE45 (SLTI45, N32_RA54 (insn), N32_IMM15S (insn)); + insn_type = NDS32_INSN_SLTI45; + } + break; + + case N32_OP6_SLTSI: + if (N32_RT5 (insn) == REG_R15 && N32_IS_RA4 (insn) + && IS_WITHIN_U (N32_IMM15S (insn), 5)) + { + insn16 = N16_TYPE45 (SLTSI45, N32_RA54 (insn), N32_IMM15S (insn)); + insn_type = NDS32_INSN_SLTSI45; + } + break; + + case N32_OP6_LWI: + if (N32_IS_RT4 (insn) && N32_IMM15S (insn) == 0) + { + insn16 = N16_TYPE45 (LWI450, N32_RT54 (insn), N32_RA5 (insn)); + insn_type = NDS32_INSN_LWI450; + } + else if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) + && IS_WITHIN_U (N32_IMM15S (insn), 3)) + { + insn16 = N16_TYPE333 (LWI333, N32_RT5 (insn), N32_RA5 (insn), + N32_IMM15S (insn)); + insn_type = NDS32_INSN_LWI333; + } + else if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_FP + && IS_WITHIN_U (N32_IMM15S (insn), 7)) + { + insn16 = N16_TYPE37 (XWI37, N32_RT5 (insn), 0, N32_IMM15S (insn)); + insn_type = NDS32_INSN_LWI37; + } + else if (mach >= MACH_V2 && N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_SP + && IS_WITHIN_U (N32_IMM15S (insn), 7)) + { + insn16 = N16_TYPE37 (XWI37SP, N32_RT5 (insn), 0, N32_IMM15S (insn)); + insn_type = NDS32_INSN_LWI37_SP; + } + else if (mach >= MACH_V2 && N32_IS_RT4 (insn) && N32_RA5 (insn) == REG_R8 + && -32 <= N32_IMM15S (insn) && N32_IMM15S (insn) < 0) + { + insn16 = N16_TYPE45 (LWI45_FE, N32_RT54 (insn), + N32_IMM15S (insn) + 32); + insn_type = NDS32_INSN_LWI45_FE; + } + break; + + case N32_OP6_SWI: + if (N32_IS_RT4 (insn) && N32_IMM15S (insn) == 0) + { + insn16 = N16_TYPE45 (SWI450, N32_RT54 (insn), N32_RA5 (insn)); + insn_type = NDS32_INSN_SWI450; + } + else if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) + && IS_WITHIN_U (N32_IMM15S (insn), 3)) + { + insn16 = N16_TYPE333 (SWI333, N32_RT5 (insn), N32_RA5 (insn), + N32_IMM15S (insn)); + insn_type = NDS32_INSN_SWI333; + } + else if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_FP + && IS_WITHIN_U (N32_IMM15S (insn), 7)) + { + insn16 = N16_TYPE37 (XWI37, N32_RT5 (insn), 1, N32_IMM15S (insn)); + insn_type = NDS32_INSN_SWI37; + } + else if (mach >= MACH_V2 && N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_SP + && IS_WITHIN_U (N32_IMM15S (insn), 7)) + { + insn16 = N16_TYPE37 (XWI37SP, N32_RT5 (insn), 1, N32_IMM15S (insn)); + insn_type = NDS32_INSN_SWI37_SP; + } + break; + + case N32_OP6_LWI_BI: + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) + && IS_WITHIN_U (N32_IMM15S (insn), 3)) + { + insn16 = N16_TYPE333 (LWI333_BI, N32_RT5 (insn), N32_RA5 (insn), + N32_IMM15S (insn)); + insn_type = NDS32_INSN_LWI333_BI; + } + break; + + case N32_OP6_SWI_BI: + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) + && IS_WITHIN_U (N32_IMM15S (insn), 3)) + { + insn16 = N16_TYPE333 (SWI333_BI, N32_RT5 (insn), N32_RA5 (insn), + N32_IMM15S (insn)); + insn_type = NDS32_INSN_SWI333_BI; + } + break; + + case N32_OP6_LHI: + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) + && IS_WITHIN_U (N32_IMM15S (insn), 3)) + { + insn16 = N16_TYPE333 (LHI333, N32_RT5 (insn), N32_RA5 (insn), + N32_IMM15S (insn)); + insn_type = NDS32_INSN_LHI333; + } + break; + + case N32_OP6_SHI: + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) + && IS_WITHIN_U (N32_IMM15S (insn), 3)) + { + insn16 = N16_TYPE333 (SHI333, N32_RT5 (insn), N32_RA5 (insn), + N32_IMM15S (insn)); + insn_type = NDS32_INSN_SHI333; + } + break; + + case N32_OP6_LBI: + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) + && IS_WITHIN_U (N32_IMM15S (insn), 3)) + { + insn16 = N16_TYPE333 (LBI333, N32_RT5 (insn), N32_RA5 (insn), + N32_IMM15S (insn)); + insn_type = NDS32_INSN_LBI333; + } + break; + + case N32_OP6_SBI: + if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) + && IS_WITHIN_U (N32_IMM15S (insn), 3)) + { + insn16 = N16_TYPE333 (SBI333, N32_RT5 (insn), N32_RA5 (insn), + N32_IMM15S (insn)); + insn_type = NDS32_INSN_SBI333; + } + break; + + case N32_OP6_ALU1: + return nds32_convert_32_to_16_alu1 (abfd, insn, pinsn16, pinsn_type); + + case N32_OP6_ALU2: + return nds32_convert_32_to_16_alu2 (abfd, insn, pinsn16, pinsn_type); + + case N32_OP6_BR1: + if (!IS_WITHIN_S (N32_IMM14S (insn), 8)) + goto done; + + if ((insn & __BIT (14)) == 0) + { + /* N32_BR1_BEQ */ + if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5 + && N32_RT5 (insn) != REG_R5) + insn16 = N16_TYPE38 (BEQS38, N32_RT5 (insn), N32_IMM14S (insn)); + else if (N32_IS_RA3 (insn) && N32_RT5 (insn) == REG_R5 + && N32_RA5 (insn) != REG_R5) + insn16 = N16_TYPE38 (BEQS38, N32_RA5 (insn), N32_IMM14S (insn)); + insn_type = NDS32_INSN_BEQS38; + break; + } + else + { + /* N32_BR1_BNE */ + if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5 + && N32_RT5 (insn) != REG_R5) + insn16 = N16_TYPE38 (BNES38, N32_RT5 (insn), N32_IMM14S (insn)); + else if (N32_IS_RA3 (insn) && N32_RT5 (insn) == REG_R5 + && N32_RA5 (insn) != REG_R5) + insn16 = N16_TYPE38 (BNES38, N32_RA5 (insn), N32_IMM14S (insn)); + insn_type = NDS32_INSN_BNES38; + break; + } + break; + + case N32_OP6_BR2: + switch (N32_BR2_SUB (insn)) + { + case N32_BR2_BEQZ: + if (N32_IS_RT3 (insn) && IS_WITHIN_S (N32_IMM16S (insn), 8)) + { + insn16 = N16_TYPE38 (BEQZ38, N32_RT5 (insn), N32_IMM16S (insn)); + insn_type = NDS32_INSN_BEQZ38; + } + else if (N32_RT5 (insn) == REG_R15 + && IS_WITHIN_S (N32_IMM16S (insn), 8)) + { + insn16 = N16_TYPE8 (BEQZS8, N32_IMM16S (insn)); + insn_type = NDS32_INSN_BEQZS8; + } + break; + + case N32_BR2_BNEZ: + if (N32_IS_RT3 (insn) && IS_WITHIN_S (N32_IMM16S (insn), 8)) + { + insn16 = N16_TYPE38 (BNEZ38, N32_RT5 (insn), N32_IMM16S (insn)); + insn_type = NDS32_INSN_BNEZ38; + } + else if (N32_RT5 (insn) == REG_R15 + && IS_WITHIN_S (N32_IMM16S (insn), 8)) + { + insn16 = N16_TYPE8 (BNEZS8, N32_IMM16S (insn)); + insn_type = NDS32_INSN_BNEZS8; + } + break; + + case N32_BR2_IFCALL: + if (IS_WITHIN_U (N32_IMM16S (insn), 9)) + { + insn16 = N16_TYPE9 (IFCALL9, N32_IMM16S (insn)); + insn_type = NDS32_INSN_IFCALL9; + } + break; + } + break; + + case N32_OP6_JI: + if ((insn & __BIT (24)) == 0) + { + /* N32_JI_J */ + if (IS_WITHIN_S (N32_IMM24S (insn), 8)) + { + insn16 = N16_TYPE8 (J8, N32_IMM24S (insn)); + insn_type = NDS32_INSN_J8; + } + } + break; + + case N32_OP6_JREG: + if (__GF (insn, 8, 2) != 0) + goto done; + + switch (N32_IMMU (insn, 5)) + { + case N32_JREG_JR: + if (N32_JREG_HINT (insn) == 0) + { + /* jr */ + insn16 = N16_TYPE5 (JR5, N32_RB5 (insn)); + insn_type = NDS32_INSN_JR5; + } + else if (N32_JREG_HINT (insn) == 1) + { + /* ret */ + insn16 = N16_TYPE5 (RET5, N32_RB5 (insn)); + insn_type = NDS32_INSN_RET5; + } + else if (N32_JREG_HINT (insn) == 3) + { + /* ifret = mov55 $sp, $sp */ + insn16 = N16_TYPE55 (MOV55, REG_SP, REG_SP); + insn_type = NDS32_INSN_IFRET; + } + break; + + case N32_JREG_JRAL: + /* It's convertible when return rt5 is $lp and address + translation is kept. */ + if (N32_RT5 (insn) == REG_LP && N32_JREG_HINT (insn) == 0) + { + insn16 = N16_TYPE5 (JRAL5, N32_RB5 (insn)); + insn_type = NDS32_INSN_JRAL5; + } + break; + } + break; + + case N32_OP6_MISC: + if (N32_SUB5 (insn) == N32_MISC_BREAK && N32_SWID (insn) < 32) + { + /* For v3, swid above 31 are used for ex9.it. */ + insn16 = N16_TYPE5 (BREAK16, N32_SWID (insn)); + insn_type = NDS32_INSN_BREAK16; + } + break; + + default: + /* This instruction has no 16-bit variant. */ + goto done; + } + +done: + /* Bit-15 of insn16 should be set for a valid instruction. */ + if ((insn16 & 0x8000) == 0) + return 0; + + if (pinsn16) + *pinsn16 = insn16; + if (pinsn_type) + *pinsn_type = insn_type; + return 1; +} + +static int +special_convert_32_to_16 (unsigned long insn, uint16_t *pinsn16, + Elf_Internal_Rela *reloc) +{ + uint16_t insn16 = 0; + + if ((reloc->r_addend & R_NDS32_INSN16_FP7U2_FLAG) == 0 + || (ELF32_R_TYPE (reloc->r_info) != R_NDS32_INSN16)) + return 0; + + if (!N32_IS_RT3 (insn)) + return 0; + + switch (N32_OP6 (insn)) + { + case N32_OP6_LWI: + if (N32_RA5 (insn) == REG_GP && IS_WITHIN_U (N32_IMM15S (insn), 7)) + insn16 = N16_TYPE37 (XWI37, N32_RT5 (insn), 0, N32_IMM15S (insn)); + break; + case N32_OP6_SWI: + if (N32_RA5 (insn) == REG_GP && IS_WITHIN_U (N32_IMM15S (insn), 7)) + insn16 = N16_TYPE37 (XWI37, N32_RT5 (insn), 1, N32_IMM15S (insn)); + break; + case N32_OP6_HWGP: + if (!IS_WITHIN_U (N32_IMM17S (insn), 7)) + break; + + if (__GF (insn, 17, 3) == 6) + insn16 = N16_TYPE37 (XWI37, N32_RT5 (insn), 0, N32_IMM17S (insn)); + else if (__GF (insn, 17, 3) == 7) + insn16 = N16_TYPE37 (XWI37, N32_RT5 (insn), 1, N32_IMM17S (insn)); + break; + } + + if ((insn16 & 0x8000) == 0) + return 0; + + *pinsn16 = insn16; + return 1; +} + +/* Convert a 16-bit instruction to 32-bit one. + INSN16 it the input and PINSN it the point to output. + Return non-zero on successful. Otherwise 0 is returned. */ + +int +nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn) +{ + uint32_t insn = 0xffffffff; + unsigned long mach = bfd_get_mach (abfd); + + /* NOTE: push25, pop25 and movd44 do not have 32-bit variants. */ + + switch (__GF (insn16, 9, 6)) + { + case 0x4: /* add45 */ + insn = N32_ALU1 (ADD, N16_RT4 (insn16), N16_RT4 (insn16), + N16_RA5 (insn16)); + goto done; + case 0x5: /* sub45 */ + insn = N32_ALU1 (SUB, N16_RT4 (insn16), N16_RT4 (insn16), + N16_RA5 (insn16)); + goto done; + case 0x6: /* addi45 */ + insn = N32_TYPE2 (ADDI, N16_RT4 (insn16), N16_RT4 (insn16), + N16_IMM5U (insn16)); + goto done; + case 0x7: /* subi45 */ + insn = N32_TYPE2 (ADDI, N16_RT4 (insn16), N16_RT4 (insn16), + -N16_IMM5U (insn16)); + goto done; + case 0x8: /* srai45 */ + insn = N32_ALU1 (SRAI, N16_RT4 (insn16), N16_RT4 (insn16), + N16_IMM5U (insn16)); + goto done; + case 0x9: /* srli45 */ + insn = N32_ALU1 (SRLI, N16_RT4 (insn16), N16_RT4 (insn16), + N16_IMM5U (insn16)); + goto done; + case 0xa: /* slli333 */ + insn = N32_ALU1 (SLLI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); + goto done; + case 0xc: /* add333 */ + insn = N32_ALU1 (ADD, N16_RT3 (insn16), N16_RA3 (insn16), + N16_RB3 (insn16)); + goto done; + case 0xd: /* sub333 */ + insn = N32_ALU1 (SUB, N16_RT3 (insn16), N16_RA3 (insn16), + N16_RB3 (insn16)); + goto done; + case 0xe: /* addi333 */ + insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); + goto done; + case 0xf: /* subi333 */ + insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), N16_RA3 (insn16), + -N16_IMM3U (insn16)); + goto done; + case 0x10: /* lwi333 */ + insn = N32_TYPE2 (LWI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); + goto done; + case 0x12: /* lhi333 */ + insn = N32_TYPE2 (LHI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); + goto done; + case 0x13: /* lbi333 */ + insn = N32_TYPE2 (LBI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); + goto done; + case 0x11: /* lwi333.bi */ + insn = N32_TYPE2 (LWI_BI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); + goto done; + case 0x14: /* swi333 */ + insn = N32_TYPE2 (SWI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); + goto done; + case 0x16: /* shi333 */ + insn = N32_TYPE2 (SHI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); + goto done; + case 0x17: /* sbi333 */ + insn = N32_TYPE2 (SBI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); + goto done; + case 0x15: /* swi333.bi */ + insn = N32_TYPE2 (SWI_BI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); + goto done; + case 0x18: /* addri36.sp */ + insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), REG_SP, + N16_IMM6U (insn16) << 2); + goto done; + case 0x19: /* lwi45.fe */ + insn = N32_TYPE2 (LWI, N16_RT4 (insn16), REG_R8, + (N16_IMM5U (insn16) - 32)); + goto done; + case 0x1a: /* lwi450 */ + insn = N32_TYPE2 (LWI, N16_RT4 (insn16), N16_RA5 (insn16), 0); + goto done; + case 0x1b: /* swi450 */ + insn = N32_TYPE2 (SWI, N16_RT4 (insn16), N16_RA5 (insn16), 0); + goto done; + + /* These are r15 implied instructions. */ + case 0x30: /* slts45 */ + insn = N32_ALU1 (SLTS, REG_TA, N16_RT4 (insn16), N16_RA5 (insn16)); + goto done; + case 0x31: /* slt45 */ + insn = N32_ALU1 (SLT, REG_TA, N16_RT4 (insn16), N16_RA5 (insn16)); + goto done; + case 0x32: /* sltsi45 */ + insn = N32_TYPE2 (SLTSI, REG_TA, N16_RT4 (insn16), N16_IMM5U (insn16)); + goto done; + case 0x33: /* slti45 */ + insn = N32_TYPE2 (SLTI, REG_TA, N16_RT4 (insn16), N16_IMM5U (insn16)); + goto done; + case 0x34: /* beqzs8, bnezs8 */ + if (insn16 & __BIT (8)) + insn = N32_BR2 (BNEZ, REG_TA, N16_IMM8S (insn16)); + else + insn = N32_BR2 (BEQZ, REG_TA, N16_IMM8S (insn16)); + goto done; + + case 0x35: /* break16, ex9.it */ + /* Only consider range of v3 break16. */ + insn = N32_TYPE0 (MISC, (N16_IMM5U (insn16) << 5) | N32_MISC_BREAK); + goto done; + + case 0x3c: /* ifcall9 */ + insn = N32_BR2 (IFCALL, 0, N16_IMM9U (insn16)); + goto done; + case 0x3d: /* movpi45 */ + insn = N32_TYPE1 (MOVI, N16_RT4 (insn16), N16_IMM5U (insn16) + 16); + goto done; + + case 0x3f: /* MISC33 */ + switch (insn16 & 0x7) + { + case 2: /* neg33 */ + insn = N32_TYPE2 (SUBRI, N16_RT3 (insn16), N16_RA3 (insn16), 0); + break; + case 3: /* not33 */ + insn = N32_ALU1 (NOR, N16_RT3 (insn16), N16_RA3 (insn16), + N16_RA3 (insn16)); + break; + case 4: /* mul33 */ + insn = N32_ALU2 (MUL, N16_RT3 (insn16), N16_RT3 (insn16), + N16_RA3 (insn16)); + break; + case 5: /* xor33 */ + insn = N32_ALU1 (XOR, N16_RT3 (insn16), N16_RT3 (insn16), + N16_RA3 (insn16)); + break; + case 6: /* and33 */ + insn = N32_ALU1 (AND, N16_RT3 (insn16), N16_RT3 (insn16), + N16_RA3 (insn16)); + break; + case 7: /* or33 */ + insn = N32_ALU1 (OR, N16_RT3 (insn16), N16_RT3 (insn16), + N16_RA3 (insn16)); + break; + } + goto done; + + case 0xb: + switch (insn16 & 0x7) + { + case 0: /* zeb33 */ + insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RA3 (insn16), 0xff); + break; + case 1: /* zeh33 */ + insn = N32_ALU1 (ZEH, N16_RT3 (insn16), N16_RA3 (insn16), 0); + break; + case 2: /* seb33 */ + insn = N32_ALU1 (SEB, N16_RT3 (insn16), N16_RA3 (insn16), 0); + break; + case 3: /* seh33 */ + insn = N32_ALU1 (SEH, N16_RT3 (insn16), N16_RA3 (insn16), 0); + break; + case 4: /* xlsb33 */ + insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RA3 (insn16), 1); + break; + case 5: /* x11b33 */ + insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RA3 (insn16), 0x7ff); + break; + case 6: /* bmski33 */ + insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RT3 (insn16), + 1 << __GF (insn16, 3, 3)); + break; + case 7: /* fexti33 */ + insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RT3 (insn16), + (1 << (__GF (insn16, 3, 3) + 1)) - 1); + break; + } + goto done; + } + + switch (__GF (insn16, 10, 5)) + { + case 0x0: /* mov55 or ifret16 */ + if (mach >= MACH_V3 && N16_RT5 (insn16) == REG_SP + && N16_RT5 (insn16) == N16_RA5 (insn16)) + insn = N32_JREG (JR, 0, 0, 0, 3); + else + insn = N32_TYPE2 (ADDI, N16_RT5 (insn16), N16_RA5 (insn16), 0); + goto done; + case 0x1: /* movi55 */ + insn = N32_TYPE1 (MOVI, N16_RT5 (insn16), N16_IMM5S (insn16)); + goto done; + case 0x1b: /* addi10s (V2) */ + insn = N32_TYPE2 (ADDI, REG_SP, REG_SP, N16_IMM10S (insn16)); + goto done; + } + + switch (__GF (insn16, 11, 4)) + { + case 0x7: /* lwi37.fp/swi37.fp */ + if (insn16 & __BIT (7)) /* swi37.fp */ + insn = N32_TYPE2 (SWI, N16_RT38 (insn16), REG_FP, N16_IMM7U (insn16)); + else /* lwi37.fp */ + insn = N32_TYPE2 (LWI, N16_RT38 (insn16), REG_FP, N16_IMM7U (insn16)); + goto done; + case 0x8: /* beqz38 */ + insn = N32_BR2 (BEQZ, N16_RT38 (insn16), N16_IMM8S (insn16)); + goto done; + case 0x9: /* bnez38 */ + insn = N32_BR2 (BNEZ, N16_RT38 (insn16), N16_IMM8S (insn16)); + goto done; + case 0xa: /* beqs38/j8, implied r5 */ + if (N16_RT38 (insn16) == 5) + insn = N32_JI (J, N16_IMM8S (insn16)); + else + insn = N32_BR1 (BEQ, N16_RT38 (insn16), REG_R5, N16_IMM8S (insn16)); + goto done; + case 0xb: /* bnes38 and others */ + if (N16_RT38 (insn16) == 5) + { + switch (__GF (insn16, 5, 3)) + { + case 0: /* jr5 */ + insn = N32_JREG (JR, 0, N16_RA5 (insn16), 0, 0); + break; + case 4: /* ret5 */ + insn = N32_JREG (JR, 0, N16_RA5 (insn16), 0, 1); + break; + case 1: /* jral5 */ + insn = N32_JREG (JRAL, REG_LP, N16_RA5 (insn16), 0, 0); + break; + case 2: /* ex9.it imm5 */ + /* ex9.it had no 32-bit variantl. */ + break; + case 5: /* add5.pc */ + /* add5.pc had no 32-bit variantl. */ + break; + } + } + else /* bnes38 */ + insn = N32_BR1 (BNE, N16_RT38 (insn16), REG_R5, N16_IMM8S (insn16)); + goto done; + case 0xe: /* lwi37/swi37 */ + if (insn16 & (1 << 7)) /* swi37.sp */ + insn = N32_TYPE2 (SWI, N16_RT38 (insn16), REG_SP, N16_IMM7U (insn16)); + else /* lwi37.sp */ + insn = N32_TYPE2 (LWI, N16_RT38 (insn16), REG_SP, N16_IMM7U (insn16)); + goto done; + } + +done: + if (insn & 0x80000000) + return 0; + + if (pinsn) + *pinsn = insn; + return 1; +} + +static bfd_boolean +is_sda_access_insn (unsigned long insn) +{ + switch (N32_OP6 (insn)) + { + case N32_OP6_LWI: + case N32_OP6_LHI: + case N32_OP6_LHSI: + case N32_OP6_LBI: + case N32_OP6_LBSI: + case N32_OP6_SWI: + case N32_OP6_SHI: + case N32_OP6_SBI: + case N32_OP6_LWC: + case N32_OP6_LDC: + case N32_OP6_SWC: + case N32_OP6_SDC: + return TRUE; + default: + ; + } + return FALSE; +} + +static unsigned long +turn_insn_to_sda_access (uint32_t insn, bfd_signed_vma type, uint32_t *pinsn) +{ + uint32_t oinsn = 0; + + switch (type) + { + case R_NDS32_GOT_LO12: + case R_NDS32_GOTOFF_LO12: + case R_NDS32_PLTREL_LO12: + case R_NDS32_PLT_GOTREL_LO12: + case R_NDS32_LO12S0_RELA: + switch (N32_OP6 (insn)) + { + case N32_OP6_LBI: + /* lbi.gp */ + oinsn = N32_TYPE1 (LBGP, N32_RT5 (insn), 0); + break; + case N32_OP6_LBSI: + /* lbsi.gp */ + oinsn = N32_TYPE1 (LBGP, N32_RT5 (insn), __BIT (19)); + break; + case N32_OP6_SBI: + /* sbi.gp */ + oinsn = N32_TYPE1 (SBGP, N32_RT5 (insn), 0); + break; + case N32_OP6_ORI: + /* addi.gp */ + oinsn = N32_TYPE1 (SBGP, N32_RT5 (insn), __BIT (19)); + break; + } + break; + + case R_NDS32_LO12S1_RELA: + switch (N32_OP6 (insn)) + { + case N32_OP6_LHI: + /* lhi.gp */ + oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), 0); + break; + case N32_OP6_LHSI: + /* lhsi.gp */ + oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (18)); + break; + case N32_OP6_SHI: + /* shi.gp */ + oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (19)); + break; + } + break; + + case R_NDS32_LO12S2_RELA: + switch (N32_OP6 (insn)) + { + case N32_OP6_LWI: + /* lwi.gp */ + oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3)); + break; + case N32_OP6_SWI: + /* swi.gp */ + oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (7, 17, 3)); + break; + } + break; + + case R_NDS32_LO12S2_DP_RELA: + case R_NDS32_LO12S2_SP_RELA: + oinsn = (insn & 0x7ff07000) | (REG_GP << 15); + break; + } + + if (oinsn) + *pinsn = oinsn; + + return oinsn != 0; +} + +/* Linker hasn't found the correct merge section for non-section symbol + in relax time, this work is left to the function elf_link_input_bfd(). + So for non-section symbol, _bfd_merged_section_offset is also needed + to find the correct symbol address. */ + +static bfd_vma +nds32_elf_rela_local_sym (bfd *abfd, Elf_Internal_Sym *sym, + asection **psec, Elf_Internal_Rela *rel) +{ + asection *sec = *psec; + bfd_vma relocation; + + relocation = (sec->output_section->vma + + sec->output_offset + sym->st_value); + if ((sec->flags & SEC_MERGE) && sec->sec_info_type == SEC_INFO_TYPE_MERGE) + { + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) + rel->r_addend = + _bfd_merged_section_offset (abfd, psec, + elf_section_data (sec)->sec_info, + sym->st_value + rel->r_addend); + else + rel->r_addend = + _bfd_merged_section_offset (abfd, psec, + elf_section_data (sec)->sec_info, + sym->st_value) + rel->r_addend; + + if (sec != *psec) + { + /* If we have changed the section, and our original section is + marked with SEC_EXCLUDE, it means that the original + SEC_MERGE section has been completely subsumed in some + other SEC_MERGE section. In this case, we need to leave + some info around for --emit-relocs. */ + if ((sec->flags & SEC_EXCLUDE) != 0) + sec->kept_section = *psec; + sec = *psec; + } + rel->r_addend -= relocation; + rel->r_addend += sec->output_section->vma + sec->output_offset; + } + return relocation; +} + +static bfd_vma +calculate_memory_address (bfd *abfd, Elf_Internal_Rela *irel, + Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + bfd_signed_vma foff; + bfd_vma symval, addend; + Elf_Internal_Rela irel_fn; + Elf_Internal_Sym *isym; + asection *sym_sec; + + /* Get the value of the symbol referred to by the reloc. */ + if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) + { + /* A local symbol. */ + isym = isymbuf + ELF32_R_SYM (irel->r_info); + + if (isym->st_shndx == SHN_UNDEF) + sym_sec = bfd_und_section_ptr; + else if (isym->st_shndx == SHN_ABS) + sym_sec = bfd_abs_section_ptr; + else if (isym->st_shndx == SHN_COMMON) + sym_sec = bfd_com_section_ptr; + else + sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); + memcpy (&irel_fn, irel, sizeof (Elf_Internal_Rela)); + symval = nds32_elf_rela_local_sym (abfd, isym, &sym_sec, &irel_fn); + addend = irel_fn.r_addend; + } + else + { + unsigned long indx; + struct elf_link_hash_entry *h; + + /* An external symbol. */ + indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + BFD_ASSERT (h != NULL); + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + /* This appears to be a reference to an undefined + symbol. Just ignore it--it will be caught by the + regular reloc processing. */ + return 0; + + if (h->root.u.def.section->flags & SEC_MERGE) + { + sym_sec = h->root.u.def.section; + symval = _bfd_merged_section_offset (abfd, &sym_sec, elf_section_data + (sym_sec)->sec_info, h->root.u.def.value); + symval = symval + sym_sec->output_section->vma + + sym_sec->output_offset; + } + else + symval = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + addend = irel->r_addend; + } + + foff = symval + addend; + + return foff; +} + +static bfd_vma +calculate_got_memory_address (bfd *abfd, struct bfd_link_info *link_info, + Elf_Internal_Rela *irel, + Elf_Internal_Shdr *symtab_hdr) +{ + int symndx; + bfd_vma *local_got_offsets; + /* Get the value of the symbol referred to by the reloc. */ + struct elf_link_hash_entry *h; + struct elf_nds32_link_hash_table *htab = nds32_elf_hash_table (link_info); + + /* An external symbol. */ + symndx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[symndx]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (symndx >= 0) + { + BFD_ASSERT (h != NULL); + return htab->sgot->output_section->vma + htab->sgot->output_offset + + h->got.offset; + } + else + { + local_got_offsets = elf_local_got_offsets (abfd); + BFD_ASSERT (local_got_offsets != NULL); + return htab->sgot->output_section->vma + htab->sgot->output_offset + + local_got_offsets[ELF32_R_SYM (irel->r_info)]; + } + + /* The _GLOBAL_OFFSET_TABLE_ may be undefweak(or should be?). */ + /* The check of h->root.type is passed. */ +} + +static int +is_16bit_NOP (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, Elf_Internal_Rela *rel) +{ + bfd_byte *contents; + unsigned short insn16; + + if (!(rel->r_addend & R_NDS32_INSN16_CONVERT_FLAG)) + return FALSE; + contents = elf_section_data (sec)->this_hdr.contents; + insn16 = bfd_getb16 (contents + rel->r_offset); + if (insn16 == NDS32_NOP16) + return TRUE; + return FALSE; +} + +/* It checks whether the instruction could be converted to + 16-bit form and returns the converted one. + + `internal_relocs' is supposed to be sorted. */ + +static int +is_convert_32_to_16 (bfd *abfd, asection *sec, + Elf_Internal_Rela *reloc, + Elf_Internal_Rela *internal_relocs, + Elf_Internal_Rela *irelend, + uint16_t *insn16) +{ +#define NORMAL_32_TO_16 (1 << 0) +#define SPECIAL_32_TO_16 (1 << 1) + bfd_byte *contents = NULL; + bfd_signed_vma off; + bfd_vma mem_addr; + uint32_t insn = 0; + Elf_Internal_Rela *pc_rel; + int pic_ext_target = 0; + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Sym *isymbuf = NULL; + int convert_type; + bfd_vma offset; + + if (reloc->r_offset + 4 > sec->size) + return FALSE; + + offset = reloc->r_offset; + + if (!nds32_get_section_contents (abfd, sec, &contents, TRUE)) + return FALSE; + insn = bfd_getb32 (contents + offset); + + if (nds32_convert_32_to_16 (abfd, insn, insn16, NULL)) + convert_type = NORMAL_32_TO_16; + else if (special_convert_32_to_16 (insn, insn16, reloc)) + convert_type = SPECIAL_32_TO_16; + else + return FALSE; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + if (!nds32_get_local_syms (abfd, sec, &isymbuf)) + return FALSE; + + /* Find the first relocation of the same relocation-type, + so we iteratie them forward. */ + pc_rel = reloc; + while ((pc_rel - 1) >= internal_relocs && pc_rel[-1].r_offset == offset) + pc_rel--; + + for (; pc_rel < irelend && pc_rel->r_offset == offset; pc_rel++) + { + if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_15_PCREL_RELA + || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17_PCREL_RELA + || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_25_PCREL_RELA + || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_25_PLTREL) + { + off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr, + &pic_ext_target); + if (off >= ACCURATE_8BIT_S1 || off < -ACCURATE_8BIT_S1 + || off == 0) + return FALSE; + break; + } + else if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_20_RELA) + { + /* movi => movi55 */ + mem_addr = calculate_memory_address (abfd, pc_rel, isymbuf, + symtab_hdr); + /* mem_addr is unsigned, but the value should + be between [-16, 15]. */ + if ((mem_addr + 0x10) >> 5) + return FALSE; + break; + } + else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_TLS_LE_20) + || (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_TLS_LE_LO12)) + { + /* It never happen movi to movi55 for R_NDS32_TLS_LE_20, + because it can be relaxed to addi for TLS_LE_ADD. */ + return FALSE; + } + else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA15S2_RELA + || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA17S2_RELA) + && (reloc->r_addend & R_NDS32_INSN16_FP7U2_FLAG) + && convert_type == SPECIAL_32_TO_16) + { + /* fp-as-gp + We've selected a best fp-base for this access, so we can + always resolve it anyway. Do nothing. */ + break; + } + else if ((ELF32_R_TYPE (pc_rel->r_info) > R_NDS32_NONE + && (ELF32_R_TYPE (pc_rel->r_info) < R_NDS32_RELA_GNU_VTINHERIT)) + || ((ELF32_R_TYPE (pc_rel->r_info) > R_NDS32_RELA_GNU_VTENTRY) + && (ELF32_R_TYPE (pc_rel->r_info) < R_NDS32_INSN16)) + || ((ELF32_R_TYPE (pc_rel->r_info) > R_NDS32_LOADSTORE) + && (ELF32_R_TYPE (pc_rel->r_info) < R_NDS32_DWARF2_OP1_RELA))) + { + /* Prevent unresolved addi instruction translate + to addi45 or addi333. */ + return FALSE; + } + else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17IFC_PCREL_RELA)) + { + off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr, + &pic_ext_target); + if (off >= ACCURATE_U9BIT_S1 || off <= 0) + return FALSE; + break; + } + } + + return TRUE; +} + +static void +nds32_elf_write_16 (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *contents, + Elf_Internal_Rela *reloc, + Elf_Internal_Rela *internal_relocs, + Elf_Internal_Rela *irelend, + unsigned short insn16) +{ + Elf_Internal_Rela *pc_rel; + bfd_vma offset; + + offset = reloc->r_offset; + bfd_putb16 (insn16, contents + offset); + /* Find the first relocation of the same relocation-type, + so we iteratie them forward. */ + pc_rel = reloc; + while ((pc_rel - 1) > internal_relocs && pc_rel[-1].r_offset == offset) + pc_rel--; + + for (; pc_rel < irelend && pc_rel->r_offset == offset; pc_rel++) + { + if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_15_PCREL_RELA + || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17_PCREL_RELA + || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_25_PCREL_RELA) + { + pc_rel->r_info = + ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_9_PCREL_RELA); + } + else if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_25_PLTREL) + pc_rel->r_info = + ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_9_PLTREL); + else if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_20_RELA) + pc_rel->r_info = + ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_5_RELA); + else if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA15S2_RELA + || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA17S2_RELA) + pc_rel->r_info = + ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_SDA_FP7U2_RELA); + else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17IFC_PCREL_RELA)) + pc_rel->r_info = + ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_10IFCU_PCREL_RELA); + } +} + +/* Find a relocation of type specified by `reloc_type' + of the same r_offset with reloc. + If not found, return irelend. + + Assuming relocations are sorted by r_offset, + we find the relocation from `reloc' backward untill relocs, + or find it from `reloc' forward untill irelend. */ + +static Elf_Internal_Rela * +find_relocs_at_address (Elf_Internal_Rela *reloc, + Elf_Internal_Rela *relocs, + Elf_Internal_Rela *irelend, + enum elf_nds32_reloc_type reloc_type) +{ + Elf_Internal_Rela *rel_t; + + /* Find backward. */ + for (rel_t = reloc; + rel_t >= relocs && rel_t->r_offset == reloc->r_offset; + rel_t--) + if (ELF32_R_TYPE (rel_t->r_info) == reloc_type) + return rel_t; + + /* We didn't find it backward. Try find it forward. */ + for (rel_t = reloc; + rel_t < irelend && rel_t->r_offset == reloc->r_offset; + rel_t++) + if (ELF32_R_TYPE (rel_t->r_info) == reloc_type) + return rel_t; + + return irelend; +} + +/* Find a relocation of specified type and offset. + `reloc' is just a refence point to find a relocation at specified offset. + If not found, return irelend. + + Assuming relocations are sorted by r_offset, + we find the relocation from `reloc' backward untill relocs, + or find it from `reloc' forward untill irelend. */ + +static Elf_Internal_Rela * +find_relocs_at_address_addr (Elf_Internal_Rela *reloc, + Elf_Internal_Rela *relocs, + Elf_Internal_Rela *irelend, + unsigned char reloc_type, + bfd_vma offset_p) +{ + Elf_Internal_Rela *rel_t = NULL; + + /* First, we try to find a relocation of offset `offset_p', + and then we use find_relocs_at_address to find specific type. */ + + if (reloc->r_offset > offset_p) + { + /* Find backward. */ + for (rel_t = reloc; + rel_t >= relocs && rel_t->r_offset > offset_p; rel_t--) + /* Do nothing. */; + } + else if (reloc->r_offset < offset_p) + { + /* Find forward. */ + for (rel_t = reloc; + rel_t < irelend && rel_t->r_offset < offset_p; rel_t++) + /* Do nothing. */; + } + else + rel_t = reloc; + + /* Not found? */ + if (rel_t < relocs || rel_t == irelend || rel_t->r_offset != offset_p) + return irelend; + + return find_relocs_at_address (rel_t, relocs, irelend, reloc_type); +} + +static bfd_boolean +nds32_elf_check_dup_relocs (Elf_Internal_Rela *reloc, + Elf_Internal_Rela *internal_relocs, + Elf_Internal_Rela *irelend, + unsigned char reloc_type) +{ + Elf_Internal_Rela *rel_t; + + for (rel_t = reloc; + rel_t >= internal_relocs && rel_t->r_offset == reloc->r_offset; + rel_t--) + if (ELF32_R_TYPE (rel_t->r_info) == reloc_type) + { + if (ELF32_R_SYM (rel_t->r_info) == ELF32_R_SYM (reloc->r_info) + && rel_t->r_addend == reloc->r_addend) + continue; + return TRUE; + } + + for (rel_t = reloc; rel_t < irelend && rel_t->r_offset == reloc->r_offset; + rel_t++) + if (ELF32_R_TYPE (rel_t->r_info) == reloc_type) + { + if (ELF32_R_SYM (rel_t->r_info) == ELF32_R_SYM (reloc->r_info) + && rel_t->r_addend == reloc->r_addend) + continue; + return TRUE; + } + + return FALSE; +} + +typedef struct nds32_elf_blank nds32_elf_blank_t; +struct nds32_elf_blank +{ + /* Where the blank begins. */ + bfd_vma offset; + /* The size of the blank. */ + bfd_vma size; + /* The accumulative size before this blank. */ + bfd_vma total_size; + nds32_elf_blank_t *next; + nds32_elf_blank_t *prev; +}; + +static nds32_elf_blank_t *blank_free_list = NULL; + +static nds32_elf_blank_t * +create_nds32_elf_blank (bfd_vma offset_p, bfd_vma size_p) +{ + nds32_elf_blank_t *blank_t; + + if (blank_free_list) + { + blank_t = blank_free_list; + blank_free_list = blank_free_list->next; + } + else + blank_t = bfd_malloc (sizeof (nds32_elf_blank_t)); + + if (blank_t == NULL) + return NULL; + + blank_t->offset = offset_p; + blank_t->size = size_p; + blank_t->total_size = 0; + blank_t->next = NULL; + blank_t->prev = NULL; + + return blank_t; +} + +static void +remove_nds32_elf_blank (nds32_elf_blank_t *blank_p) +{ + if (blank_free_list) + { + blank_free_list->prev = blank_p; + blank_p->next = blank_free_list; + } + else + blank_p->next = NULL; + + blank_p->prev = NULL; + blank_free_list = blank_p; +} + +static void +clean_nds32_elf_blank (void) +{ + nds32_elf_blank_t *blank_t; + + while (blank_free_list) + { + blank_t = blank_free_list; + blank_free_list = blank_free_list->next; + free (blank_t); + } +} + +static nds32_elf_blank_t * +search_nds32_elf_blank (nds32_elf_blank_t *blank_p, bfd_vma addr) +{ + nds32_elf_blank_t *blank_t; + + if (!blank_p) + return NULL; + blank_t = blank_p; + + while (blank_t && addr < blank_t->offset) + blank_t = blank_t->prev; + while (blank_t && blank_t->next && addr >= blank_t->next->offset) + blank_t = blank_t->next; + + return blank_t; +} + +static bfd_vma +get_nds32_elf_blank_total (nds32_elf_blank_t **blank_p, bfd_vma addr, + int overwrite) +{ + nds32_elf_blank_t *blank_t; + + blank_t = search_nds32_elf_blank (*blank_p, addr); + if (!blank_t) + return 0; + + if (overwrite) + *blank_p = blank_t; + + if (addr < blank_t->offset + blank_t->size) + return blank_t->total_size + (addr - blank_t->offset); + else + return blank_t->total_size + blank_t->size; +} + +static bfd_boolean +insert_nds32_elf_blank (nds32_elf_blank_t **blank_p, bfd_vma addr, bfd_vma len) +{ + nds32_elf_blank_t *blank_t, *blank_t2; + + if (!*blank_p) + { + *blank_p = create_nds32_elf_blank (addr, len); + return *blank_p ? TRUE : FALSE; + } + + blank_t = search_nds32_elf_blank (*blank_p, addr); + + if (blank_t == NULL) + { + blank_t = create_nds32_elf_blank (addr, len); + if (!blank_t) + return FALSE; + while ((*blank_p)->prev != NULL) + *blank_p = (*blank_p)->prev; + blank_t->next = *blank_p; + (*blank_p)->prev = blank_t; + (*blank_p) = blank_t; + return TRUE; + } + + if (addr < blank_t->offset + blank_t->size) + { + if (addr > blank_t->offset + blank_t->size) + blank_t->size = addr - blank_t->offset; + } + else + { + blank_t2 = create_nds32_elf_blank (addr, len); + if (!blank_t2) + return FALSE; + if (blank_t->next) + { + blank_t->next->prev = blank_t2; + blank_t2->next = blank_t->next; + } + blank_t2->prev = blank_t; + blank_t->next = blank_t2; + *blank_p = blank_t2; + } + + return TRUE; +} + +static bfd_boolean +insert_nds32_elf_blank_recalc_total (nds32_elf_blank_t **blank_p, bfd_vma addr, + bfd_vma len) +{ + nds32_elf_blank_t *blank_t; + + if (!insert_nds32_elf_blank (blank_p, addr, len)) + return FALSE; + + blank_t = *blank_p; + + if (!blank_t->prev) + { + blank_t->total_size = 0; + blank_t = blank_t->next; + } + + while (blank_t) + { + blank_t->total_size = blank_t->prev->total_size + blank_t->prev->size; + blank_t = blank_t->next; + } + + return TRUE; +} + +static void +calc_nds32_blank_total (nds32_elf_blank_t *blank_p) +{ + nds32_elf_blank_t *blank_t; + bfd_vma total_size = 0; + + if (!blank_p) + return; + + blank_t = blank_p; + while (blank_t->prev) + blank_t = blank_t->prev; + while (blank_t) + { + blank_t->total_size = total_size; + total_size += blank_t->size; + blank_t = blank_t->next; + } +} + +static bfd_boolean +nds32_elf_relax_delete_blanks (bfd *abfd, asection *sec, + nds32_elf_blank_t *blank_p) +{ + Elf_Internal_Shdr *symtab_hdr; /* Symbol table header of this bfd. */ + Elf_Internal_Sym *isym = NULL; /* Symbol table of this bfd. */ + Elf_Internal_Sym *isymend; /* Symbol entry iterator. */ + unsigned int sec_shndx; /* The section the be relaxed. */ + bfd_byte *contents; /* Contents data of iterating section. */ + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irel; + Elf_Internal_Rela *irelend; + struct elf_link_hash_entry **sym_hashes; + struct elf_link_hash_entry **end_hashes; + unsigned int symcount; + asection *sect; + nds32_elf_blank_t *blank_t; + nds32_elf_blank_t *blank_t2; + nds32_elf_blank_t *blank_head; + + blank_head = blank_t = blank_p; + while (blank_head->prev != NULL) + blank_head = blank_head->prev; + while (blank_t->next != NULL) + blank_t = blank_t->next; + + if (blank_t->offset + blank_t->size <= sec->size) + { + blank_t->next = create_nds32_elf_blank (sec->size + 4, 0); + blank_t->next->prev = blank_t; + } + if (blank_head->offset > 0) + { + blank_head->prev = create_nds32_elf_blank (0, 0); + blank_head->prev->next = blank_head; + blank_head = blank_head->prev; + } + + sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); + + /* The deletion must stop at the next ALIGN reloc for an alignment + power larger than the number of bytes we are deleting. */ + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + if (!nds32_get_local_syms (abfd, sec, &isym)) + return FALSE; + + if (isym == NULL) + { + isym = bfd_elf_get_elf_syms (abfd, symtab_hdr, + symtab_hdr->sh_info, 0, NULL, NULL, NULL); + symtab_hdr->contents = (bfd_byte *) isym; + } + + if (isym == NULL || symtab_hdr->sh_info == 0) + return FALSE; + + blank_t = blank_head; + calc_nds32_blank_total (blank_head); + + for (sect = abfd->sections; sect != NULL; sect = sect->next) + { + /* Adjust all the relocs. */ + + /* Relocations MUST be kept in memory, because relaxation adjust them. */ + internal_relocs = _bfd_elf_link_read_relocs (abfd, sect, NULL, NULL, + TRUE /* keep_memory */); + irelend = internal_relocs + sect->reloc_count; + + blank_t = blank_head; + blank_t2 = blank_head; + + if (!(sect->flags & SEC_RELOC)) + continue; + + nds32_get_section_contents (abfd, sect, &contents, TRUE); + + for (irel = internal_relocs; irel < irelend; irel++) + { + bfd_vma raddr; + + if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_DIFF8 + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_DIFF32 + && isym[ELF32_R_SYM (irel->r_info)].st_shndx == sec_shndx) + { + unsigned long val = 0; + unsigned long mask; + long before, between; + long offset; + + switch (ELF32_R_TYPE (irel->r_info)) + { + case R_NDS32_DIFF8: + offset = bfd_get_8 (abfd, contents + irel->r_offset); + break; + case R_NDS32_DIFF16: + offset = bfd_get_16 (abfd, contents + irel->r_offset); + break; + case R_NDS32_DIFF32: + val = bfd_get_32 (abfd, contents + irel->r_offset); + /* Get the signed bit and mask for the high part. The + gcc will alarm when right shift 32-bit since the + type size of long may be 32-bit. */ + mask = 0 - (val >> 31); + if (mask) + offset = (val | (mask - 0xffffffff)); + else + offset = val; + break; + default: + BFD_ASSERT (0); + } + + /* DIFF value + 0 |encoded in location| + |------------|-------------------|--------- + sym+off(addend) + -- before ---| ***************** + --------------------- between ---| + + We only care how much data are relax between DIFF, + marked as ***. */ + + before = get_nds32_elf_blank_total (&blank_t, irel->r_addend, 0); + between = get_nds32_elf_blank_total (&blank_t, + irel->r_addend + offset, 0); + if (between == before) + goto done_adjust_diff; + + switch (ELF32_R_TYPE (irel->r_info)) + { + case R_NDS32_DIFF8: + bfd_put_8 (abfd, offset - (between - before), + contents + irel->r_offset); + break; + case R_NDS32_DIFF16: + bfd_put_16 (abfd, offset - (between - before), + contents + irel->r_offset); + break; + case R_NDS32_DIFF32: + bfd_put_32 (abfd, offset - (between - before), + contents + irel->r_offset); + break; + } + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_DIFF_ULEB128 + && isym[ELF32_R_SYM (irel->r_info)].st_shndx == sec_shndx) + { + bfd_vma val = 0; + unsigned int len = 0; + unsigned long before, between; + bfd_byte *endp, *p; + + val = read_unsigned_leb128 (abfd, contents + irel->r_offset, + &len); + + before = get_nds32_elf_blank_total (&blank_t, irel->r_addend, 0); + between = get_nds32_elf_blank_total (&blank_t, + irel->r_addend + val, 0); + if (between == before) + goto done_adjust_diff; + + p = contents + irel->r_offset; + endp = p + len -1; + memset (p, 0x80, len); + *(endp) = 0; + p = write_uleb128 (p, val - (between - before)) - 1; + if (p < endp) + *p |= 0x80; + } +done_adjust_diff: + + if (sec == sect) + { + raddr = irel->r_offset; + irel->r_offset -= get_nds32_elf_blank_total (&blank_t2, + irel->r_offset, 1); + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE) + continue; + if (blank_t2 && blank_t2->next + && (blank_t2->offset > raddr + || blank_t2->next->offset <= raddr)) + (*_bfd_error_handler) + (_("%B: %s\n"), abfd, + "Error: search_nds32_elf_blank reports wrong node"); + + /* Mark reloc in deleted portion as NONE. + For some relocs like R_NDS32_LABEL that doesn't modify the + content in the section. R_NDS32_LABEL doesn't belong to the + instruction in the section, so we should preserve it. */ + if (raddr >= blank_t2->offset + && raddr < blank_t2->offset + blank_t2->size + && ELF32_R_TYPE (irel->r_info) != R_NDS32_LABEL + && ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_REGION_BEGIN + && ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_REGION_END + && ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY + && ELF32_R_TYPE (irel->r_info) != R_NDS32_SUBTRAHEND + && ELF32_R_TYPE (irel->r_info) != R_NDS32_MINUEND) + { + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_NDS32_NONE); + continue; + } + } + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE + || ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL + || ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY) + continue; + + if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info + && isym[ELF32_R_SYM (irel->r_info)].st_shndx == sec_shndx + && ELF_ST_TYPE (isym[ELF32_R_SYM (irel->r_info)].st_info) == STT_SECTION) + { + if (irel->r_addend <= sec->size) + irel->r_addend -= + get_nds32_elf_blank_total (&blank_t, irel->r_addend, 1); + } + } + } + + /* Adjust the local symbols defined in this section. */ + blank_t = blank_head; + for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) + { + if (isym->st_shndx == sec_shndx) + { + if (isym->st_value <= sec->size) + { + bfd_vma ahead; + bfd_vma orig_addr = isym->st_value; + + ahead = get_nds32_elf_blank_total (&blank_t, isym->st_value, 1); + isym->st_value -= ahead; + + /* Adjust function size. */ + if (ELF32_ST_TYPE (isym->st_info) == STT_FUNC + && isym->st_size > 0) + isym->st_size -= + get_nds32_elf_blank_total + (&blank_t, orig_addr + isym->st_size, 0) - ahead; + } + } + } + + /* Now adjust the global symbols defined in this section. */ + symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) + - symtab_hdr->sh_info); + sym_hashes = elf_sym_hashes (abfd); + end_hashes = sym_hashes + symcount; + blank_t = blank_head; + for (; sym_hashes < end_hashes; sym_hashes++) + { + struct elf_link_hash_entry *sym_hash = *sym_hashes; + + if ((sym_hash->root.type == bfd_link_hash_defined + || sym_hash->root.type == bfd_link_hash_defweak) + && sym_hash->root.u.def.section == sec) + { + if (sym_hash->root.u.def.value <= sec->size) + { + bfd_vma ahead; + bfd_vma orig_addr = sym_hash->root.u.def.value; + + ahead = get_nds32_elf_blank_total (&blank_t, sym_hash->root.u.def.value, 1); + sym_hash->root.u.def.value -= ahead; + + /* Adjust function size. */ + if (sym_hash->type == STT_FUNC) + sym_hash->size -= + get_nds32_elf_blank_total + (&blank_t, orig_addr + sym_hash->size, 0) - ahead; + + } + } + } + + contents = elf_section_data (sec)->this_hdr.contents; + blank_t = blank_head; + while (blank_t->next) + { + /* Actually delete the bytes. */ + + /* If current blank is the last blank overlap with current section, + go to finish process. */ + if (sec->size <= (blank_t->next->offset)) + break; + + memmove (contents + blank_t->offset - blank_t->total_size, + contents + blank_t->offset + blank_t->size, + blank_t->next->offset - (blank_t->offset + blank_t->size)); + + blank_t = blank_t->next; + } + + if (sec->size > (blank_t->offset + blank_t->size)) + { + /* There are remaining code between blank and section boundary. + Move the remaining code to appropriate location. */ + memmove (contents + blank_t->offset - blank_t->total_size, + contents + blank_t->offset + blank_t->size, + sec->size - (blank_t->offset + blank_t->size)); + sec->size -= blank_t->total_size + blank_t->size; + } + else + /* This blank is not entirely included in the section, + reduce the section size by only part of the blank size. */ + sec->size -= blank_t->total_size + (sec->size - blank_t->offset); + + while (blank_head) + { + blank_t = blank_head; + blank_head = blank_head->next; + remove_nds32_elf_blank (blank_t); + } + + return TRUE; +} + +/* Get the contents of a section. */ + +static int +nds32_get_section_contents (bfd *abfd, asection *sec, + bfd_byte **contents_p, bfd_boolean cache) +{ + /* Get the section contents. */ + if (elf_section_data (sec)->this_hdr.contents != NULL) + *contents_p = elf_section_data (sec)->this_hdr.contents; + else + { + if (!bfd_malloc_and_get_section (abfd, sec, contents_p)) + return FALSE; + if (cache) + elf_section_data (sec)->this_hdr.contents = *contents_p; + } + + return TRUE; +} + +/* Get the contents of the internal symbol of abfd. */ + +static int +nds32_get_local_syms (bfd *abfd, asection *sec ATTRIBUTE_UNUSED, + Elf_Internal_Sym **isymbuf_p) +{ + Elf_Internal_Shdr *symtab_hdr; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + /* Read this BFD's local symbols if we haven't done so already. */ + if (*isymbuf_p == NULL && symtab_hdr->sh_info != 0) + { + *isymbuf_p = (Elf_Internal_Sym *) symtab_hdr->contents; + if (*isymbuf_p == NULL) + { + *isymbuf_p = bfd_elf_get_elf_syms (abfd, symtab_hdr, + symtab_hdr->sh_info, 0, + NULL, NULL, NULL); + if (*isymbuf_p == NULL) + return FALSE; + } + } + symtab_hdr->contents = (bfd_byte *) (*isymbuf_p); + + return TRUE; +} + +/* Range of small data. */ +static bfd_vma sdata_range[2][2]; +static bfd_vma const sdata_init_range[2] = +{ ACCURATE_12BIT_S1, ACCURATE_19BIT }; + +static int +nds32_elf_insn_size (bfd *abfd ATTRIBUTE_UNUSED, + bfd_byte *contents, bfd_vma addr) +{ + unsigned long insn = bfd_getb32 (contents + addr); + + if (insn & 0x80000000) + return 2; + + return 4; +} + +/* Set the gp relax range. We have to measure the safe range + to do gp relaxation. */ + +static void +relax_range_measurement (bfd *abfd) +{ + asection *sec_f, *sec_b; + /* For upper bound. */ + bfd_vma maxpgsz = get_elf_backend_data (abfd)->maxpagesize; + bfd_vma align; + static int decide_relax_range = 0; + int i; + int range_number = sizeof (sdata_init_range) / sizeof (sdata_init_range[0]); + + if (decide_relax_range) + return; + decide_relax_range = 1; + + if (sda_rela_sec == NULL) + { + /* Since there is no data sections, we assume the range is page size. */ + for (i = 0; i < range_number; i++) + { + sdata_range[i][0] = sdata_init_range[i] - 0x1000; + sdata_range[i][1] = sdata_init_range[i] - 0x1000; + } + return; + } + + /* Get the biggest alignment power after the gp located section. */ + sec_f = sda_rela_sec->output_section; + sec_b = sec_f->next; + align = 0; + while (sec_b != NULL) + { + if ((unsigned)(1 << sec_b->alignment_power) > align) + align = (1 << sec_b->alignment_power); + sec_b = sec_b->next; + } + + /* I guess we can not determine the section before + gp located section, so we assume the align is max page size. */ + for (i = 0; i < range_number; i++) + { + sdata_range[i][1] = sdata_init_range[i] - align; + BFD_ASSERT (sdata_range[i][1] <= sdata_init_range[i]); + sdata_range[i][0] = sdata_init_range[i] - maxpgsz; + BFD_ASSERT (sdata_range[i][0] <= sdata_init_range[i]); + } +} + +/* These are macros used to check flags encoded in r_addend. + They are only used by nds32_elf_relax_section (). */ +#define GET_SEQ_LEN(addend) ((addend) & 0x000000ff) +#define IS_1ST_CONVERT(addend) ((addend) & 0x80000000) +#define IS_OPTIMIZE(addend) ((addend) & 0x40000000) +#define IS_16BIT_ON(addend) ((addend) & 0x20000000) + +/* Relax LONGCALL1 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longcall1 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 3 variations for LONGCALL1 + case 4-4-2; 16-bit on, optimize off or optimize for space + sethi ta, hi20(symbol) ; LONGCALL1/HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jral5 ta ; + + case 4-4-4; 16-bit off, optimize don't care + sethi ta, hi20(symbol) ; LONGCALL1/HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jral ta ; + + case 4-4-4; 16-bit on, optimize for speed + sethi ta, hi20(symbol) ; LONGCALL1/HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jral ta ; + Check code for -mlong-calls output. */ + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + + bfd_vma laddr; + int seq_len; /* Original length of instruction sequence. */ + uint32_t insn; + Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; + uint16_t insn16; + + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; + + hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_HI20_RELA, laddr); + lo_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_LO12S0_ORI_RELA, + laddr + 4); + + if (hi_irelfn == irelend || lo_irelfn == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL1 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, + &pic_ext_target); + + /* This condition only happened when symbol is undefined. */ + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + || foff >= CONSERVATIVE_24BIT_S1) + return FALSE; + + /* Relax to: jal symbol; 25_PCREL */ + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ + + /* Replace the long call with a jal. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), + R_NDS32_25_PCREL_RELA); + irel->r_addend = hi_irelfn->r_addend; + + /* We don't resolve this here but resolve it in relocate_section. */ + insn = INSN_JAL; + bfd_putb32 (insn, contents + irel->r_offset); + + hi_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); + *insn_len = 4; + + if (seq_len & 0x2) + { + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_INSN16); + lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + *insn_len += 2; + } + return TRUE; +} + +#define CONVERT_CONDITION_CALL(insn) (((insn) & 0xffff0000) ^ 0x90000) +/* Relax LONGCALL2 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longcall2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* bltz rt, .L1 ; LONGCALL2 + jal symbol ; 25_PCREL + .L1: */ + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + + bfd_vma laddr; + uint32_t insn; + Elf_Internal_Rela *i1_irelfn, *cond_irelfn, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + i1_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_25_PCREL_RELA, laddr + 4); + + if (i1_irelfn == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL2 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + insn = bfd_getb32 (contents + laddr); + + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, i1_irelfn, isymbuf, symtab_hdr, + &pic_ext_target); + + if (foff == 0 || foff < -CONSERVATIVE_16BIT_S1 + || foff >= CONSERVATIVE_16BIT_S1) + return FALSE; + + /* Relax to bgezal rt, label ; 17_PCREL + or bltzal rt, label ; 17_PCREL */ + + /* Convert to complimentary conditional call. */ + insn = CONVERT_CONDITION_CALL (insn); + + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ + + /* Clean unnessary relocations. */ + i1_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE); + cond_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_17_PCREL_RELA, laddr); + if (cond_irelfn != irelend) + cond_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info), R_NDS32_NONE); + + /* Replace the long call with a bgezal. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), + R_NDS32_17_PCREL_RELA); + irel->r_addend = i1_irelfn->r_addend; + + bfd_putb32 (insn, contents + irel->r_offset); + + *insn_len = 4; + return TRUE; +} + +/* Relax LONGCALL3 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longcall3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 3 variations for LONGCALL3 + case 4-4-4-2; 16-bit on, optimize off or optimize for space + bltz rt, $1 ; LONGCALL3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jral5 ta ; + $1 + + case 4-4-4-4; 16-bit off, optimize don't care + bltz rt, $1 ; LONGCALL3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jral ta ; + $1 + + case 4-4-4-4; 16-bit on, optimize for speed + bltz rt, $1 ; LONGCALL3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jral ta ; + $1 */ + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + + bfd_vma laddr; + int seq_len; /* Original length of instruction sequence. */ + uint32_t insn; + Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *cond_irelfn, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; + uint16_t insn16; + + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; + + hi_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_HI20_RELA, laddr + 4); + lo_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_LO12S0_ORI_RELA, laddr + 8); + + if (hi_irelfn == irelend || lo_irelfn == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL3 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, + &pic_ext_target); + + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + || foff >= CONSERVATIVE_24BIT_S1) + return FALSE; + + insn = bfd_getb32 (contents + laddr); + if (foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1) + { + /* Relax to bgezal rt, label ; 17_PCREL + or bltzal rt, label ; 17_PCREL */ + + /* Convert to complimentary conditional call. */ + insn = CONVERT_CONDITION_CALL (insn); + bfd_putb32 (insn, contents + irel->r_offset); + + *insn_len = 4; + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); + hi_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); + + cond_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_17_PCREL_RELA, laddr); + if (cond_irelfn != irelend) + { + cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), + R_NDS32_17_PCREL_RELA); + cond_irelfn->r_addend = hi_irelfn->r_addend; + } + + if (seq_len & 0x2) + { + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); + hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), + R_NDS32_INSN16); + hi_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + insn_len += 2; + } + } + else if (foff >= -CONSERVATIVE_24BIT_S1 && foff < CONSERVATIVE_24BIT_S1) + { + /* Relax to the following instruction sequence + bltz rt, $1 ; LONGCALL2 + jal symbol ; 25_PCREL + $1 */ + *insn_len = 8; + insn = INSN_JAL; + bfd_putb32 (insn, contents + hi_irelfn->r_offset); + + hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), + R_NDS32_25_PCREL_RELA); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGCALL2); + + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); + + if (seq_len & 0x2) + { + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_INSN16); + lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + insn_len += 2; + } + } + return TRUE; +} + +/* Relax LONGJUMP1 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longjump1 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 3 variations for LONGJUMP1 + case 4-4-2; 16-bit bit on, optimize off or optimize for space + sethi ta, hi20(symbol) ; LONGJUMP1/HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr5 ta ; + + case 4-4-4; 16-bit off, optimize don't care + sethi ta, hi20(symbol) ; LONGJUMP1/HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr ta ; + + case 4-4-4; 16-bit on, optimize for speed + sethi ta, hi20(symbol) ; LONGJUMP1/HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr ta ; */ + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + + bfd_vma laddr; + int seq_len; /* Original length of instruction sequence. */ + int insn16_on; /* 16-bit on/off. */ + uint32_t insn; + Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; + uint16_t insn16; + unsigned long reloc; + + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; + insn16_on = IS_16BIT_ON (irel->r_addend); + + hi_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_HI20_RELA, laddr); + lo_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_LO12S0_ORI_RELA, laddr + 4); + if (hi_irelfn == irelend || lo_irelfn == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP1 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, + &pic_ext_target); + + if (pic_ext_target || foff == 0 || foff >= CONSERVATIVE_24BIT_S1 + || foff < -CONSERVATIVE_24BIT_S1) + return FALSE; + + if (insn16_on && foff >= -ACCURATE_8BIT_S1 + && foff < ACCURATE_8BIT_S1 && (seq_len & 0x2)) + { + /* j8 label */ + /* 16-bit on, but not optimized for speed. */ + reloc = R_NDS32_9_PCREL_RELA; + insn16 = INSN_J8; + bfd_putb16 (insn16, contents + irel->r_offset); + *insn_len = 2; + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + } + else + { + /* j label */ + reloc = R_NDS32_25_PCREL_RELA; + insn = INSN_J; + bfd_putb32 (insn, contents + irel->r_offset); + *insn_len = 4; + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_INSN16); + irel->r_addend = 0; + } + + hi_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc); + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); + + if ((seq_len & 0x2) && ((*insn_len & 2) == 0)) + { + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), + R_NDS32_INSN16); + lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + *insn_len += 2; + } + return TRUE; +} + +/* Revert condition branch. This function does not check if the input + instruction is condition branch or not. */ + +static void +nds32_elf_convert_branch (uint16_t insn16, uint32_t insn, + uint16_t *re_insn16, uint32_t *re_insn) +{ + uint32_t comp_insn = 0; + uint16_t comp_insn16 = 0; + + if (insn) + { + if (N32_OP6 (insn) == N32_OP6_BR1) + { + /* beqs label. */ + comp_insn = (insn ^ 0x4000) & 0xffffc000; + if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5) + { + /* Insn can be contracted to 16-bit implied r5. */ + comp_insn16 = + (comp_insn & 0x4000) ? INSN_BNES38 : INSN_BEQS38; + comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8; + } + } + else if (N32_OP6 (insn) == N32_OP6_BR3) + { + /* bnec $ta, imm11, label. */ + comp_insn = (insn ^ 0x80000) & 0xffffff00; + } + else + { + comp_insn = (insn ^ 0x10000) & 0xffffc000; + if (N32_BR2_SUB (insn) == N32_BR2_BEQZ + || N32_BR2_SUB (insn) == N32_BR2_BNEZ) + { + if (N32_IS_RT3 (insn)) + { + /* Insn can be contracted to 16-bit. */ + comp_insn16 = + (comp_insn & 0x10000) ? INSN_BNEZ38 : INSN_BEQZ38; + comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8; + } + else if (N32_RT5 (insn) == REG_R15) + { + /* Insn can be contracted to 16-bit. */ + comp_insn16 = + (comp_insn & 0x10000) ? INSN_BNES38 : INSN_BEQS38; + } + } + } + } + else + { + switch ((insn16 & 0xf000) >> 12) + { + case 0xc: + /* beqz38 or bnez38 */ + comp_insn16 = (insn16 ^ 0x0800) & 0xff00; + comp_insn = (comp_insn16 & 0x0800) ? INSN_BNEZ : INSN_BEQZ; + comp_insn |= ((comp_insn16 & 0x0700) >> 8) << 20; + break; + + case 0xd: + /* beqs38 or bnes38 */ + comp_insn16 = (insn16 ^ 0x0800) & 0xff00; + comp_insn = (comp_insn16 & 0x0800) ? INSN_BNE : INSN_BEQ; + comp_insn |= (((comp_insn16 & 0x0700) >> 8) << 20) + | (REG_R5 << 15); + break; + + case 0xe: + /* beqzS8 or bnezS8 */ + comp_insn16 = (insn16 ^ 0x0100) & 0xff00; + comp_insn = (comp_insn16 & 0x0100) ? INSN_BNEZ : INSN_BEQZ; + comp_insn |= REG_R15 << 20; + break; + + default: + break; + } + } + if (comp_insn && re_insn) + *re_insn = comp_insn; + if (comp_insn16 && re_insn16) + *re_insn16 = comp_insn16; +} + +/* Relax LONGJUMP2 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longjump2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 3 variations for LONGJUMP2 + case 2-4; 1st insn convertible, 16-bit on, + optimize off or optimize for space + bnes38 rt, ra, $1 ; LONGJUMP2 + j label ; 25_PCREL + $1: + + case 4-4; 1st insn not convertible + bne rt, ra, $1 ; LONGJUMP2 + j label ; 25_PCREL + $1: + + case 4-4; 1st insn convertible, 16-bit on, optimize for speed + bne rt, ra, $1 ; LONGJUMP2 + j label ; 25_PCREL + $1: */ + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + + bfd_vma laddr; + int seq_len; /* Original length of instruction sequence. */ + Elf_Internal_Rela *i2_irelfn, *cond_irelfn, *irelend; + int pic_ext_target = 0, first_size; + unsigned int i; + bfd_signed_vma foff; + uint32_t insn, re_insn = 0; + uint16_t insn16, re_insn16 = 0; + unsigned long reloc, cond_reloc; + + enum elf_nds32_reloc_type checked_types[] = + { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA }; + + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; + first_size = (seq_len == 6) ? 2 : 4; + + i2_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, + irelend, R_NDS32_25_PCREL_RELA, + laddr + first_size); + + for (i = 0; i < sizeof (checked_types) / sizeof(checked_types[0]); i++) + { + cond_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + checked_types[i], laddr); + if (cond_irelfn != irelend) + break; + } + + if (i2_irelfn == irelend || cond_irelfn == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP2 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + /* Get the value of the symbol referred to by the reloc. */ + foff = + calculate_offset (abfd, sec, i2_irelfn, isymbuf, symtab_hdr, + &pic_ext_target); + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_16BIT_S1 + || foff >= CONSERVATIVE_16BIT_S1) + return FALSE; + + /* Get the all corresponding instructions. */ + if (first_size == 4) + { + insn = bfd_getb32 (contents + laddr); + nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn); + } + else + { + insn16 = bfd_getb16 (contents + laddr); + nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn); + } + + if (re_insn16 && foff >= -(ACCURATE_8BIT_S1 - first_size) + && foff < ACCURATE_8BIT_S1 - first_size) + { + if (first_size == 4) + { + /* Don't convert it to 16-bit now, keep this as relaxable for + ``label reloc; INSN16''. */ + + /* Save comp_insn32 to buffer. */ + bfd_putb32 (re_insn, contents + irel->r_offset); + *insn_len = 4; + reloc = (N32_OP6 (re_insn) == N32_OP6_BR1) ? + R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA; + cond_reloc = R_NDS32_INSN16; + } + else + { + bfd_putb16 (re_insn16, contents + irel->r_offset); + *insn_len = 2; + reloc = R_NDS32_9_PCREL_RELA; + cond_reloc = R_NDS32_NONE; + } + } + else if (N32_OP6 (re_insn) == N32_OP6_BR1 + && (foff >= -(ACCURATE_14BIT_S1 - first_size) + && foff < ACCURATE_14BIT_S1 - first_size)) + { + /* beqs label ; 15_PCREL */ + bfd_putb32 (re_insn, contents + irel->r_offset); + *insn_len = 4; + reloc = R_NDS32_15_PCREL_RELA; + cond_reloc = R_NDS32_NONE; + } + else if (N32_OP6 (re_insn) == N32_OP6_BR2 + && foff >= -CONSERVATIVE_16BIT_S1 + && foff < CONSERVATIVE_16BIT_S1) + { + /* beqz label ; 17_PCREL */ + bfd_putb32 (re_insn, contents + irel->r_offset); + *insn_len = 4; + reloc = R_NDS32_17_PCREL_RELA; + cond_reloc = R_NDS32_NONE; + } + else + return FALSE; + + /* Set all relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), reloc); + irel->r_addend = i2_irelfn->r_addend; + + cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info), + cond_reloc); + cond_irelfn->r_addend = 0; + + if ((seq_len ^ *insn_len ) & 0x2) + { + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + irel->r_offset + 4); + i2_irelfn->r_offset = 4; + i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), + R_NDS32_INSN16); + i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + *insn_len += 2; + } + else + i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), + R_NDS32_NONE); + return TRUE; +} + +/* Relax LONGJUMP3 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longjump3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 5 variations for LONGJUMP3 + case 1: 2-4-4-2; 1st insn convertible, 16-bit on, + optimize off or optimize for space + bnes38 rt, ra, $1 ; LONGJUMP3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr5 ta ; + $1: ; + + case 2: 2-4-4-2; 1st insn convertible, 16-bit on, optimize for speed + bnes38 rt, ra, $1 ; LONGJUMP3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr5 ta ; + $1: ; LABEL + + case 3: 4-4-4-2; 1st insn not convertible, 16-bit on, + optimize off or optimize for space + bne rt, ra, $1 ; LONGJUMP3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr5 ta ; + $1: ; + + case 4: 4-4-4-4; 1st insn don't care, 16-bit off, optimize don't care + 16-bit off if no INSN16 + bne rt, ra, $1 ; LONGJUMP3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr ta ; + $1: ; + + case 5: 4-4-4-4; 1st insn not convertible, 16-bit on, optimize for speed + 16-bit off if no INSN16 + bne rt, ra, $1 ; LONGJUMP3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr ta ; + $1: ; LABEL */ + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + enum elf_nds32_reloc_type checked_types[] = + { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA }; + + int reloc_off = 0, cond_removed = 0, convertible; + bfd_vma laddr; + int seq_len; /* Original length of instruction sequence. */ + Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *cond_irelfn, *irelend; + int pic_ext_target = 0, first_size; + unsigned int i; + bfd_signed_vma foff; + uint32_t insn, re_insn = 0; + uint16_t insn16, re_insn16 = 0; + unsigned long reloc, cond_reloc; + + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; + + convertible = IS_1ST_CONVERT (irel->r_addend); + + if (convertible) + first_size = 2; + else + first_size = 4; + + /* Get all needed relocations. */ + hi_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_HI20_RELA, laddr + first_size); + lo_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_LO12S0_ORI_RELA, + laddr + first_size + 4); + + for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++) + { + cond_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + checked_types[i], laddr); + if (cond_irelfn != irelend) + break; + } + + if (hi_irelfn == irelend || lo_irelfn == irelend || cond_irelfn == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP3 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, + &pic_ext_target); + + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + || foff >= CONSERVATIVE_24BIT_S1) + return FALSE; + + /* Get the all corresponding instructions. */ + if (first_size == 4) + { + insn = bfd_getb32 (contents + laddr); + nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn); + } + else + { + insn16 = bfd_getb16 (contents + laddr); + nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn); + } + + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ + + if (re_insn16 && foff >= -ACCURATE_8BIT_S1 - first_size + && foff < ACCURATE_8BIT_S1 - first_size) + { + if (!(seq_len & 0x2)) + { + /* Don't convert it to 16-bit now, keep this as relaxable + for ``label reloc; INSN1a''6. */ + /* Save comp_insn32 to buffer. */ + bfd_putb32 (re_insn, contents + irel->r_offset); + *insn_len = 4; + reloc = (N32_OP6 (re_insn) == N32_OP6_BR1) ? + R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA; + cond_reloc = R_NDS32_INSN16; + } + else + { + /* Not optimize for speed; convert sequence to 16-bit. */ + /* Save comp_insn16 to buffer. */ + bfd_putb16 (re_insn16, contents + irel->r_offset); + *insn_len = 2; + reloc = R_NDS32_9_PCREL_RELA; + cond_reloc = R_NDS32_NONE; + } + cond_removed = 1; + } + else if (N32_OP6 (re_insn) == N32_OP6_BR1 + && (foff >= -(ACCURATE_14BIT_S1 - first_size) + && foff < ACCURATE_14BIT_S1 - first_size)) + { + /* beqs label ; 15_PCREL */ + bfd_putb32 (re_insn, contents + irel->r_offset); + *insn_len = 4; + reloc = R_NDS32_15_PCREL_RELA; + cond_reloc = R_NDS32_NONE; + cond_removed = 1; + } + else if (N32_OP6 (re_insn) == N32_OP6_BR2 + && foff >= -CONSERVATIVE_16BIT_S1 + && foff < CONSERVATIVE_16BIT_S1) + { + /* beqz label ; 17_PCREL */ + bfd_putb32 (re_insn, contents + irel->r_offset); + *insn_len = 4; + reloc = R_NDS32_17_PCREL_RELA; + cond_reloc = R_NDS32_NONE; + cond_removed = 1; + } + else if (foff >= -CONSERVATIVE_24BIT_S1 - reloc_off + && foff < CONSERVATIVE_24BIT_S1 - reloc_off) + { + /* Relax to one of the following 3 variations + + case 2-4; 1st insn convertible, 16-bit on, optimize off or optimize + for space + bnes38 rt, $1 ; LONGJUMP2 + j label ; 25_PCREL + $1 + + case 4-4; 1st insn not convertible, others don't care + bne rt, ra, $1 ; LONGJUMP2 + j label ; 25_PCREL + $1 + + case 4-4; 1st insn convertible, 16-bit on, optimize for speed + bne rt, ra, $1 ; LONGJUMP2 + j label ; 25_PCREL + $1 */ + + /* Offset for first instruction. */ + + /* Use j label as second instruction. */ + *insn_len = 4 + first_size; + insn = INSN_J; + bfd_putb32 (insn, contents + hi_irelfn->r_offset); + reloc = R_NDS32_LONGJUMP2; + cond_reloc = R_NDS32_25_PLTREL; + } + else + return FALSE; + + if (cond_removed == 1) + { + /* Set all relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc); + irel->r_addend = hi_irelfn->r_addend; + + cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info), + cond_reloc); + cond_irelfn->r_addend = 0; + hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), + R_NDS32_NONE); + } + else + { + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); + irel->r_addend = irel->r_addend; + hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), + cond_reloc); + } + + if ((seq_len ^ *insn_len ) & 0x2) + { + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); + lo_irelfn->r_offset = *insn_len; + lo_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), + R_NDS32_INSN16); + lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + *insn_len += 2; + } + else + lo_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), + R_NDS32_NONE); + return TRUE; +} + +/* Relax LONGCALL4 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longcall4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* The pattern for LONGCALL4. Support for function cse. + sethi ta, hi20(symbol) ; LONGCALL4/HI20 + ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR + jral ta ; PTR_RES/EMPTY/INSN16 */ + + bfd_vma laddr; + uint32_t insn; + Elf_Internal_Rela *hi_irel, *ptr_irel, *insn_irel, *em_irel, *call_irel; + Elf_Internal_Rela *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + hi_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_HI20_RELA, laddr); + + if (hi_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL4 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr, + &pic_ext_target); + + /* This condition only happened when symbol is undefined. */ + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + || foff >= CONSERVATIVE_24BIT_S1) + return FALSE; + + /* Relax to: jal symbol; 25_PCREL */ + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ + + ptr_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED, irel->r_addend); + em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_EMPTY, irel->r_addend); + + if (ptr_irel == irelend || em_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL4 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + /* Check these is enough space to insert jal in R_NDS32_EMPTY. */ + insn = bfd_getb32 (contents + irel->r_addend); + if (insn & 0x80000000) + return FALSE; + + /* Replace the long call with a jal. */ + em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), + R_NDS32_25_PCREL_RELA); + ptr_irel->r_addend = 1; + + /* We don't resolve this here but resolve it in relocate_section. */ + insn = INSN_JAL; + bfd_putb32 (insn, contents + em_irel->r_offset); + + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + + /* If there is function cse, HI20 can not remove now. */ + call_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_LONGCALL4, laddr); + if (call_irel == irelend) + { + *insn_len = 0; + hi_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irel->r_info), R_NDS32_NONE); + } + + insn_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_INSN16, irel->r_addend); + if (insn_irel != irelend) + insn_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + + return TRUE; +} + +/* Relax LONGCALL5 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longcall5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* The pattern for LONGCALL5. + bltz rt, .L1 ; LONGCALL5/17_PCREL + jal symbol ; 25_PCREL + .L1: */ + + bfd_vma laddr; + uint32_t insn; + Elf_Internal_Rela *cond_irel, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_25_PCREL_RELA, irel->r_addend); + if (cond_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL5 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr, + &pic_ext_target); + + if (foff == 0 || foff < -CONSERVATIVE_16BIT_S1 + || foff >= CONSERVATIVE_16BIT_S1) + return FALSE; + + /* Relax to bgezal rt, label ; 17_PCREL + or bltzal rt, label ; 17_PCREL */ + + /* Convert to complimentary conditional call. */ + insn = CONVERT_CONDITION_CALL (insn); + + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ + + /* Modify relocation and contents. */ + cond_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_17_PCREL_RELA); + + /* Replace the long call with a bgezal. */ + bfd_putb32 (insn, contents + cond_irel->r_offset); + *insn_len = 0; + + /* Clean unnessary relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + + cond_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_17_PCREL_RELA, laddr); + cond_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); + + return TRUE; +} + +/* Relax LONGCALL6 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longcall6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* The pattern for LONGCALL6. + bltz rt, .L1 ; LONGCALL6/17_PCREL + sethi ta, hi20(symbol) ; HI20/PTR + ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR + jral ta ; PTR_RES/EMPTY/INSN16 + .L1 */ + + bfd_vma laddr; + uint32_t insn; + Elf_Internal_Rela *em_irel, *cond_irel, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_EMPTY, irel->r_addend); + + if (em_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL6 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr, + &pic_ext_target); + + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + || foff >= CONSERVATIVE_24BIT_S1) + return FALSE; + + /* Check these is enough space to insert jal in R_NDS32_EMPTY. */ + insn = bfd_getb32 (contents + irel->r_addend); + if (insn & 0x80000000) + return FALSE; + + insn = bfd_getb32 (contents + laddr); + if (foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1) + { + /* Relax to bgezal rt, label ; 17_PCREL + or bltzal rt, label ; 17_PCREL */ + + /* Convert to complimentary conditional call. */ + *insn_len = 0; + insn = CONVERT_CONDITION_CALL (insn); + bfd_putb32 (insn, contents + em_irel->r_offset); + + em_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), R_NDS32_17_PCREL_RELA); + + /* Set resolved relocation. */ + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED, irel->r_addend); + if (cond_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL6 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + cond_irel->r_addend = 1; + + /* Clear relocations. */ + + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_17_PCREL_RELA, laddr); + if (cond_irel != irelend) + cond_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); + + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_INSN16, irel->r_addend); + if (cond_irel != irelend) + cond_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); + + } + else if (foff >= -CONSERVATIVE_24BIT_S1 && foff < CONSERVATIVE_24BIT_S1) + { + /* Relax to the following instruction sequence + bltz rt, .L1 ; LONGCALL2/17_PCREL + jal symbol ; 25_PCREL/PTR_RES + .L1 */ + *insn_len = 4; + /* Convert instruction. */ + insn = INSN_JAL; + bfd_putb32 (insn, contents + em_irel->r_offset); + + /* Convert relocations. */ + em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), + R_NDS32_25_PCREL_RELA); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGCALL5); + + /* Set resolved relocation. */ + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED, irel->r_addend); + if (cond_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL6 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + cond_irel->r_addend = 1; + + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_INSN16, irel->r_addend); + if (cond_irel != irelend) + cond_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); + } + return TRUE; +} + +/* Relax LONGJUMP4 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longjump4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* The pattern for LONGJUMP4. + sethi ta, hi20(symbol) ; LONGJUMP4/HI20 + ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR + jr ta ; PTR_RES/INSN16/EMPTY */ + + bfd_vma laddr; + int seq_len; /* Original length of instruction sequence. */ + uint32_t insn; + Elf_Internal_Rela *hi_irel, *ptr_irel, *em_irel, *call_irel, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; + + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + + hi_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_HI20_RELA, laddr); + + if (hi_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP4 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr, + &pic_ext_target); + + if (pic_ext_target || foff == 0 || foff >= CONSERVATIVE_24BIT_S1 + || foff < -CONSERVATIVE_24BIT_S1) + return FALSE; + + /* Convert it to "j label", it may be converted to j8 in the final + pass of relaxation. Therefore, we do not consider this currently. */ + ptr_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED, irel->r_addend); + em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_EMPTY, irel->r_addend); + + if (ptr_irel == irelend || em_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP4 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + em_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), R_NDS32_25_PCREL_RELA); + ptr_irel->r_addend = 1; + + /* Write instruction. */ + insn = INSN_J; + bfd_putb32 (insn, contents + em_irel->r_offset); + + /* Clear relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + + /* If there is function cse, HI20 can not remove now. */ + call_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_LONGJUMP4, laddr); + if (call_irel == irelend) + { + *insn_len = 0; + hi_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irel->r_info), R_NDS32_NONE); + } + + return TRUE; +} + +/* Relax LONGJUMP5 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longjump5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + int *seq_len, bfd_byte *contents, + Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 2 variations for LONGJUMP5 + case 2-4; 1st insn convertible, 16-bit on. + bnes38 rt, ra, .L1 ; LONGJUMP5/9_PCREL/INSN16 + j label ; 25_PCREL/INSN16 + $1: + + case 4-4; 1st insn not convertible + bne rt, ra, .L1 ; LONGJUMP5/15_PCREL/INSN16 + j label ; 25_PCREL/INSN16 + .L1: */ + + bfd_vma laddr; + Elf_Internal_Rela *cond_irel, *irelend; + int pic_ext_target = 0; + unsigned int i; + bfd_signed_vma foff; + uint32_t insn, re_insn = 0; + uint16_t insn16, re_insn16 = 0; + unsigned long reloc; + + enum elf_nds32_reloc_type checked_types[] = + { R_NDS32_17_PCREL_RELA, R_NDS32_15_PCREL_RELA, + R_NDS32_9_PCREL_RELA, R_NDS32_INSN16 }; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_25_PCREL_RELA, irel->r_addend); + if (cond_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP5 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr, + &pic_ext_target); + + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_16BIT_S1 + || foff >= CONSERVATIVE_16BIT_S1) + return FALSE; + + /* Get the all corresponding instructions. */ + insn = bfd_getb32 (contents + laddr); + /* Check instruction size. */ + if (insn & 0x80000000) + { + *seq_len = 0; + insn16 = insn >> 16; + nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn); + } + else + nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn); + + if (N32_OP6 (re_insn) == N32_OP6_BR1 + && (foff >= -CONSERVATIVE_14BIT_S1 && foff < CONSERVATIVE_14BIT_S1)) + { + /* beqs label ; 15_PCREL. */ + bfd_putb32 (re_insn, contents + cond_irel->r_offset); + reloc = R_NDS32_15_PCREL_RELA; + } + else if (N32_OP6 (re_insn) == N32_OP6_BR2 + && foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1) + { + /* beqz label ; 17_PCREL. */ + bfd_putb32 (re_insn, contents + cond_irel->r_offset); + reloc = R_NDS32_17_PCREL_RELA; + } + else if ( N32_OP6 (re_insn) == N32_OP6_BR3 + && foff >= -CONSERVATIVE_8BIT_S1 && foff < CONSERVATIVE_8BIT_S1) + { + /* beqc label ; 9_PCREL. */ + bfd_putb32 (re_insn, contents + cond_irel->r_offset); + reloc = R_NDS32_WORD_9_PCREL_RELA; + } + else + return FALSE; + + /* Set all relocations. */ + cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), reloc); + + /* Clean relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++) + { + cond_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + checked_types[i], laddr); + if (cond_irel != irelend) + { + if (*seq_len == 0 + && (ELF32_R_TYPE (cond_irel->r_info) == R_NDS32_INSN16)) + { + /* If the branch instruction is 2 byte, it cannot remove + directly. Only convert it to nop16 and remove it after + checking alignment issue. */ + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + laddr); + cond_irel->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + } + else + cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), + R_NDS32_NONE); + } + } + *insn_len = 0; + + return TRUE; +} + +/* Relax LONGJUMP6 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longjump6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + int *seq_len, bfd_byte *contents, + Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 5 variations for LONGJUMP6 + case : 2-4-4-4; 1st insn convertible, 16-bit on. + bnes38 rt, ra, .L1 ; LONGJUMP6/15_PCREL/INSN16 + sethi ta, hi20(symbol) ; HI20/PTR + ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR + jr ta ; PTR_RES/INSN16/EMPTY + .L1: + + case : 4-4-4-4; 1st insn not convertible, 16-bit on. + bne rt, ra, .L1 ; LONGJUMP6/15_PCREL/INSN16 + sethi ta, hi20(symbol) ; HI20/PTR + ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR + jr ta ; PTR_RES/INSN16/EMPTY + .L1: */ + + enum elf_nds32_reloc_type checked_types[] = + { R_NDS32_17_PCREL_RELA, R_NDS32_15_PCREL_RELA, + R_NDS32_9_PCREL_RELA, R_NDS32_INSN16 }; + + int reloc_off = 0, cond_removed = 0; + bfd_vma laddr; + Elf_Internal_Rela *cond_irel, *em_irel, *irelend, *insn_irel; + int pic_ext_target = 0; + unsigned int i; + bfd_signed_vma foff; + uint32_t insn, re_insn = 0; + uint16_t insn16, re_insn16 = 0; + unsigned long reloc; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_EMPTY, irel->r_addend); + + if (em_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP6 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr, + &pic_ext_target); + + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + || foff >= CONSERVATIVE_24BIT_S1) + return FALSE; + + insn = bfd_getb32 (contents + laddr); + /* Check instruction size. */ + if (insn & 0x80000000) + { + *seq_len = 0; + insn16 = insn >> 16; + nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn); + } + else + nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn); + + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ + + if (N32_OP6 (re_insn) == N32_OP6_BR1 + && (foff >= -CONSERVATIVE_14BIT_S1 && foff < CONSERVATIVE_14BIT_S1)) + { + /* beqs label ; 15_PCREL */ + bfd_putb32 (re_insn, contents + em_irel->r_offset); + reloc = R_NDS32_15_PCREL_RELA; + cond_removed = 1; + } + else if (N32_OP6 (re_insn) == N32_OP6_BR2 + && foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1) + { + /* beqz label ; 17_PCREL */ + bfd_putb32 (re_insn, contents + em_irel->r_offset); + reloc = R_NDS32_17_PCREL_RELA; + cond_removed = 1; + } + else if (foff >= -CONSERVATIVE_24BIT_S1 - reloc_off + && foff < CONSERVATIVE_24BIT_S1 - reloc_off) + { + /* Relax to one of the following 2 variations + + case 2-4; 1st insn convertible, 16-bit on. + bnes38 rt, ra, .L1 ; LONGJUMP5/9_PCREL/INSN16 + j label ; 25_PCREL/INSN16 + $1: + + case 4-4; 1st insn not convertible + bne rt, ra, .L1 ; LONGJUMP5/15_PCREL/INSN16 + j label ; 25_PCREL/INSN16 + .L1: */ + + /* Use j label as second instruction. */ + insn = INSN_J; + reloc = R_NDS32_25_PCREL_RELA; + bfd_putb32 (insn, contents + em_irel->r_offset); + } + else + return FALSE; + + /* Set all relocations. */ + em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), reloc); + + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED, em_irel->r_offset); + cond_irel->r_addend = 1; + + /* Use INSN16 of first branch instruction to distinguish if keeping + INSN16 of final instruction or not. */ + insn_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_INSN16, irel->r_offset); + if (insn_irel == irelend) + { + /* Clean the final INSN16. */ + insn_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_INSN16, em_irel->r_offset); + insn_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), + R_NDS32_NONE); + } + + if (cond_removed == 1) + { + *insn_len = 0; + + /* Clear relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + + for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++) + { + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + checked_types[i], laddr); + if (cond_irel != irelend) + { + if (*seq_len == 0 + && (ELF32_R_TYPE (cond_irel->r_info) == R_NDS32_INSN16)) + { + /* If the branch instruction is 2 byte, it cannot remove + directly. Only convert it to nop16 and remove it after + checking alignment issue. */ + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + laddr); + cond_irel->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + } + else + cond_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); + } + } + } + else + { + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_NDS32_LONGJUMP5); + } + + return TRUE; +} + +/* Relax LONGJUMP7 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longjump7 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + int *seq_len, bfd_byte *contents, + Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 2 variations for LONGJUMP5 + case 2-4; 1st insn convertible, 16-bit on. + movi55 ta, imm11 ; LONGJUMP7/INSN16 + beq rt, ta, label ; 15_PCREL + + case 4-4; 1st insn not convertible + movi55 ta, imm11 ; LONGJUMP7/INSN16 + beq rt, ta, label ; 15_PCREL */ + + bfd_vma laddr; + Elf_Internal_Rela *cond_irel, *irelend, *insn_irel; + int pic_ext_target = 0; + bfd_signed_vma foff; + uint32_t insn, re_insn = 0; + uint16_t insn16; + uint32_t imm11; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_15_PCREL_RELA, irel->r_addend); + if (cond_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP7 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr, + &pic_ext_target); + + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_8BIT_S1 + || foff >= CONSERVATIVE_8BIT_S1) + return FALSE; + + /* Get the first instruction for its size. */ + insn = bfd_getb32 (contents + laddr); + if (insn & 0x80000000) + { + *seq_len = 0; + /* Get the immediate from movi55. */ + imm11 = N16_IMM5S (insn >> 16); + } + else + { + /* Get the immediate from movi. */ + imm11 = N32_IMM20S (insn); + } + + /* Get the branch instruction. */ + insn = bfd_getb32 (contents + irel->r_addend); + /* Convert instruction to BR3. */ + if ((insn >> 14) & 0x1) + re_insn = N32_BR3 (BNEC, N32_RT5 (insn), imm11, 0); + else + re_insn = N32_BR3 (BEQC, N32_RT5 (insn), imm11, 0); + + bfd_putb32 (re_insn, contents + cond_irel->r_offset); + + /* Set all relocations. */ + cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), + R_NDS32_WORD_9_PCREL_RELA); + + /* Clean relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + insn_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_INSN16, irel->r_offset); + if (insn_irel != irelend) + { + if (*seq_len == 0) + { + /* If the first insntruction is 16bit, convert it to nop16. */ + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + laddr); + insn_irel->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + } + else + cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), + R_NDS32_NONE); + } + *insn_len = 0; + + return TRUE; +} + +#define GET_LOADSTORE_RANGE(addend) (((addend) >> 8) & 0x3f) + +/* Relax LOADSTORE relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_loadstore (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr, int load_store_relax) +{ + int eliminate_sethi = 0, range_type, i; + bfd_vma local_sda, laddr; + int seq_len; /* Original length of instruction sequence. */ + uint32_t insn; + Elf_Internal_Rela *hi_irelfn = NULL, *irelend; + bfd_vma access_addr = 0; + bfd_vma range_l = 0, range_h = 0; /* Upper/lower bound. */ + enum elf_nds32_reloc_type checked_types[] = + { R_NDS32_HI20_RELA, R_NDS32_GOT_HI20, + R_NDS32_GOTPC_HI20, R_NDS32_GOTOFF_HI20, + R_NDS32_PLTREL_HI20, R_NDS32_PLT_GOTREL_HI20, + R_NDS32_TLS_LE_HI20 + }; + + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; + + /* Get the high part relocation. */ + for (i = 0; (unsigned) i < sizeof (checked_types); i++) + { + hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, + checked_types[i], laddr); + if (hi_irelfn != irelend) + break; + } + + if (hi_irelfn == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LOADSTORE points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + + range_type = GET_LOADSTORE_RANGE (irel->r_addend); + nds32_elf_final_sda_base (sec->output_section->owner, + link_info, &local_sda, FALSE); + + switch (ELF32_R_TYPE (hi_irelfn->r_info)) + { + case R_NDS32_HI20_RELA: + insn = bfd_getb32 (contents + laddr); + access_addr = + calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr); + + if (range_type == NDS32_LOADSTORE_IMM) + { + struct elf_link_hash_entry *h = NULL; + int indx; + + if (ELF32_R_SYM (hi_irelfn->r_info) >= symtab_hdr->sh_info) + { + indx = ELF32_R_SYM (hi_irelfn->r_info) - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + } + + if ((access_addr < CONSERVATIVE_20BIT) + && (!h || (h && strcmp (h->root.root.string, FP_BASE_NAME) != 0))) + { + eliminate_sethi = 1; + break; + } + + /* This is avoid to relax symbol address which is fixed + relocations. Ex: _stack. */ + if (h && bfd_is_abs_section (h->root.u.def.section)) + return FALSE; + } + + if (!load_store_relax) + return FALSE; + + /* Case for set gp register. */ + if (N32_RT5 (insn) == REG_GP) + break; + + if (range_type == NDS32_LOADSTORE_FLOAT_S + || range_type == NDS32_LOADSTORE_FLOAT_S) + { + range_l = sdata_range[0][0]; + range_h = sdata_range[0][1]; + } + else + { + range_l = sdata_range[1][0]; + range_h = sdata_range[1][1]; + } + break; + + case R_NDS32_GOT_HI20: + access_addr = + calculate_got_memory_address (abfd, link_info, hi_irelfn, symtab_hdr); + + /* If this symbol is not in .got, the return value will be -1. + Since the gp value is set to SDA_BASE but not GLOBAL_OFFSET_TABLE, + a negative offset is allowed. */ + if ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT + && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT) + eliminate_sethi = 1; + break; + + case R_NDS32_PLT_GOTREL_HI20: + access_addr = calculate_plt_memory_address (abfd, link_info, isymbuf, + hi_irelfn, symtab_hdr); + + if ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT + && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT) + eliminate_sethi = 1; + break; + + case R_NDS32_GOTOFF_HI20: + access_addr = + calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr); + + if ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT + && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT) + eliminate_sethi = 1; + break; + + case R_NDS32_GOTPC_HI20: + /* The access_addr must consider r_addend of hi_irel. */ + access_addr = sec->output_section->vma + sec->output_offset + + irel->r_offset + hi_irelfn->r_addend; + + if ((bfd_signed_vma) (local_sda - access_addr) < CONSERVATIVE_20BIT + && (bfd_signed_vma) (local_sda - access_addr) >= -CONSERVATIVE_20BIT) + eliminate_sethi = 1; + break; + + case R_NDS32_TLS_LE_HI20: + access_addr = + calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr); + BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL); + access_addr -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET); + if ((range_type == NDS32_LOADSTORE_IMM) + && (bfd_signed_vma) (access_addr) < CONSERVATIVE_20BIT + && (bfd_signed_vma) (access_addr) >= -CONSERVATIVE_20BIT) + eliminate_sethi = 1; + break; + + default: + return FALSE; + } + + /* Delete sethi instruction. */ + if (eliminate_sethi == 1 + || (local_sda <= access_addr && (access_addr - local_sda) < range_h) + || (local_sda > access_addr && (local_sda - access_addr) <= range_l)) + { + hi_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + *insn_len = 0; + } + return TRUE; +} + +/* Relax LO12 relocation for nds32_elf_relax_section. */ + +static void +nds32_elf_relax_lo12 (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, bfd_byte *contents, + Elf_Internal_Sym *isymbuf, Elf_Internal_Shdr *symtab_hdr) +{ + uint32_t insn; + bfd_vma local_sda, laddr; + unsigned long reloc; + bfd_vma access_addr; + bfd_vma range_l = 0, range_h = 0; /* Upper/lower bound. */ + Elf_Internal_Rela *irelfn = NULL, *irelend; + struct elf_link_hash_entry *h = NULL; + int indx; + + /* For SDA base relative relaxation. */ + nds32_elf_final_sda_base (sec->output_section->owner, link_info, + &local_sda, FALSE); + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + + if (!is_sda_access_insn (insn) && N32_OP6 (insn) != N32_OP6_ORI) + return; + + access_addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); + + if (ELF32_R_SYM (irel->r_info) >= symtab_hdr->sh_info) + { + indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + } + + if (N32_OP6 (insn) == N32_OP6_ORI && access_addr < CONSERVATIVE_20BIT + && (!h || (h && strcmp (h->root.root.string, FP_BASE_NAME) != 0))) + { + reloc = R_NDS32_20_RELA; + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); + insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0); + bfd_putb32 (insn, contents + laddr); + } + /* This is avoid to relax symbol address which is fixed + relocations. Ex: _stack. */ + else if (N32_OP6 (insn) == N32_OP6_ORI + && h && bfd_is_abs_section (h->root.u.def.section)) + return; + else + { + range_l = sdata_range[1][0]; + range_h = sdata_range[1][1]; + switch (ELF32_R_TYPE (irel->r_info)) + { + case R_NDS32_LO12S0_RELA: + reloc = R_NDS32_SDA19S0_RELA; + break; + case R_NDS32_LO12S1_RELA: + reloc = R_NDS32_SDA18S1_RELA; + break; + case R_NDS32_LO12S2_RELA: + reloc = R_NDS32_SDA17S2_RELA; + break; + case R_NDS32_LO12S2_DP_RELA: + range_l = sdata_range[0][0]; + range_h = sdata_range[0][1]; + reloc = R_NDS32_SDA12S2_DP_RELA; + break; + case R_NDS32_LO12S2_SP_RELA: + range_l = sdata_range[0][0]; + range_h = sdata_range[0][1]; + reloc = R_NDS32_SDA12S2_SP_RELA; + break; + default: + return; + } + + /* There are range_h and range_l because linker has to promise + all sections move cross one page together. */ + if ((local_sda <= access_addr && (access_addr - local_sda) < range_h) + || (local_sda > access_addr && (local_sda - access_addr) <= range_l)) + { + if (N32_OP6 (insn) == N32_OP6_ORI && N32_RT5 (insn) == REG_GP) + { + /* Maybe we should add R_NDS32_INSN16 reloc type here + or manually do some optimization. sethi can't be + eliminated when updating $gp so the relative ori + needs to be preserved. */ + return; + } + if (!turn_insn_to_sda_access (insn, ELF32_R_TYPE (irel->r_info), + &insn)) + return; + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); + bfd_putb32 (insn, contents + laddr); + + irelfn = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_INSN16); + /* SDA17 must keep INSN16 for converting fp_as_gp. */ + if (irelfn != irelend && reloc != R_NDS32_SDA17S2_RELA) + irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (irelfn->r_info), R_NDS32_NONE); + + } + } + return; +} + +/* Relax low part of PIC instruction pattern. */ + +static void +nds32_elf_relax_piclo12 (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + uint32_t insn; + bfd_vma local_sda, laddr; + bfd_signed_vma foff; + unsigned long reloc; + + nds32_elf_final_sda_base (sec->output_section->owner, link_info, + &local_sda, FALSE); + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + + if (N32_OP6 (insn) != N32_OP6_ORI) + return; + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12) + { + foff = calculate_got_memory_address (abfd, link_info, irel, + symtab_hdr) - local_sda; + reloc = R_NDS32_GOT20; + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12) + { + foff = calculate_plt_memory_address (abfd, link_info, isymbuf, irel, + symtab_hdr) - local_sda; + reloc = R_NDS32_PLT_GOTREL_LO20; + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12) + { + foff = calculate_memory_address (abfd, irel, isymbuf, + symtab_hdr) - local_sda; + reloc = R_NDS32_GOTOFF; + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTPC_LO12) + { + foff = local_sda - sec->output_section->vma + sec->output_offset + + irel->r_offset + irel->r_addend; + reloc = R_NDS32_GOTPC20; + } + else + return; + + if ((foff < CONSERVATIVE_20BIT) && (foff >= -CONSERVATIVE_20BIT)) + { + /* Turn into MOVI. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); + insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0); + bfd_putb32 (insn, contents + laddr); + } +} + +/* Relax low part of LE TLS instruction pattern. */ + +static void +nds32_elf_relax_letlslo12 (struct bfd_link_info *link_info, bfd *abfd, + Elf_Internal_Rela *irel, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + uint32_t insn; + bfd_vma laddr; + bfd_signed_vma foff; + unsigned long reloc; + + laddr = irel->r_offset; + foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); + BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL); + foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET); + insn = bfd_getb32 (contents + laddr); + + if ( (bfd_signed_vma) (foff) < CONSERVATIVE_20BIT + && (bfd_signed_vma) (foff) >= -CONSERVATIVE_20BIT) + { + /* Pattern sethi-ori transform to movi. */ + reloc = R_NDS32_TLS_LE_20; + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); + insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0); + bfd_putb32 (insn, contents + laddr); + } +} + +/* Relax LE TLS calculate address instruction pattern. */ + +static void +nds32_elf_relax_letlsadd (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again) +{ + /* Local TLS non-pic + sethi ta, hi20(symbol@tpoff) ; TLS_LE_HI20 + ori ta, ta, lo12(symbol@tpoff) ; TLS_LE_LO12 + add ra, ta, tp ; TLS_LE_ADD */ + + uint32_t insn; + bfd_vma laddr; + bfd_signed_vma foff; + Elf_Internal_Rela *i1_irelfn, *irelend; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED); + foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); + BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL); + foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET); + + /* The range is +/-16k. */ + if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT + && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT) + { + /* Transform add to addi. */ + insn = N32_TYPE2 (ADDI, N32_RT5 (insn), N32_RB5 (insn), 0); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S0); + + bfd_putb32 (insn, contents + laddr); + if (i1_irelfn != irelend) + { + i1_irelfn->r_addend |= 1; + *again = TRUE; + } + } +} + +/* Relax LE TLS load store instruction pattern. */ + +static void +nds32_elf_relax_letlsls (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again) +{ + + uint32_t insn; + bfd_vma laddr; + bfd_signed_vma foff; + Elf_Internal_Rela *i1_irelfn, *irelend; + int success = 0; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED); + foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); + BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL); + foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET); + + switch ((N32_OP6 (insn) << 8) | (insn & 0xff)) + { + case (N32_OP6_MEM << 8) | N32_MEM_LB: + case (N32_OP6_MEM << 8) | N32_MEM_SB: + case (N32_OP6_MEM << 8) | N32_MEM_LBS: + /* The range is +/-16k. */ + if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT + && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT) + { + insn = + ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S0); + success = 1; + break; + } + case (N32_OP6_MEM << 8) | N32_MEM_LH: + case (N32_OP6_MEM << 8) | N32_MEM_SH: + case (N32_OP6_MEM << 8) | N32_MEM_LHS: + /* The range is +/-32k. */ + if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT_S1 + && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT_S1) + { + insn = + ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S1); + success = 1; + break; + } + case (N32_OP6_MEM << 8) | N32_MEM_LW: + case (N32_OP6_MEM << 8) | N32_MEM_SW: + /* The range is +/-64k. */ + if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT_S2 + && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT_S2) + { + insn = + ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S2); + success = 1; + break; + } + default: + break; + } + + if (success) + { + bfd_putb32 (insn, contents + laddr); + if (i1_irelfn != irelend) + { + i1_irelfn->r_addend |= 1; + *again = TRUE; + } + } +} + +/* Relax PTR relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_ptr (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + int *seq_len, bfd_byte *contents) +{ + Elf_Internal_Rela *ptr_irel, *irelend, *count_irel, *re_irel; + + irelend = internal_relocs + sec->reloc_count; + + re_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED, irel->r_addend); + + if (re_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_PTR points to unrecognized reloc at 0x%lx.", + abfd, (long) irel->r_offset); + return FALSE; + } + + if (re_irel->r_addend != 1) + return FALSE; + + /* Pointed target is relaxed and no longer needs this void *, + change the type to NONE. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + + /* Find PTR_COUNT to decide remove it or not. If PTR_COUNT does + not exist, it means only count 1 and remove it directly. */ + /* TODO: I hope we can obsolate R_NDS32_COUNT in the future. */ + count_irel = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR_COUNT); + ptr_irel = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR); + if (count_irel != irelend) + { + if (--count_irel->r_addend > 0) + return FALSE; + } + + if (ptr_irel != irelend) + return FALSE; + + /* If the PTR_COUNT is already 0, remove current instruction. */ + *seq_len = nds32_elf_insn_size (abfd, contents, irel->r_offset); + *insn_len = 0; + return TRUE; +} + +/* Relax PLT_GOT_SUFF relocation for nds32_elf_relax_section. */ + +static void +nds32_elf_relax_pltgot_suff (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again) +{ + uint32_t insn; + bfd_signed_vma foff; + Elf_Internal_Rela *i1_irelfn, *irelend; + bfd_vma local_sda, laddr; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + + /* FIXME: It's a little trouble to turn JRAL5 to JAL since + we need additional space. It might be help if we could + borrow some space from instructions to be eliminated + such as sethi, ori, add. */ + if (insn & 0x80000000) + return; + + if (nds32_elf_check_dup_relocs + (irel, internal_relocs, irelend, R_NDS32_PLT_GOT_SUFF)) + return; + + i1_irelfn = + find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED); + + /* FIXIT 090606 + The boundary should be reduced since the .plt section hasn't + been created and the address of specific entry is still unknown + Maybe the range between the function call and the begin of the + .text section can be used to decide if the .plt is in the range + of function call. */ + + if (N32_OP6 (insn) == N32_OP6_ALU1 + && N32_SUB5 (insn) == N32_ALU1_ADD) + { + /* Get the value of the symbol referred to by the reloc. */ + nds32_elf_final_sda_base (sec->output_section->owner, link_info, + &local_sda, FALSE); + foff = (bfd_signed_vma) (calculate_plt_memory_address + (abfd, link_info, isymbuf, irel, + symtab_hdr) - local_sda); + /* This condition only happened when symbol is undefined. */ + if (foff == 0) + return; + + if (foff < -CONSERVATIVE_19BIT || foff >= CONSERVATIVE_19BIT) + return; + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_NDS32_PLT_GOTREL_LO19); + /* addi.gp */ + insn = N32_TYPE1 (SBGP, N32_RT5 (insn), __BIT (19)); + } + else if (N32_OP6 (insn) == N32_OP6_JREG + && N32_SUB5 (insn) == N32_JREG_JRAL) + { + /* Get the value of the symbol referred to by the reloc. */ + foff = + calculate_plt_offset (abfd, sec, link_info, isymbuf, irel, symtab_hdr); + /* This condition only happened when symbol is undefined. */ + if (foff == 0) + return; + if (foff < -CONSERVATIVE_24BIT_S1 || foff >= CONSERVATIVE_24BIT_S1) + return; + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_25_PLTREL); + insn = INSN_JAL; + } + else + return; + + bfd_putb32 (insn, contents + laddr); + if (i1_irelfn != irelend) + { + i1_irelfn->r_addend |= 1; + *again = TRUE; + } +} + +/* Relax GOT_SUFF relocation for nds32_elf_relax_section. */ + +static void +nds32_elf_relax_got_suff (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, + bfd_byte *contents, Elf_Internal_Shdr *symtab_hdr, + bfd_boolean *again) +{ + uint32_t insn; + bfd_signed_vma foff; + Elf_Internal_Rela *i1_irelfn, *irelend; + bfd_vma local_sda, laddr; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + if (insn & 0x80000000) + return; + + if (nds32_elf_check_dup_relocs + (irel, internal_relocs, irelend, R_NDS32_GOT_SUFF)) + return; + + i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED); + + nds32_elf_final_sda_base (sec->output_section->owner, link_info, + &local_sda, FALSE); + foff = calculate_got_memory_address (abfd, link_info, irel, + symtab_hdr) - local_sda; + + if (foff < CONSERVATIVE_19BIT && foff >= -CONSERVATIVE_19BIT) + { + /* Turn LW to LWI.GP. Change relocation type to R_NDS32_GOT_REL. */ + insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_GOT17S2_RELA); + bfd_putb32 (insn, contents + laddr); + if (i1_irelfn != irelend) + { + i1_irelfn->r_addend |= 1; + *again = TRUE; + } + } +} + +/* Relax PLT_GOT_SUFF relocation for nds32_elf_relax_section. */ + +static void +nds32_elf_relax_gotoff_suff (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again) +{ + int opc_insn_gotoff; + uint32_t insn; + bfd_signed_vma foff; + Elf_Internal_Rela *i1_irelfn, *i2_irelfn, *irelend; + bfd_vma local_sda, laddr; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + + if (insn & 0x80000000) + return; + + if (nds32_elf_check_dup_relocs + (irel, internal_relocs, irelend, R_NDS32_GOTOFF_SUFF)) + return; + + i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED); + nds32_elf_final_sda_base (sec->output_section->owner, link_info, + &local_sda, FALSE); + foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); + foff = foff - local_sda; + + if (foff >= CONSERVATIVE_19BIT || foff < -CONSERVATIVE_19BIT) + return; + + /* Concatenate opcode and sub-opcode for switch case. + It may be MEM or ALU1. */ + opc_insn_gotoff = (N32_OP6 (insn) << 8) | (insn & 0xff); + switch (opc_insn_gotoff) + { + case (N32_OP6_MEM << 8) | N32_MEM_LW: + /* 4-byte aligned. */ + insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA17S2_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_SW: + insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (7, 17, 3)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA17S2_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_LH: + /* 2-byte aligned. */ + insn = N32_TYPE1 (HWGP, N32_RT5 (insn), 0); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_LHS: + insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (18)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_SH: + insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (19)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_LB: + /* 1-byte aligned. */ + insn = N32_TYPE1 (LBGP, N32_RT5 (insn), 0); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_LBS: + insn = N32_TYPE1 (LBGP, N32_RT5 (insn), __BIT (19)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_SB: + insn = N32_TYPE1 (SBGP, N32_RT5 (insn), 0); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); + break; + case (N32_OP6_ALU1 << 8) | N32_ALU1_ADD: + insn = N32_TYPE1 (SBGP, N32_RT5 (insn), __BIT (19)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); + break; + default: + return; + } + + bfd_putb32 (insn, contents + laddr); + if (i1_irelfn != irelend) + { + i1_irelfn->r_addend |= 1; + *again = TRUE; + } + if ((i2_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_INSN16)) != irelend) + i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + +} + +static bfd_boolean +nds32_relax_adjust_label (bfd *abfd, asection *sec, + Elf_Internal_Rela *internal_relocs, + bfd_byte *contents, + nds32_elf_blank_t **relax_blank_list, + int optimize, int opt_size) +{ + /* This code block is used to adjust 4-byte alignment by relax a pair + of instruction a time. + + It recognizes three types of relocations. + 1. R_NDS32_LABEL - a aligment. + 2. R_NDS32_INSN16 - relax a 32-bit instruction to 16-bit. + 3. is_16bit_NOP () - remove a 16-bit instruction. */ + + /* TODO: It seems currently implementation only support 4-byte aligment. + We should handle any-aligment. */ + + Elf_Internal_Rela *insn_rel = NULL, *label_rel = NULL, *irel; + Elf_Internal_Rela *tmp_rel, *tmp2_rel = NULL; + Elf_Internal_Rela rel_temp; + Elf_Internal_Rela *irelend; + bfd_vma address; + uint16_t insn16; + + /* Checking for branch relaxation relies on the relocations to + be sorted on 'r_offset'. This is not guaranteed so we must sort. */ + nds32_insertion_sort (internal_relocs, sec->reloc_count, + sizeof (Elf_Internal_Rela), compar_reloc); + + irelend = internal_relocs + sec->reloc_count; + + /* Force R_NDS32_LABEL before R_NDS32_INSN16. */ + /* FIXME: Can we generate the right order in assembler? + So we don't have to swapping them here. */ + + for (label_rel = internal_relocs, insn_rel = internal_relocs; + label_rel < irelend; label_rel++) + { + if (ELF32_R_TYPE (label_rel->r_info) != R_NDS32_LABEL) + continue; + + /* Find the first reloc has the same offset with label_rel. */ + while (insn_rel < irelend && insn_rel->r_offset < label_rel->r_offset) + insn_rel++; + + for (;insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset; + insn_rel++) + /* Check if there were R_NDS32_INSN16 and R_NDS32_LABEL at the same + address. */ + if (ELF32_R_TYPE (insn_rel->r_info) == R_NDS32_INSN16) + break; + + if (insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset + && insn_rel < label_rel) + { + /* Swap the two reloc if the R_NDS32_INSN16 is + before R_NDS32_LABEL. */ + memcpy (&rel_temp, insn_rel, sizeof (Elf_Internal_Rela)); + memcpy (insn_rel, label_rel, sizeof (Elf_Internal_Rela)); + memcpy (label_rel, &rel_temp, sizeof (Elf_Internal_Rela)); + } + } + + label_rel = NULL; + insn_rel = NULL; + /* If there were a sequence of R_NDS32_LABEL end up with .align 2 + or higher, remove other R_NDS32_LABEL with lower alignment. + If an R_NDS32_INSN16 in between R_NDS32_LABELs must be converted, + then the R_NDS32_LABEL sequence is broke. */ + for (tmp_rel = internal_relocs; tmp_rel < irelend; tmp_rel++) + { + if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_LABEL) + { + if (label_rel == NULL) + { + if (tmp_rel->r_addend < 2) + label_rel = tmp_rel; + continue; + } + else if (tmp_rel->r_addend > 1) + { + /* Remove all LABEL relocation from label_rel to tmp_rel + including relocations with same offset as tmp_rel. */ + for (tmp2_rel = label_rel; tmp2_rel < tmp_rel + || tmp2_rel->r_offset == tmp_rel->r_offset; tmp2_rel++) + { + if (ELF32_R_TYPE (tmp2_rel->r_info) == R_NDS32_LABEL + && tmp2_rel->r_addend < 2) + tmp2_rel->r_info = + ELF32_R_INFO (ELF32_R_SYM (tmp2_rel->r_info), + R_NDS32_NONE); + } + label_rel = NULL; + } + } + else if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16 && label_rel) + { + /* A new INSN16 which can be converted, so clear label_rel. */ + if (is_convert_32_to_16 (abfd, sec, tmp_rel, internal_relocs, + irelend, &insn16) + || is_16bit_NOP (abfd, sec, tmp_rel)) + label_rel = NULL; + } + } + + label_rel = NULL; + insn_rel = NULL; + /* Optimized for speed and nothing has not been relaxed. + It's time to align labels. + We may convert a 16-bit instruction right before a label to + 32-bit, in order to align the label if necessary + all reloc entries has been sorted by r_offset. */ + for (irel = internal_relocs; irel < irelend; irel++) + { + if (ELF32_R_TYPE (irel->r_info) != R_NDS32_INSN16 + && ELF32_R_TYPE (irel->r_info) != R_NDS32_LABEL) + continue; + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_INSN16) + { + /* A new INSN16 found, resize the old one. */ + if (is_convert_32_to_16 + (abfd, sec, irel, internal_relocs, irelend, &insn16) + || is_16bit_NOP (abfd, sec, irel)) + { + if (insn_rel) + { + /* Previous INSN16 reloc exists, reduce its + size to 16-bit. */ + if (is_convert_32_to_16 (abfd, sec, insn_rel, internal_relocs, + irelend, &insn16)) + { + nds32_elf_write_16 (abfd, contents, insn_rel, + internal_relocs, irelend, insn16); + + if (!insert_nds32_elf_blank_recalc_total + (relax_blank_list, insn_rel->r_offset + 2, 2)) + return FALSE; + } + else if (is_16bit_NOP (abfd, sec, insn_rel)) + { + if (!insert_nds32_elf_blank_recalc_total + (relax_blank_list, insn_rel->r_offset, 2)) + return FALSE; + } + insn_rel->r_info = + ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), R_NDS32_NONE); + } + /* Save the new one for later use. */ + insn_rel = irel; + } + else + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_NDS32_NONE); + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL) + { + /* Search for label. */ + int force_relax = 0; + + /* Label on 16-bit instruction or optimization + needless, just reset this reloc. */ + insn16 = bfd_getb16 (contents + irel->r_offset); + if ((irel->r_addend & 0x1f) < 2 && (!optimize || (insn16 & 0x8000))) + { + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + continue; + } + + address = + irel->r_offset - get_nds32_elf_blank_total (relax_blank_list, + irel->r_offset, 1); + + if (!insn_rel) + { + /* Check if there is case which can not be aligned. */ + if (irel->r_addend == 2 && address & 0x2) + return FALSE; + continue; + } + + /* Try to align this label. */ + + if ((irel->r_addend & 0x1f) < 2) + { + /* Check if there is a INSN16 at the same address. + Label_rel always seats before insn_rel after + our sort. */ + + /* Search for INSN16 at LABEL location. If INSN16 is at + same location and this LABEL alignment is lower than 2, + the INSN16 can be converted to 2-byte. */ + for (tmp_rel = irel; + tmp_rel < irelend && tmp_rel->r_offset == irel->r_offset; + tmp_rel++) + { + if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16 + && (is_convert_32_to_16 + (abfd, sec, tmp_rel, internal_relocs, + irelend, &insn16) + || is_16bit_NOP (abfd, sec, tmp_rel))) + { + force_relax = 1; + break; + } + } + } + + if (force_relax || irel->r_addend == 1 || address & 0x2) + { + /* Label not aligned. */ + /* Previous reloc exists, reduce its size to 16-bit. */ + if (is_convert_32_to_16 (abfd, sec, insn_rel, + internal_relocs, irelend, &insn16)) + { + nds32_elf_write_16 (abfd, contents, insn_rel, + internal_relocs, irelend, insn16); + + if (!insert_nds32_elf_blank_recalc_total + (relax_blank_list, insn_rel->r_offset + 2, 2)) + return FALSE; + } + else if (is_16bit_NOP (abfd, sec, insn_rel)) + { + if (!insert_nds32_elf_blank_recalc_total + (relax_blank_list, insn_rel->r_offset, 2)) + return FALSE; + } + + } + /* INSN16 reloc is used. */ + insn_rel = NULL; + } + } + + address = + sec->size - get_nds32_elf_blank_total (relax_blank_list, sec->size, 0); + if (insn_rel && (address & 0x2 || opt_size)) + { + if (is_convert_32_to_16 (abfd, sec, insn_rel, internal_relocs, + irelend, &insn16)) + { + nds32_elf_write_16 (abfd, contents, insn_rel, internal_relocs, + irelend, insn16); + if (!insert_nds32_elf_blank_recalc_total + (relax_blank_list, insn_rel->r_offset + 2, 2)) + return FALSE; + insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), + R_NDS32_NONE); + } + else if (is_16bit_NOP (abfd, sec, insn_rel)) + { + if (!insert_nds32_elf_blank_recalc_total + (relax_blank_list, insn_rel->r_offset, 2)) + return FALSE; + insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), + R_NDS32_NONE); + } + } + insn_rel = NULL; + return TRUE; +} + +/* Pick relaxation round. */ + +static int +nds32_elf_pick_relax (bfd_boolean init, asection *sec, bfd_boolean *again, + struct elf_nds32_link_hash_table *table, + struct bfd_link_info *link_info) +{ + static asection *final_sec, *first_sec = NULL; + static bfd_boolean normal_again = FALSE; + static bfd_boolean set = FALSE; + static bfd_boolean first = TRUE; + int round_table[] = { + NDS32_RELAX_NORMAL_ROUND, + NDS32_RELAX_JUMP_IFC_ROUND, + NDS32_RELAX_EX9_BUILD_ROUND, + NDS32_RELAX_EX9_REPLACE_ROUND, + }; + static int pass = 0; + static int relax_round; + + /* The new round. */ + if (init && first_sec == sec) + { + set = TRUE; + normal_again = FALSE; + } + + if (first) + { + /* Run an empty run to get the final section. */ + relax_round = NDS32_RELAX_EMPTY_ROUND; + + /* It has to enter relax again because we can + not make sure what the final turn is. */ + *again = TRUE; + + first = FALSE; + first_sec = sec; + } + + if (!set) + { + /* Not reenter yet. */ + final_sec = sec; + return relax_round; + } + + relax_round = round_table[pass]; + + if (!init && relax_round == NDS32_RELAX_NORMAL_ROUND && *again) + normal_again = TRUE; + + if (!init && final_sec == sec) + { + switch (relax_round) + { + case NDS32_RELAX_NORMAL_ROUND: + if (!normal_again) + { + /* Normal relaxation done. */ + if (table->target_optimize & NDS32_RELAX_JUMP_IFC_ON) + { + pass++; + *again = TRUE; + } + else if (table->target_optimize & NDS32_RELAX_EX9_ON) + { + pass += 2; /* NDS32_RELAX_EX9_BUILD_ROUND */ + *again = TRUE; + } + else if (table->ex9_import_file) + { + /* Import ex9 table. */ + if (table->update_ex9_table) + pass += 2; /* NDS32_RELAX_EX9_BUILD_ROUND */ + else + pass += 3; /* NDS32_RELAX_EX9_REPLACE_ROUND */ + nds32_elf_ex9_import_table (link_info); + *again = TRUE; + } + } + break; + case NDS32_RELAX_JUMP_IFC_ROUND: + if (!nds32_elf_ifc_finish (link_info)) + (*_bfd_error_handler) (_("error: Jump IFC Fail.")); + if (table->target_optimize & NDS32_RELAX_EX9_ON) + { + pass++; + *again = TRUE; + } + break; + case NDS32_RELAX_EX9_BUILD_ROUND: + nds32_elf_ex9_finish (link_info); + pass++; + *again = TRUE; + break; + case NDS32_RELAX_EX9_REPLACE_ROUND: + if (table->target_optimize & NDS32_RELAX_JUMP_IFC_ON) + { + /* Do jump IFC optimization again. */ + if (!nds32_elf_ifc_finish (link_info)) + (*_bfd_error_handler) (_("error: Jump IFC Fail.")); + } + break; + default: + break; + } + } + + return relax_round; +} + +static bfd_boolean +nds32_elf_relax_section (bfd *abfd, asection *sec, + struct bfd_link_info *link_info, bfd_boolean *again) +{ + nds32_elf_blank_t *relax_blank_list = NULL; + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irel; + Elf_Internal_Rela *irelend; + Elf_Internal_Sym *isymbuf = NULL; + bfd_byte *contents = NULL; + bfd_boolean result = TRUE; + int optimize = 0; + int opt_size = 0; + uint32_t insn; + uint16_t insn16; + + /* Target dependnet option. */ + struct elf_nds32_link_hash_table *table; + int load_store_relax; + int relax_round; + + relax_blank_list = NULL; + + *again = FALSE; + + /* Nothing to do for + * relocatable link or + * non-relocatable section or + * non-code section or + * empty content or + * no reloc entry. */ + if (link_info->relocatable + || (sec->flags & SEC_RELOC) == 0 + || (sec->flags & SEC_EXCLUDE) == 1 + || (sec->flags & SEC_CODE) == 0 + || sec->size == 0) + return TRUE; + + /* 09.12.11 Workaround. */ + /* We have to adjust align for R_NDS32_LABEL if needed. + The adjust approach only can fix 2-byte align once. */ + if (sec->alignment_power > 2) + return TRUE; + + /* The optimization type to do. */ + + table = nds32_elf_hash_table (link_info); + relax_round = nds32_elf_pick_relax (TRUE, sec, again, table, link_info); + switch (relax_round) + { + case NDS32_RELAX_JUMP_IFC_ROUND: + /* Here is the entrance of ifc jump relaxation. */ + if (!nds32_elf_ifc_calc (link_info, abfd, sec)) + return FALSE; + nds32_elf_pick_relax (FALSE, sec, again, table, link_info); + return TRUE; + + case NDS32_RELAX_EX9_BUILD_ROUND: + /* Here is the entrance of ex9 relaxation. There are two pass of + ex9 relaxation. The one is to traverse all instructions and build + the hash table. The other one is to compare instructions and replace + it by ex9.it. */ + if (!nds32_elf_ex9_build_hash_table (abfd, sec, link_info)) + return FALSE; + nds32_elf_pick_relax (FALSE, sec, again, table, link_info); + return TRUE; + + case NDS32_RELAX_EX9_REPLACE_ROUND: + if (!nds32_elf_ex9_replace_instruction (link_info, abfd, sec)) + return FALSE; + return TRUE; + + case NDS32_RELAX_EMPTY_ROUND: + nds32_elf_pick_relax (FALSE, sec, again, table, link_info); + return TRUE; + + case NDS32_RELAX_NORMAL_ROUND: + default: + if (sec->reloc_count == 0) + return TRUE; + break; + } + + /* The begining of general relaxation. */ + + if (is_SDA_BASE_set == 0) + { + bfd_vma gp; + is_SDA_BASE_set = 1; + nds32_elf_final_sda_base (sec->output_section->owner, link_info, + &gp, FALSE); + relax_range_measurement (abfd); + } + + if (is_ITB_BASE_set == 0) + { + /* Set the _ITB_BASE_. */ + if (!nds32_elf_ex9_itb_base (link_info)) + { + (*_bfd_error_handler) (_("%B: error: Cannot set _ITB_BASE_"), abfd); + bfd_set_error (bfd_error_bad_value); + } + } + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + /* Relocations MUST be kept in memory, because relaxation adjust them. */ + internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, + TRUE /* keep_memory */); + if (internal_relocs == NULL) + goto error_return; + + irelend = internal_relocs + sec->reloc_count; + irel = find_relocs_at_address (internal_relocs, internal_relocs, + irelend, R_NDS32_RELAX_ENTRY); + + if (irel == irelend) + return TRUE; + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY) + { + if (irel->r_addend & R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG) + { + nds32_elf_pick_relax (FALSE, sec, again, table, link_info); + return TRUE; + } + + if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG) + optimize = 1; + + if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FOR_SPACE_FLAG) + opt_size = 1; + } + + load_store_relax = table->load_store_relax; + + /* Get symbol table and section content. */ + if (!nds32_get_section_contents (abfd, sec, &contents, TRUE) + || !nds32_get_local_syms (abfd, sec, &isymbuf)) + goto error_return; + + /* Do relax loop only when finalize is not done. + Take care of relaxable relocs except INSN16. */ + for (irel = internal_relocs; irel < irelend; irel++) + { + int seq_len; /* Original length of instruction sequence. */ + int insn_len = 0; /* Final length of instruction sequence. */ + bfd_boolean removed; + + insn = 0; + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL + && (irel->r_addend & 0x1f) >= 2) + optimize = 1; + + /* Relocation Types + R_NDS32_LONGCALL1 53 + R_NDS32_LONGCALL2 54 + R_NDS32_LONGCALL3 55 + R_NDS32_LONGJUMP1 56 + R_NDS32_LONGJUMP2 57 + R_NDS32_LONGJUMP3 58 + R_NDS32_LOADSTORE 59 */ + if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL1 + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LOADSTORE) + seq_len = GET_SEQ_LEN (irel->r_addend); + + /* Relocation Types + R_NDS32_LONGCALL4 107 + R_NDS32_LONGCALL5 108 + R_NDS32_LONGCALL6 109 + R_NDS32_LONGJUMP4 110 + R_NDS32_LONGJUMP5 111 + R_NDS32_LONGJUMP6 112 + R_NDS32_LONGJUMP7 113 */ + else if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL4 + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LONGJUMP7) + seq_len = 4; + + /* Relocation Types + R_NDS32_LO12S0_RELA 30 + R_NDS32_LO12S1_RELA 29 + R_NDS32_LO12S2_RELA 28 + R_NDS32_LO12S2_SP_RELA 71 + R_NDS32_LO12S2_DP_RELA 70 + R_NDS32_GOT_LO12 46 + R_NDS32_GOTOFF_LO12 50 + R_NDS32_PLTREL_LO12 65 + R_NDS32_PLT_GOTREL_LO12 67 + R_NDS32_17IFC_PCREL_RELA 96 + R_NDS32_GOT_SUFF 193 + R_NDS32_GOTOFF_SUFF 194 + R_NDS32_PLT_GOT_SUFF 195 + R_NDS32_MULCALL_SUFF 196 + R_NDS32_PTR 197 */ + else if ((ELF32_R_TYPE (irel->r_info) <= R_NDS32_LO12S0_RELA + && ELF32_R_TYPE (irel->r_info) >= R_NDS32_LO12S2_RELA) + || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_SP_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_DP_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12 + || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12 + || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTPC_LO12 + || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTREL_LO12 + || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12 + || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_GOT_SUFF + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_PTR) + || ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_LO12 + || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_ADD + || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_LS) + seq_len = 0; + else + continue; + + insn_len = seq_len; + removed = FALSE; + + switch (ELF32_R_TYPE (irel->r_info)) + { + case R_NDS32_LONGCALL1: + removed = nds32_elf_relax_longcall1 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGCALL2: + removed = nds32_elf_relax_longcall2 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGCALL3: + removed = nds32_elf_relax_longcall3 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGJUMP1: + removed = nds32_elf_relax_longjump1 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGJUMP2: + removed = nds32_elf_relax_longjump2 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGJUMP3: + removed = nds32_elf_relax_longjump3 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGCALL4: + removed = nds32_elf_relax_longcall4 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGCALL5: + removed = nds32_elf_relax_longcall5 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGCALL6: + removed = nds32_elf_relax_longcall6 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGJUMP4: + removed = nds32_elf_relax_longjump4 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGJUMP5: + removed = nds32_elf_relax_longjump5 (abfd, sec, irel, internal_relocs, + &insn_len, &seq_len, contents, + isymbuf, symtab_hdr); + break; + case R_NDS32_LONGJUMP6: + removed = nds32_elf_relax_longjump6 (abfd, sec, irel, internal_relocs, + &insn_len, &seq_len, contents, + isymbuf, symtab_hdr); + break; + case R_NDS32_LONGJUMP7: + removed = nds32_elf_relax_longjump7 (abfd, sec, irel, internal_relocs, + &insn_len, &seq_len, contents, + isymbuf, symtab_hdr); + break; + case R_NDS32_LOADSTORE: + removed = nds32_elf_relax_loadstore (link_info, abfd, sec, irel, + internal_relocs, &insn_len, + contents, isymbuf, symtab_hdr, + load_store_relax); + break; + case R_NDS32_LO12S0_RELA: + case R_NDS32_LO12S1_RELA: + case R_NDS32_LO12S2_DP_RELA: + case R_NDS32_LO12S2_SP_RELA: + case R_NDS32_LO12S2_RELA: + /* Relax for low part. */ + nds32_elf_relax_lo12 (link_info, abfd, sec, irel, internal_relocs, + contents, isymbuf, symtab_hdr); + + /* It is impossible to delete blank, so just continue. */ + continue; + case R_NDS32_GOT_LO12: + case R_NDS32_GOTOFF_LO12: + case R_NDS32_PLTREL_LO12: + case R_NDS32_PLT_GOTREL_LO12: + case R_NDS32_GOTPC_LO12: + /* Relax for PIC gp-relative low part. */ + nds32_elf_relax_piclo12 (link_info, abfd, sec, irel, contents, + isymbuf, symtab_hdr); + + /* It is impossible to delete blank, so just continue. */ + continue; + case R_NDS32_TLS_LE_LO12: + /* Relax for LE TLS low part. */ + nds32_elf_relax_letlslo12 (link_info, abfd, irel, contents, + isymbuf, symtab_hdr); + + /* It is impossible to delete blank, so just continue. */ + continue; + case R_NDS32_TLS_LE_ADD: + nds32_elf_relax_letlsadd (link_info, abfd, sec, irel, internal_relocs, + contents, isymbuf, symtab_hdr, again); + /* It is impossible to delete blank, so just continue. */ + continue; + case R_NDS32_TLS_LE_LS: + nds32_elf_relax_letlsls (link_info, abfd, sec, irel, internal_relocs, + contents, isymbuf, symtab_hdr, again); + continue; + case R_NDS32_PTR: + removed = nds32_elf_relax_ptr (abfd, sec, irel, internal_relocs, + &insn_len, &seq_len, contents); + break; + case R_NDS32_PLT_GOT_SUFF: + nds32_elf_relax_pltgot_suff (link_info, abfd, sec, irel, + internal_relocs, contents, + isymbuf, symtab_hdr, again); + /* It is impossible to delete blank, so just continue. */ + continue; + case R_NDS32_GOT_SUFF: + nds32_elf_relax_got_suff (link_info, abfd, sec, irel, + internal_relocs, contents, + symtab_hdr, again); + /* It is impossible to delete blank, so just continue. */ + continue; + case R_NDS32_GOTOFF_SUFF: + nds32_elf_relax_gotoff_suff (link_info, abfd, sec, irel, + internal_relocs, contents, + isymbuf, symtab_hdr, again); + /* It is impossible to delete blank, so just continue. */ + continue; + default: + continue; + + } + if (removed && seq_len - insn_len > 0) + { + if (!insert_nds32_elf_blank + (&relax_blank_list, irel->r_offset + insn_len, + seq_len - insn_len)) + goto error_return; + *again = TRUE; + } + } + + calc_nds32_blank_total (relax_blank_list); + + if (table->relax_fp_as_gp) + { + if (!nds32_relax_fp_as_gp (link_info, abfd, sec, internal_relocs, + irelend, isymbuf)) + goto error_return; + + if (*again == FALSE) + { + if (!nds32_fag_remove_unused_fpbase (abfd, sec, internal_relocs, + irelend)) + goto error_return; + } + } + + nds32_elf_pick_relax (FALSE, sec, again, table, link_info); + + if (*again == FALSE) + { + if (!nds32_relax_adjust_label (abfd, sec, internal_relocs, contents, + &relax_blank_list, optimize, opt_size)) + goto error_return; + } + + /* It doesn't matter optimize_for_space_no_align anymore. + If object file is assembled with flag '-Os', + the we don't adjust jump-destination on 4-byte boundary. */ + + if (relax_blank_list) + { + nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list); + relax_blank_list = NULL; + } + + if (*again == FALSE) + { + /* Closing the section, so we don't relax it anymore. */ + bfd_vma sec_size_align; + Elf_Internal_Rela *tmp_rel; + + /* Pad to alignment boundary. Only handle current section alignment. */ + sec_size_align = (sec->size + (~((-1) << sec->alignment_power))) + & ((-1) << sec->alignment_power); + if ((sec_size_align - sec->size) & 0x2) + { + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + sec->size); + sec->size += 2; + } + + while (sec_size_align != sec->size) + { + insn = NDS32_NOP32; + bfd_putb32 (insn, contents + sec->size); + sec->size += 4; + } + + tmp_rel = find_relocs_at_address (internal_relocs, internal_relocs, + irelend, R_NDS32_RELAX_ENTRY); + if (tmp_rel != irelend) + tmp_rel->r_addend |= R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG; + + clean_nds32_elf_blank (); + } + +finish: + if (internal_relocs != NULL + && elf_section_data (sec)->relocs != internal_relocs) + free (internal_relocs); + + if (contents != NULL + && elf_section_data (sec)->this_hdr.contents != contents) + free (contents); + + if (isymbuf != NULL && symtab_hdr->contents != (bfd_byte *) isymbuf) + free (isymbuf); + + return result; + +error_return: + result = FALSE; + goto finish; +} + +static struct bfd_elf_special_section const nds32_elf_special_sections[] = +{ + {".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE}, + {".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE}, + {NULL, 0, 0, 0, 0} +}; + +static bfd_boolean +nds32_elf_output_arch_syms (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info, + void *finfo ATTRIBUTE_UNUSED, + bfd_boolean (*func) (void *, const char *, + Elf_Internal_Sym *, + asection *, + struct elf_link_hash_entry *) + ATTRIBUTE_UNUSED) +{ + FILE *sym_ld_script = NULL; + struct elf_nds32_link_hash_table *table; + + table = nds32_elf_hash_table (info); + sym_ld_script = table->sym_ld_script; + + if (check_start_export_sym) + fprintf (sym_ld_script, "}\n"); + + return TRUE; +} + +static enum elf_reloc_type_class +nds32_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, + const asection *rel_sec ATTRIBUTE_UNUSED, + const Elf_Internal_Rela *rela) +{ + switch ((int) ELF32_R_TYPE (rela->r_info)) + { + case R_NDS32_RELATIVE: + return reloc_class_relative; + case R_NDS32_JMP_SLOT: + return reloc_class_plt; + case R_NDS32_COPY: + return reloc_class_copy; + default: + return reloc_class_normal; + } +} + +/* Put target dependent option into info hash table. */ +void +bfd_elf32_nds32_set_target_option (struct bfd_link_info *link_info, + int relax_fp_as_gp, + int eliminate_gc_relocs, + FILE * sym_ld_script, int load_store_relax, + int target_optimize, int relax_status, + int relax_round, FILE * ex9_export_file, + FILE * ex9_import_file, + int update_ex9_table, int ex9_limit, + bfd_boolean ex9_loop_aware, + bfd_boolean ifc_loop_aware) +{ + struct elf_nds32_link_hash_table *table; + + table = nds32_elf_hash_table (link_info); + if (table == NULL) + return; + + table->relax_fp_as_gp = relax_fp_as_gp; + table->eliminate_gc_relocs = eliminate_gc_relocs; + table->sym_ld_script = sym_ld_script; + table ->load_store_relax = load_store_relax; + table->target_optimize = target_optimize; + table->relax_status = relax_status; + table->relax_round = relax_round; + table->ex9_export_file = ex9_export_file; + table->ex9_import_file = ex9_import_file; + table->update_ex9_table = update_ex9_table; + table->ex9_limit = ex9_limit; + table->ex9_loop_aware = ex9_loop_aware; + table->ifc_loop_aware = ifc_loop_aware; +} + +/* These functions and data-structures are used for fp-as-gp + optimization. */ + +#define FAG_THRESHOLD 3 /* At least 3 gp-access. */ +/* lwi37.fp covers 508 bytes, but there may be 32-byte padding between + the read-only section and read-write section. */ +#define FAG_WINDOW (508 - 32) + +/* An nds32_fag represent a gp-relative access. + We find best fp-base by using a sliding window + to find a base address which can cover most gp-access. */ +struct nds32_fag +{ + struct nds32_fag *next; /* NULL-teminated linked list. */ + bfd_vma addr; /* The address of this fag. */ + Elf_Internal_Rela **relas; /* The relocations associated with this fag. + It is used for applying FP7U2_FLAG. */ + int count; /* How many times this address is referred. + There should be exactly `count' relocations + in relas. */ + int relas_capcity; /* The buffer size of relas. + We use an array instead of linked-list, + and realloc is used to adjust buffer size. */ +}; + +static void +nds32_fag_init (struct nds32_fag *head) +{ + memset (head, 0, sizeof (struct nds32_fag)); +} + +static void +nds32_fag_verify (struct nds32_fag *head) +{ + struct nds32_fag *iter; + struct nds32_fag *prev; + + prev = NULL; + iter = head->next; + while (iter) + { + if (prev && prev->addr >= iter->addr) + puts ("Bug in fp-as-gp insertion."); + prev = iter; + iter = iter->next; + } +} + +/* Insert a fag in ascending order. + If a fag of the same address already exists, + they are chained by relas array. */ + +static void +nds32_fag_insert (struct nds32_fag *head, bfd_vma addr, + Elf_Internal_Rela * rel) +{ + struct nds32_fag *iter; + struct nds32_fag *new_fag; + const int INIT_RELAS_CAP = 4; + + for (iter = head; + iter->next && iter->next->addr <= addr; + iter = iter->next) + /* Find somewhere to insert. */ ; + + /* `iter' will be equal to `head' if the list is empty. */ + if (iter != head && iter->addr == addr) + { + /* The address exists in the list. + Insert `rel' into relocation list, relas. */ + + /* Check whether relas is big enough. */ + if (iter->count >= iter->relas_capcity) + { + iter->relas_capcity *= 2; + iter->relas = bfd_realloc + (iter->relas, iter->relas_capcity * sizeof (void *)); + } + iter->relas[iter->count++] = rel; + return; + } + + /* This is a new address. Create a fag node for it. */ + new_fag = bfd_malloc (sizeof (struct nds32_fag)); + memset (new_fag, 0, sizeof (*new_fag)); + new_fag->addr = addr; + new_fag->count = 1; + new_fag->next = iter->next; + new_fag->relas_capcity = INIT_RELAS_CAP; + new_fag->relas = (Elf_Internal_Rela **) + bfd_malloc (new_fag->relas_capcity * sizeof (void *)); + new_fag->relas[0] = rel; + iter->next = new_fag; + + nds32_fag_verify (head); +} + +static void +nds32_fag_free_list (struct nds32_fag *head) +{ + struct nds32_fag *iter; + + iter = head->next; + while (iter) + { + struct nds32_fag *tmp = iter; + iter = iter->next; + free (tmp->relas); + tmp->relas = NULL; + free (tmp); + } +} + +/* Find the best fp-base address. + The relocation associated with that address is returned, + so we can track the symbol instead of a fixed address. + + When relaxation, the address of an datum may change, + because a text section is shrinked, so the data section + moves forward. If the aligments of text and data section + are different, their distance may change too. + Therefore, tracking a fixed address is not appriate. */ + +static int +nds32_fag_find_base (struct nds32_fag *head, struct nds32_fag **bestpp) +{ + struct nds32_fag *base; /* First fag in the window. */ + struct nds32_fag *last; /* First fag outside the window. */ + int accu = 0; /* Usage accumulation. */ + struct nds32_fag *best; /* Best fag. */ + int baccu = 0; /* Best accumulation. */ + + /* Use first fag for initial, and find the last fag in the window. + + In each iteration, we could simply subtract previous fag + and accumulate following fags which are inside the window, + untill we each the end. */ + + if (head->next == NULL) + { + *bestpp = NULL; + return 0; + } + + /* Initialize base. */ + base = head->next; + best = base; + for (last = base; + last && last->addr < base->addr + FAG_WINDOW; + last = last->next) + accu += last->count; + + baccu = accu; + + /* Record the best base in each iteration. */ + while (base->next) + { + accu -= base->count; + base = base->next; + /* Account fags in window. */ + for (/* Nothing. */; + last && last->addr < base->addr + FAG_WINDOW; + last = last->next) + accu += last->count; + + /* A better fp-base? */ + if (accu > baccu) + { + best = base; + baccu = accu; + } + } + + if (bestpp) + *bestpp = best; + return baccu; +} + +/* Apply R_NDS32_INSN16_FP7U2_FLAG on gp-relative accesses, + so we can convert it fo fp-relative access later. + `best_fag' is the best fp-base. Only those inside the window + of best_fag is applied the flag. */ + +static bfd_boolean +nds32_fag_mark_relax (struct bfd_link_info *link_info, + bfd *abfd, struct nds32_fag *best_fag, + Elf_Internal_Rela *internal_relocs, + Elf_Internal_Rela *irelend) +{ + struct nds32_fag *ifag; + bfd_vma best_fpbase, gp; + bfd *output_bfd; + + output_bfd = abfd->sections->output_section->owner; + nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE); + best_fpbase = best_fag->addr; + + if (best_fpbase > gp + sdata_range[1][1] + || best_fpbase < gp - sdata_range[1][0]) + return FALSE; + + /* Mark these inside the window R_NDS32_INSN16_FP7U2_FLAG flag, + so we know they can be converted to lwi37.fp. */ + for (ifag = best_fag; + ifag && ifag->addr < best_fpbase + FAG_WINDOW; ifag = ifag->next) + { + int i; + + for (i = 0; i < ifag->count; i++) + { + Elf_Internal_Rela *insn16_rel; + Elf_Internal_Rela *fag_rel; + + fag_rel = ifag->relas[i]; + + /* Only if this is within the WINDOWS, FP7U2_FLAG + is applied. */ + + insn16_rel = find_relocs_at_address + (fag_rel, internal_relocs, irelend, R_NDS32_INSN16); + + if (insn16_rel != irelend) + insn16_rel->r_addend = R_NDS32_INSN16_FP7U2_FLAG; + } + } + return TRUE; +} + +/* Reset INSN16 to clean fp as gp. */ + +static void +nds32_fag_unmark_relax (struct nds32_fag *fag, + Elf_Internal_Rela *internal_relocs, + Elf_Internal_Rela *irelend) +{ + struct nds32_fag *ifag; + int i; + Elf_Internal_Rela *insn16_rel; + Elf_Internal_Rela *fag_rel; + + for (ifag = fag; ifag; ifag = ifag->next) + { + for (i = 0; i < ifag->count; i++) + { + fag_rel = ifag->relas[i]; + + /* Restore the INSN16 relocation. */ + insn16_rel = find_relocs_at_address + (fag_rel, internal_relocs, irelend, R_NDS32_INSN16); + + if (insn16_rel != irelend) + insn16_rel->r_addend &= ~R_NDS32_INSN16_FP7U2_FLAG; + } + } +} + +/* This is the main function of fp-as-gp optimization. + It should be called by relax_section. */ + +static bfd_boolean +nds32_relax_fp_as_gp (struct bfd_link_info *link_info, + bfd *abfd, asection *sec, + Elf_Internal_Rela *internal_relocs, + Elf_Internal_Rela *irelend, + Elf_Internal_Sym *isymbuf) +{ + Elf_Internal_Rela *begin_rel = NULL; + Elf_Internal_Rela *irel; + struct nds32_fag fag_head; + Elf_Internal_Shdr *symtab_hdr; + bfd_byte *contents; + bfd_boolean ifc_inside = FALSE; + + /* FIXME: Can we bfd_elf_link_read_relocs for the relocs? */ + + /* Per-function fp-base selection. + 1. Create a list for all the gp-relative access. + 2. Base on those gp-relative address, + find a fp-base which can cover most access. + 3. Use the fp-base for fp-as-gp relaxation. + + NOTE: If fp-as-gp is not worth to do, (e.g., less than 3 times), + we should + 1. delete the `la $fp, _FP_BASE_' instruction and + 2. not convert lwi.gp to lwi37.fp. + + To delete the _FP_BASE_ instruction, we simply apply + R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG flag in the r_addend to disable it. + + To suppress the conversion, we simply NOT to apply + R_NDS32_INSN16_FP7U2_FLAG flag. */ + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + if (!nds32_get_section_contents (abfd, sec, &contents, TRUE) + || !nds32_get_local_syms (abfd, sec, &isymbuf)) + return FALSE; + + /* Check whether it is worth for fp-as-gp optimization, + i.e., at least 3 gp-load. + + Set R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG if we should NOT + apply this optimization. */ + + for (irel = internal_relocs; irel < irelend; irel++) + { + /* We recognize R_NDS32_RELAX_REGION_BEGIN/_END for the region. + One we enter the begin of the region, we track all the LW/ST + instructions, so when we leave the region, we try to find + the best fp-base address for those LW/ST instructions. */ + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN + && (irel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG)) + { + /* Begin of the region. */ + if (begin_rel) + (*_bfd_error_handler) (_("%B: Nested OMIT_FP in %A."), abfd, sec); + + begin_rel = irel; + nds32_fag_init (&fag_head); + ifc_inside = FALSE; + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END + && (irel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG)) + { + int accu; + struct nds32_fag *best_fag, *tmp_fag; + int dist; + + /* End of the region. + Check whether it is worth to do fp-as-gp. */ + + if (begin_rel == NULL) + { + (*_bfd_error_handler) (_("%B: Unmatched OMIT_FP in %A."), abfd, sec); + continue; + } + + accu = nds32_fag_find_base (&fag_head, &best_fag); + + /* Clean FP7U2_FLAG because they may set ever. */ + tmp_fag = fag_head.next; + nds32_fag_unmark_relax (tmp_fag, internal_relocs, irelend); + + /* Check if it is worth, and FP_BASE is near enough to SDA_BASE. */ + if (accu < FAG_THRESHOLD + || !nds32_fag_mark_relax (link_info, abfd, best_fag, + internal_relocs, irelend)) + { + /* Not worth to do fp-as-gp. */ + begin_rel->r_addend |= R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG; + begin_rel->r_addend &= ~R_NDS32_RELAX_REGION_OMIT_FP_FLAG; + irel->r_addend |= R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG; + irel->r_addend &= ~R_NDS32_RELAX_REGION_OMIT_FP_FLAG; + nds32_fag_free_list (&fag_head); + begin_rel = NULL; + continue; + } + + /* R_SYM of R_NDS32_RELAX_REGION_BEGIN is not used by assembler, + so we use it to record the distance to the reloction of best + fp-base. */ + dist = best_fag->relas[0] - begin_rel; + BFD_ASSERT (dist > 0 && dist < 0xffffff); + /* Use high 16 bits of addend to record the _FP_BASE_ matched + relocation. And get the base value when relocating. */ + begin_rel->r_addend &= (0x1 << 16) - 1; + begin_rel->r_addend |= dist << 16; + + nds32_fag_free_list (&fag_head); + begin_rel = NULL; + } + + if (begin_rel == NULL || ifc_inside) + /* Skip if we are not in the region of fp-as-gp. */ + continue; + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA15S2_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA17S2_RELA) + { + bfd_vma addr; + uint32_t insn; + + /* A gp-relative access is found. Insert it to the fag-list. */ + + /* Rt is necessary an RT3, so it can be converted to lwi37.fp. */ + insn = bfd_getb32 (contents + irel->r_offset); + if (!N32_IS_RT3 (insn)) + continue; + + addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); + nds32_fag_insert (&fag_head, addr, irel); + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA_FP7U2_RELA) + { + begin_rel = NULL; + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_10IFCU_PCREL_RELA) + { + /* Suppress fp as gp when encounter ifc. */ + ifc_inside = TRUE; + } + } + + return TRUE; +} + +/* Remove unused `la $fp, _FD_BASE_' instruction. */ + +static bfd_boolean +nds32_fag_remove_unused_fpbase (bfd *abfd, asection *sec, + Elf_Internal_Rela *internal_relocs, + Elf_Internal_Rela *irelend) +{ + Elf_Internal_Rela *irel; + Elf_Internal_Shdr *symtab_hdr; + bfd_byte *contents = NULL; + nds32_elf_blank_t *relax_blank_list = NULL; + bfd_boolean result = TRUE; + bfd_boolean unused_region = FALSE; + + /* + NOTE: Disable fp-as-gp if we encounter ifcall relocations. + * R_NDS32_17IFC_PCREL_RELA + * R_NDS32_10IFCU_PCREL_RELA + + CASE?????????????? + */ + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + nds32_get_section_contents (abfd, sec, &contents, TRUE); + + for (irel = internal_relocs; irel < irelend; irel++) + { + /* To remove unused fp-base, we simply find the REGION_NOT_OMIT_FP + we marked to in previous pass. + DO NOT scan relocations again, since we've alreadly decided it + and set the flag. */ + const char *syname; + int syndx; + uint32_t insn; + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN + && (irel->r_addend & R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG)) + unused_region = TRUE; + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END + && (irel->r_addend & R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG)) + unused_region = FALSE; + + /* We're not in the region. */ + if (!unused_region) + continue; + + /* _FP_BASE_ must be a GLOBAL symbol. */ + syndx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; + if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) + continue; + + /* The symbol name must be _FP_BASE_. */ + syname = elf_sym_hashes (abfd)[syndx]->root.root.string; + if (strcmp (syname, FP_BASE_NAME) != 0) + continue; + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA19S0_RELA) + { + /* addi.gp $fp, -256 */ + insn = bfd_getb32 (contents + irel->r_offset); + if (insn != INSN_ADDIGP_TO_FP) + continue; + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA15S0_RELA) + { + /* addi $fp, $gp, -256 */ + insn = bfd_getb32 (contents + irel->r_offset); + if (insn != INSN_ADDI_GP_TO_FP) + continue; + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_20_RELA) + { + /* movi $fp, FP_BASE */ + insn = bfd_getb32 (contents + irel->r_offset); + if (insn != INSN_MOVI_TO_FP) + continue; + } + else + continue; + + /* We got here because a FP_BASE instruction is found. */ + if (!insert_nds32_elf_blank_recalc_total + (&relax_blank_list, irel->r_offset, 4)) + goto error_return; + } + +finish: + if (relax_blank_list) + { + nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list); + relax_blank_list = NULL; + } + return result; + +error_return: + result = FALSE; + goto finish; +} + +/* This is a version of bfd_generic_get_relocated_section_contents. + We need this variety because relaxation will modify the dwarf + infomation. When there is undefined symbol reference error mesage, + linker need to dump line number where the symbol be used. However + the address is be relaxed, it can not get the original dwarf contents. + The variety only modify function call for reading in the section. */ + +static bfd_byte * +nds32_elf_get_relocated_section_contents (bfd *abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + bfd_byte *data, + bfd_boolean relocatable, + asymbol **symbols) +{ + bfd *input_bfd = link_order->u.indirect.section->owner; + asection *input_section = link_order->u.indirect.section; + long reloc_size; + arelent **reloc_vector; + long reloc_count; + + reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); + if (reloc_size < 0) + return NULL; + + /* Read in the section. */ + if (!nds32_get_section_contents (input_bfd, input_section, &data, FALSE)) + return NULL; + + if (reloc_size == 0) + return data; + + reloc_vector = (arelent **) bfd_malloc (reloc_size); + if (reloc_vector == NULL) + return NULL; + + reloc_count = bfd_canonicalize_reloc (input_bfd, input_section, + reloc_vector, symbols); + if (reloc_count < 0) + goto error_return; + + if (reloc_count > 0) + { + arelent **parent; + for (parent = reloc_vector; *parent != NULL; parent++) + { + char *error_message = NULL; + asymbol *symbol; + bfd_reloc_status_type r; + + symbol = *(*parent)->sym_ptr_ptr; + if (symbol->section && discarded_section (symbol->section)) + { + bfd_byte *p; + static reloc_howto_type none_howto + = HOWTO (0, 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, + "unused", FALSE, 0, 0, FALSE); + + p = data + (*parent)->address * bfd_octets_per_byte (input_bfd); + _bfd_clear_contents ((*parent)->howto, input_bfd, input_section, + p); + (*parent)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + (*parent)->addend = 0; + (*parent)->howto = &none_howto; + r = bfd_reloc_ok; + } + else + r = bfd_perform_relocation (input_bfd, *parent, data, + input_section, + relocatable ? abfd : NULL, + &error_message); + + if (relocatable) + { + asection *os = input_section->output_section; + + /* A partial link, so keep the relocs. */ + os->orelocation[os->reloc_count] = *parent; + os->reloc_count++; + } + + if (r != bfd_reloc_ok) + { + switch (r) + { + case bfd_reloc_undefined: + if (!((*link_info->callbacks->undefined_symbol) + (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), + input_bfd, input_section, (*parent)->address, TRUE))) + goto error_return; + break; + case bfd_reloc_dangerous: + BFD_ASSERT (error_message != NULL); + if (!((*link_info->callbacks->reloc_dangerous) + (link_info, error_message, input_bfd, input_section, + (*parent)->address))) + goto error_return; + break; + case bfd_reloc_overflow: + if (!((*link_info->callbacks->reloc_overflow) + (link_info, NULL, + bfd_asymbol_name (*(*parent)->sym_ptr_ptr), + (*parent)->howto->name, (*parent)->addend, + input_bfd, input_section, (*parent)->address))) + goto error_return; + break; + case bfd_reloc_outofrange: + /* PR ld/13730: + This error can result when processing some partially + complete binaries. Do not abort, but issue an error + message instead. */ + link_info->callbacks->einfo + (_("%X%P: %B(%A): relocation \"%R\" goes out of range\n"), + abfd, input_section, * parent); + goto error_return; + + default: + abort (); + break; + } + } + } + } + + free (reloc_vector); + return data; + +error_return: + free (reloc_vector); + return NULL; +} + +/* Link-time IFC relaxation. + In this optimization, we chains jump instructions + of the same destination with ifcall. */ + + +/* List to save jal and j relocation. */ +struct elf_nds32_ifc_symbol_entry +{ + asection *sec; + struct elf_link_hash_entry *h; + struct elf_nds32_ifc_irel_list *irel_head; + unsigned long insn; + int times; + int enable; /* Apply ifc. */ + int ex9_enable; /* Apply ifc after ex9. */ + struct elf_nds32_ifc_symbol_entry *next; +}; + +struct elf_nds32_ifc_irel_list +{ + Elf_Internal_Rela *irel; + asection *sec; + bfd_vma addr; + /* If this is set, then it is the last instruction for + ifc-chain, so it must be keep for the actual branching. */ + int keep; + struct elf_nds32_ifc_irel_list *next; +}; + +static struct elf_nds32_ifc_symbol_entry *ifc_symbol_head = NULL; + +/* Insert symbol of jal and j for ifc. */ + +static void +nds32_elf_ifc_insert_symbol (asection *sec, + struct elf_link_hash_entry *h, + Elf_Internal_Rela *irel, + unsigned long insn) +{ + struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; + + /* Check there is target of existing entry the same as the new one. */ + while (ptr != NULL) + { + if (((h == NULL && ptr->sec == sec + && ELF32_R_SYM (ptr->irel_head->irel->r_info) == ELF32_R_SYM (irel->r_info) + && ptr->irel_head->irel->r_addend == irel->r_addend) + || h != NULL) + && ptr->h == h + && ptr->insn == insn) + { + /* The same target exist, so insert into list. */ + struct elf_nds32_ifc_irel_list *irel_list = ptr->irel_head; + + while (irel_list->next != NULL) + irel_list = irel_list->next; + irel_list->next = bfd_malloc (sizeof (struct elf_nds32_ifc_irel_list)); + irel_list = irel_list->next; + irel_list->irel = irel; + irel_list->keep = 1; + + if (h == NULL) + irel_list->sec = NULL; + else + irel_list->sec = sec; + irel_list->next = NULL; + return; + } + if (ptr->next == NULL) + break; + ptr = ptr->next; + } + + /* There is no same target entry, so build a new one. */ + if (ifc_symbol_head == NULL) + { + ifc_symbol_head = bfd_malloc (sizeof (struct elf_nds32_ifc_symbol_entry)); + ptr = ifc_symbol_head; + } + else + { + ptr->next = bfd_malloc (sizeof (struct elf_nds32_ifc_symbol_entry)); + ptr = ptr->next; + } + + ptr->h = h; + ptr->irel_head = bfd_malloc (sizeof (struct elf_nds32_ifc_irel_list)); + ptr->irel_head->irel = irel; + ptr->insn = insn; + ptr->irel_head->keep = 1; + + if (h == NULL) + { + /* Local symbols. */ + ptr->sec = sec; + ptr->irel_head->sec = NULL; + } + else + { + /* Global symbol. */ + ptr->sec = NULL; + ptr->irel_head->sec = sec; + } + + ptr->irel_head->next = NULL; + ptr->times = 0; + ptr->enable = 0; + ptr->ex9_enable = 0; + ptr->next = NULL; +} + +/* Gather all jal and j instructions. */ + +static bfd_boolean +nds32_elf_ifc_calc (struct bfd_link_info *info, + bfd *abfd, asection *sec) +{ + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irelend; + Elf_Internal_Rela *irel; + Elf_Internal_Shdr *symtab_hdr; + bfd_byte *contents = NULL; + uint32_t insn, insn_with_reg; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd); + struct elf_nds32_link_hash_table *table; + bfd_boolean ifc_loop_aware; + + internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, + TRUE /* keep_memory */); + irelend = internal_relocs + sec->reloc_count; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + /* Check if the object enable ifc. */ + irel = find_relocs_at_address (internal_relocs, internal_relocs, irelend, + R_NDS32_RELAX_ENTRY); + + if (irel == NULL + || irel >= irelend + || ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY + || (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY + && !(irel->r_addend & R_NDS32_RELAX_ENTRY_IFC_FLAG))) + return TRUE; + + if (!nds32_get_section_contents (abfd, sec, &contents, TRUE)) + return FALSE; + + table = nds32_elf_hash_table (info); + ifc_loop_aware = table->ifc_loop_aware; + while (irel != NULL && irel < irelend) + { + /* Traverse all relocation and gather all of them to build the list. */ + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN) + { + if (ifc_loop_aware == 1 + && (irel->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG) != 0) + { + /* Check the region if loop or not. If it is true and + ifc-loop-aware is true, ignore the region till region end. */ + while (irel != NULL + && irel < irelend + && (ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_REGION_END + || (irel->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG) != 0)) + irel++; + } + } + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA) + { + insn = bfd_getb32 (contents + irel->r_offset); + nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg); + r_symndx = ELF32_R_SYM (irel->r_info); + if (r_symndx < symtab_hdr->sh_info) + { + /* Local symbol. */ + nds32_elf_ifc_insert_symbol (sec, NULL, irel, insn_with_reg); + } + else + { + /* External symbol. */ + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + nds32_elf_ifc_insert_symbol (sec, h, irel, insn_with_reg); + } + } + irel++; + } + return TRUE; +} + +/* Determine whether j and jal should be substituted. */ + +static void +nds32_elf_ifc_filter (struct bfd_link_info *info) +{ + struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; + struct elf_nds32_ifc_irel_list *irel_ptr = NULL; + struct elf_nds32_ifc_irel_list *irel_keeper = NULL; + struct elf_nds32_link_hash_table *table; + int target_optimize; + bfd_vma address; + + table = nds32_elf_hash_table (info); + target_optimize = table->target_optimize; + while (ptr) + { + irel_ptr = ptr->irel_head; + if (ptr->h == NULL) + { + /* Local symbol. */ + irel_keeper = irel_ptr; + while (irel_ptr && irel_ptr->next) + { + /* Check there is jump target can be used. */ + if ((irel_ptr->next->irel->r_offset + - irel_keeper->irel->r_offset) > 1022) + irel_keeper = irel_ptr->next; + else + { + ptr->enable = 1; + irel_ptr->keep = 0; + } + irel_ptr = irel_ptr->next; + } + } + else + { + /* Global symbol. */ + /* We have to get the absolute address and decide + whether to keep it or not. */ + while (irel_ptr) + { + address = (irel_ptr->irel->r_offset + + irel_ptr->sec->output_section->vma + + irel_ptr->sec->output_offset); + irel_ptr->addr = address; + irel_ptr = irel_ptr->next; + } + + irel_ptr = ptr->irel_head; + while (irel_ptr) + { + /* Sort by address. */ + struct elf_nds32_ifc_irel_list *irel_dest = irel_ptr; + struct elf_nds32_ifc_irel_list *irel_temp = irel_ptr; + struct elf_nds32_ifc_irel_list *irel_ptr_prev = NULL; + struct elf_nds32_ifc_irel_list *irel_dest_prev = NULL; + + /* Get the smallest one. */ + while (irel_temp->next) + { + if (irel_temp->next->addr < irel_dest->addr) + { + irel_dest_prev = irel_temp; + irel_dest = irel_temp->next; + } + irel_temp = irel_temp->next; + } + + if (irel_dest != irel_ptr) + { + if (irel_ptr_prev) + irel_ptr_prev->next = irel_dest; + if (irel_dest_prev) + irel_dest_prev->next = irel_ptr; + irel_temp = irel_ptr->next; + irel_ptr->next = irel_dest->next; + irel_dest->next = irel_temp; + } + irel_ptr_prev = irel_ptr; + irel_ptr = irel_ptr->next; + } + + irel_ptr = ptr->irel_head; + irel_keeper = irel_ptr; + while (irel_ptr && irel_ptr->next) + { + if ((irel_ptr->next->addr - irel_keeper->addr) > 1022) + irel_keeper = irel_ptr->next; + else + { + ptr->enable = 1; + irel_ptr->keep = 0; + } + irel_ptr = irel_ptr->next; + } + } + + /* Ex9 enable. Reserve it for ex9. */ + if ((target_optimize & NDS32_RELAX_EX9_ON) + && ptr->irel_head != irel_keeper) + ptr->enable = 0; + ptr = ptr->next; + } +} + +/* Determine whether j and jal should be substituted after ex9 done. */ + +static void +nds32_elf_ifc_filter_after_ex9 (void) +{ + struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; + struct elf_nds32_ifc_irel_list *irel_ptr = NULL; + + while (ptr) + { + if (ptr->enable == 0) + { + /* Check whether ifc is applied or not. */ + irel_ptr = ptr->irel_head; + ptr->ex9_enable = 1; + while (irel_ptr) + { + if (ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_TRAN) + { + /* Ex9 already. */ + ptr->ex9_enable = 0; + break; + } + irel_ptr = irel_ptr->next; + } + } + ptr = ptr->next; + } +} + +/* Wrapper to do ifc relaxation. */ + +bfd_boolean +nds32_elf_ifc_finish (struct bfd_link_info *info) +{ + int relax_status; + struct elf_nds32_link_hash_table *table; + + table = nds32_elf_hash_table (info); + relax_status = table->relax_status; + + if (!(relax_status & NDS32_RELAX_JUMP_IFC_DONE)) + nds32_elf_ifc_filter (info); + else + nds32_elf_ifc_filter_after_ex9 (); + + if (!nds32_elf_ifc_replace (info)) + return FALSE; + + if (table) + table->relax_status |= NDS32_RELAX_JUMP_IFC_DONE; + return TRUE; +} + +/* Traverse the result of ifc filter and replace it with ifcall9. */ + +static bfd_boolean +nds32_elf_ifc_replace (struct bfd_link_info *info) +{ + struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; + struct elf_nds32_ifc_irel_list *irel_ptr = NULL; + nds32_elf_blank_t *relax_blank_list = NULL; + bfd_byte *contents = NULL; + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irel; + Elf_Internal_Rela *irelend; + unsigned short insn16 = INSN_IFCALL9; + struct elf_nds32_link_hash_table *table; + int relax_status; + + table = nds32_elf_hash_table (info); + relax_status = table->relax_status; + + while (ptr) + { + /* Traverse the ifc gather list, and replace the + filter entries by ifcall9. */ + if ((!(relax_status & NDS32_RELAX_JUMP_IFC_DONE) && ptr->enable == 1) + || ((relax_status & NDS32_RELAX_JUMP_IFC_DONE) + && ptr->ex9_enable == 1)) + { + irel_ptr = ptr->irel_head; + if (ptr->h == NULL) + { + /* Local symbol. */ + internal_relocs = _bfd_elf_link_read_relocs + (ptr->sec->owner, ptr->sec, NULL, NULL, TRUE /* keep_memory */); + irelend = internal_relocs + ptr->sec->reloc_count; + + if (!nds32_get_section_contents (ptr->sec->owner, ptr->sec, + &contents, TRUE)) + return FALSE; + + while (irel_ptr) + { + if (irel_ptr->keep == 0 && irel_ptr->next) + { + /* The one can be replaced. We have to check whether + there is any alignment point in the region. */ + irel = irel_ptr->irel; + while (((irel_ptr->next->keep == 0 + && irel < irel_ptr->next->irel) + || (irel_ptr->next->keep == 1 && irel < irelend)) + && !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL + && (irel->r_addend & 0x1f) == 2)) + irel++; + if (irel >= irelend + || !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL + && (irel->r_addend & 0x1f) == 2 + && ((irel->r_offset - get_nds32_elf_blank_total + (&relax_blank_list, irel->r_offset, 1)) + & 0x02) == 0)) + { + /* Replace by ifcall9. */ + bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset); + if (!insert_nds32_elf_blank_recalc_total + (&relax_blank_list, irel_ptr->irel->r_offset + 2, 2)) + return FALSE; + irel_ptr->irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), + R_NDS32_10IFCU_PCREL_RELA); + } + } + irel_ptr = irel_ptr->next; + } + + /* Delete the redundant code. */ + if (relax_blank_list) + { + nds32_elf_relax_delete_blanks (ptr->sec->owner, ptr->sec, + relax_blank_list); + relax_blank_list = NULL; + } + } + else + { + /* Global symbol. */ + while (irel_ptr) + { + if (irel_ptr->keep == 0 && irel_ptr->next) + { + /* The one can be replaced, and we have to check + whether there is any alignment point in the region. */ + internal_relocs = _bfd_elf_link_read_relocs + (irel_ptr->sec->owner, irel_ptr->sec, NULL, NULL, + TRUE /* keep_memory */); + irelend = internal_relocs + irel_ptr->sec->reloc_count; + if (!nds32_get_section_contents (irel_ptr->sec->owner, + irel_ptr->sec, &contents, + TRUE)) + return FALSE; + + irel = irel_ptr->irel; + while (((irel_ptr->sec == irel_ptr->next->sec + && irel_ptr->next->keep == 0 + && irel < irel_ptr->next->irel) + || ((irel_ptr->sec != irel_ptr->next->sec + || irel_ptr->next->keep == 1) + && irel < irelend)) + && !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL + && (irel->r_addend & 0x1f) == 2)) + irel++; + if (irel >= irelend + || !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL + && (irel->r_addend & 0x1f) == 2 + && ((irel->r_offset + - get_nds32_elf_blank_total (&relax_blank_list, + irel->r_offset, 1)) & 0x02) == 0)) + { + /* Replace by ifcall9. */ + bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset); + if (!insert_nds32_elf_blank_recalc_total + (&relax_blank_list, irel_ptr->irel->r_offset + 2, 2)) + return FALSE; + + /* Delete the redundant code, and clear the relocation. */ + nds32_elf_relax_delete_blanks (irel_ptr->sec->owner, + irel_ptr->sec, + relax_blank_list); + irel_ptr->irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), + R_NDS32_10IFCU_PCREL_RELA); + relax_blank_list = NULL; + } + } + + irel_ptr = irel_ptr->next; + } + } + } + ptr = ptr->next; + } + + return TRUE; +} + +/* Relocate ifcall. */ + +static bfd_boolean +nds32_elf_ifc_reloc (void) +{ + struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; + struct elf_nds32_ifc_irel_list *irel_ptr = NULL; + struct elf_nds32_ifc_irel_list *irel_keeper = NULL; + bfd_vma relocation, address; + unsigned short insn16; + bfd_byte *contents = NULL; + static bfd_boolean done = FALSE; + + if (done) + return TRUE; + + done = TRUE; + + while (ptr) + { + /* Check the entry is enable ifcall. */ + if (ptr->enable == 1 || ptr->ex9_enable == 1) + { + /* Get the reserve jump. */ + irel_ptr = ptr->irel_head; + while (irel_ptr) + { + if (irel_ptr->keep == 1) + { + irel_keeper = irel_ptr; + break; + } + irel_ptr = irel_ptr->next; + } + + irel_ptr = ptr->irel_head; + if (ptr->h == NULL) + { + /* Local symbol. */ + if (!nds32_get_section_contents (ptr->sec->owner, ptr->sec, + &contents, TRUE)) + return FALSE; + + while (irel_ptr) + { + if (irel_ptr->keep == 0 + && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_10IFCU_PCREL_RELA) + { + relocation = irel_keeper->irel->r_offset; + relocation = relocation - irel_ptr->irel->r_offset; + while (irel_keeper && relocation > 1022) + { + irel_keeper = irel_keeper->next; + if (irel_keeper && irel_keeper->keep == 1) + { + relocation = irel_keeper->irel->r_offset; + relocation = relocation - irel_ptr->irel->r_offset; + } + } + if (relocation > 1022) + { + /* Double check. */ + irel_keeper = ptr->irel_head; + while (irel_keeper) + { + if (irel_keeper->keep == 1) + { + relocation = irel_keeper->irel->r_offset; + relocation = relocation - irel_ptr->irel->r_offset; + } + if (relocation <= 1022) + break; + irel_keeper = irel_keeper->next; + } + if (!irel_keeper) + return FALSE; + } + irel_ptr->irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), + R_NDS32_NONE); + insn16 = INSN_IFCALL9 | (relocation >> 1); + bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset); + } + irel_ptr = irel_ptr->next; + } + } + else + { + /* Global symbol. */ + while (irel_ptr) + { + if (irel_ptr->keep == 0 + && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_10IFCU_PCREL_RELA) + { + /* Get the distance between ifcall and jump. */ + relocation = (irel_keeper->irel->r_offset + + irel_keeper->sec->output_section->vma + + irel_keeper->sec->output_offset); + address = (irel_ptr->irel->r_offset + + irel_ptr->sec->output_section->vma + + irel_ptr->sec->output_offset); + relocation = relocation - address; + + /* The distance is over ragne, find callee again. */ + while (irel_keeper && relocation > 1022) + { + irel_keeper = irel_keeper->next; + if (irel_keeper && irel_keeper->keep ==1) + { + relocation = (irel_keeper->irel->r_offset + + irel_keeper->sec->output_section->vma + + irel_keeper->sec->output_offset); + relocation = relocation - address; + } + } + + if (relocation > 1022) + { + /* Double check. */ + irel_keeper = ptr->irel_head; + while (irel_keeper) + { + if (irel_keeper->keep == 1) + { + + relocation = (irel_keeper->irel->r_offset + + irel_keeper->sec->output_section->vma + + irel_keeper->sec->output_offset); + relocation = relocation - address; + } + if (relocation <= 1022) + break; + irel_keeper = irel_keeper->next; + } + if (!irel_keeper) + return FALSE; + } + if (!nds32_get_section_contents + (irel_ptr->sec->owner, irel_ptr->sec, &contents, TRUE)) + return FALSE; + insn16 = INSN_IFCALL9 | (relocation >> 1); + bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset); + irel_ptr->irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), + R_NDS32_NONE); + } + irel_ptr =irel_ptr->next; + } + } + } + ptr = ptr->next; + } + + return TRUE; +} + +/* End of IFC relaxation. */ + +/* EX9 Instruction Table Relaxation. */ + +/* Global hash list. */ +struct elf_link_hash_entry_list +{ + struct elf_link_hash_entry *h; + struct elf_link_hash_entry_list *next; +}; + +/* Save different destination but same insn. */ +struct elf_link_hash_entry_mul_list +{ + /* Global symbol times. */ + int times; + /* Save relocation for each global symbol but useful?? */ + Elf_Internal_Rela *irel; + /* For sethi, two sethi may have the same high-part but different low-parts. */ + Elf_Internal_Rela rel_backup; + struct elf_link_hash_entry_list *h_list; + struct elf_link_hash_entry_mul_list *next; +}; + +/* Instruction hash table. */ +struct elf_nds32_code_hash_entry +{ + struct bfd_hash_entry root; + int times; + /* For insn that can use relocation or constant ex: sethi. */ + int const_insn; + asection *sec; + struct elf_link_hash_entry_mul_list *m_list; + /* Using r_addend. */ + Elf_Internal_Rela *irel; + /* Using r_info. */ + Elf_Internal_Rela rel_backup; +}; + +/* Instruction count list. */ +struct elf_nds32_insn_times_entry +{ + const char *string; + int times; + int order; + asection *sec; + struct elf_link_hash_entry_mul_list *m_list; + Elf_Internal_Rela *irel; + Elf_Internal_Rela rel_backup; + struct elf_nds32_insn_times_entry *next; +}; + +/* J and JAL symbol list. */ +struct elf_nds32_symbol_entry +{ + char *string; + unsigned long insn; + struct elf_nds32_symbol_entry *next; +}; + +/* Relocation list. */ +struct elf_nds32_irel_entry +{ + Elf_Internal_Rela *irel; + struct elf_nds32_irel_entry *next; +}; + +/* ex9.it insn need to be fixed. */ +struct elf_nds32_ex9_refix +{ + Elf_Internal_Rela *irel; + asection *sec; + struct elf_link_hash_entry *h; + int order; + struct elf_nds32_ex9_refix *next; +}; + +static struct bfd_hash_table ex9_code_table; +static struct elf_nds32_insn_times_entry *ex9_insn_head = NULL; +static struct elf_nds32_ex9_refix *ex9_refix_head = NULL; + +/* EX9 hash function. */ + +static struct bfd_hash_entry * +nds32_elf_code_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string) +{ + struct elf_nds32_code_hash_entry *ret; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (entry == NULL) + { + entry = (struct bfd_hash_entry *) + bfd_hash_allocate (table, sizeof (*ret)); + if (entry == NULL) + return entry; + } + + /* Call the allocation method of the superclass. */ + entry = bfd_hash_newfunc (entry, table, string); + if (entry == NULL) + return entry; + + ret = (struct elf_nds32_code_hash_entry*) entry; + ret->times = 0; + ret->const_insn = 0; + ret->m_list = NULL; + ret->sec = NULL; + ret->irel = NULL; + return &ret->root; +} + +/* Insert ex9 entry + this insert must be stable sorted by times. */ + +static void +nds32_elf_ex9_insert_entry (struct elf_nds32_insn_times_entry *ptr) +{ + struct elf_nds32_insn_times_entry *temp; + struct elf_nds32_insn_times_entry *temp2; + + if (ex9_insn_head == NULL) + { + ex9_insn_head = ptr; + ptr->next = NULL; + } + else + { + temp = ex9_insn_head; + temp2 = ex9_insn_head; + while (temp->next && + (temp->next->times >= ptr->times + || temp->times == -1)) + { + if (temp->times == -1) + temp2 = temp; + temp = temp->next; + } + if (ptr->times > temp->times && temp->times != -1) + { + ptr->next = temp; + if (temp2->times == -1) + temp2->next = ptr; + else + ex9_insn_head = ptr; + } + else if (temp->next == NULL) + { + temp->next = ptr; + ptr->next = NULL; + } + else + { + ptr->next = temp->next; + temp->next = ptr; + } + } +} + +/* Examine each insn times in hash table. + Handle multi-link hash entry. + + TODO: This function doesn't assign so much info since it is fake. */ + +static int +nds32_elf_examine_insn_times (struct elf_nds32_code_hash_entry *h) +{ + struct elf_nds32_insn_times_entry *ptr; + int times; + + if (h->m_list == NULL) + { + /* Local symbol insn or insn without relocation. */ + if (h->times < 3) + return TRUE; + + ptr = (struct elf_nds32_insn_times_entry *) + bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); + ptr->times = h->times; + ptr->string = h->root.string; + ptr->m_list = NULL; + ptr->sec = h->sec; + ptr->irel = h->irel; + ptr->rel_backup = h->rel_backup; + nds32_elf_ex9_insert_entry (ptr); + } + else + { + /* Global symbol insn. */ + /* Only sethi insn has multiple m_list. */ + struct elf_link_hash_entry_mul_list *m_list = h->m_list; + + times = 0; + while (m_list) + { + times += m_list->times; + m_list = m_list->next; + } + if (times >= 3) + { + m_list = h->m_list; + ptr = (struct elf_nds32_insn_times_entry *) + bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); + ptr->times = times; /* Use the total times. */ + ptr->string = h->root.string; + ptr->m_list = m_list; + ptr->sec = h->sec; + ptr->irel = m_list->irel; + ptr->rel_backup = m_list->rel_backup; + nds32_elf_ex9_insert_entry (ptr); + } + if (h->const_insn == 1) + { + /* sethi with constant value. */ + if (h->times < 3) + return TRUE; + + ptr = (struct elf_nds32_insn_times_entry *) + bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); + ptr->times = h->times; + ptr->string = h->root.string; + ptr->m_list = NULL; + ptr->sec = NULL; + ptr->irel = NULL; + ptr->rel_backup = h->rel_backup; + nds32_elf_ex9_insert_entry (ptr); + } + } + return TRUE; +} + +/* Count each insn times in hash table. + Handle multi-link hash entry. */ + +static int +nds32_elf_count_insn_times (struct elf_nds32_code_hash_entry *h) +{ + int reservation, times; + unsigned long relocation, min_relocation; + struct elf_nds32_insn_times_entry *ptr; + + if (h->m_list == NULL) + { + /* Local symbol insn or insn without relocation. */ + if (h->times < 3) + return TRUE; + ptr = (struct elf_nds32_insn_times_entry *) + bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); + ptr->times = h->times; + ptr->string = h->root.string; + ptr->m_list = NULL; + ptr->sec = h->sec; + ptr->irel = h->irel; + ptr->rel_backup = h->rel_backup; + nds32_elf_ex9_insert_entry (ptr); + } + else + { + /* Global symbol insn. */ + /* Only sethi insn has multiple m_list. */ + struct elf_link_hash_entry_mul_list *m_list = h->m_list; + + if (ELF32_R_TYPE (m_list->rel_backup.r_info) == R_NDS32_HI20_RELA + && m_list->next != NULL) + { + /* Sethi insn has different symbol or addend but has same hi20. */ + times = 0; + reservation = 1; + relocation = 0; + min_relocation = 0xffffffff; + while (m_list) + { + /* Get the minimum sethi address + and calculate how many entry the sethi-list have to use. */ + if ((m_list->h_list->h->root.type == bfd_link_hash_defined + || m_list->h_list->h->root.type == bfd_link_hash_defweak) + && (m_list->h_list->h->root.u.def.section != NULL + && m_list->h_list->h->root.u.def.section->output_section != NULL)) + { + relocation = (m_list->h_list->h->root.u.def.value + + m_list->h_list->h->root.u.def.section->output_section->vma + + m_list->h_list->h->root.u.def.section->output_offset); + relocation += m_list->irel->r_addend; + } + else + relocation = 0; + if (relocation < min_relocation) + min_relocation = relocation; + times += m_list->times; + m_list = m_list->next; + } + if (min_relocation < ex9_relax_size) + reservation = (min_relocation >> 12) + 1; + else + reservation = (min_relocation >> 12) + - ((min_relocation - ex9_relax_size) >> 12) + 1; + if (reservation < (times / 3)) + { + /* Efficient enough to use ex9. */ + int i; + + for (i = reservation ; i > 0; i--) + { + /* Allocate number of reservation ex9 entry. */ + ptr = (struct elf_nds32_insn_times_entry *) + bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); + ptr->times = h->m_list->times / reservation; + ptr->string = h->root.string; + ptr->m_list = h->m_list; + ptr->sec = h->sec; + ptr->irel = h->m_list->irel; + ptr->rel_backup = h->m_list->rel_backup; + nds32_elf_ex9_insert_entry (ptr); + } + } + } + else + { + /* Normal global symbol that means no different address symbol + using same ex9 entry. */ + if (m_list->times >= 3) + { + ptr = (struct elf_nds32_insn_times_entry *) + bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); + ptr->times = m_list->times; + ptr->string = h->root.string; + ptr->m_list = h->m_list; + ptr->sec = h->sec; + ptr->irel = h->m_list->irel; + ptr->rel_backup = h->m_list->rel_backup; + nds32_elf_ex9_insert_entry (ptr); + } + } + + if (h->const_insn == 1) + { + /* sethi with constant value. */ + if (h->times < 3) + return TRUE; + + ptr = (struct elf_nds32_insn_times_entry *) + bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); + ptr->times = h->times; + ptr->string = h->root.string; + ptr->m_list = NULL; + ptr->sec = NULL; + ptr->irel = NULL; + ptr->rel_backup = h->rel_backup; + nds32_elf_ex9_insert_entry (ptr); + } + } + + return TRUE; +} + +/* Hash table traverse function. */ + +static void +nds32_elf_code_hash_traverse (int (*func) (struct elf_nds32_code_hash_entry*)) +{ + unsigned int i; + + ex9_code_table.frozen = 1; + for (i = 0; i < ex9_code_table.size; i++) + { + struct bfd_hash_entry *p; + + for (p = ex9_code_table.table[i]; p != NULL; p = p->next) + if (!func ((struct elf_nds32_code_hash_entry *) p)) + goto out; + } +out: + ex9_code_table.frozen = 0; +} + + +/* Give order number to insn list. */ + +static void +nds32_elf_order_insn_times (struct bfd_link_info *info) +{ + struct elf_nds32_insn_times_entry *ex9_insn; + struct elf_nds32_insn_times_entry *temp = NULL; + struct elf_nds32_link_hash_table *table; + int ex9_limit; + int number = 0; + + if (ex9_insn_head == NULL) + return; + +/* The max number of entries is 512. */ + ex9_insn = ex9_insn_head; + table = nds32_elf_hash_table (info); + ex9_limit = table->ex9_limit; + + ex9_insn = ex9_insn_head; + + while (ex9_insn != NULL && number < ex9_limit) + { + ex9_insn->order = number; + number++; + temp = ex9_insn; + ex9_insn = ex9_insn->next; + } + + if (ex9_insn && temp) + temp->next = NULL; + + while (ex9_insn != NULL) + { + /* Free useless entry. */ + temp = ex9_insn; + ex9_insn = ex9_insn->next; + free (temp); + } +} + +/* Build .ex9.itable section. */ + +static void +nds32_elf_ex9_build_itable (struct bfd_link_info *link_info) +{ + asection *table_sec; + struct elf_nds32_insn_times_entry *ptr; + bfd *it_abfd; + int number = 0; + bfd_byte *contents = NULL; + + for (it_abfd = link_info->input_bfds; it_abfd != NULL; + it_abfd = it_abfd->link.next) + { + /* Find the section .ex9.itable, and put all entries into it. */ + table_sec = bfd_get_section_by_name (it_abfd, ".ex9.itable"); + if (table_sec != NULL) + { + if (!nds32_get_section_contents (it_abfd, table_sec, &contents, TRUE)) + return; + + for (ptr = ex9_insn_head; ptr !=NULL ; ptr = ptr->next) + number++; + + table_sec->size = number * 4; + + if (number == 0) + return; + + elf_elfheader (link_info->output_bfd)->e_flags |= E_NDS32_HAS_EX9_INST; + number = 0; + for (ptr = ex9_insn_head; ptr !=NULL ; ptr = ptr->next) + { + long val; + + val = strtol (ptr->string, NULL, 16); + bfd_putb32 ((bfd_vma) val, (char *) contents + (number * 4)); + number++; + } + break; + } + } +} + +/* Get insn with regs according to relocation type. */ + +static void +nds32_elf_get_insn_with_reg (Elf_Internal_Rela *irel, + uint32_t insn, uint32_t *insn_with_reg) +{ + reloc_howto_type *howto = NULL; + + if (irel == NULL + || (ELF32_R_TYPE (irel->r_info) >= (int) ARRAY_SIZE (nds32_elf_howto_table) + && (ELF32_R_TYPE (irel->r_info) - R_NDS32_RELAX_ENTRY) + >= (int) ARRAY_SIZE (nds32_elf_relax_howto_table))) + { + *insn_with_reg = insn; + return; + } + + howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info)); + *insn_with_reg = insn & (0xffffffff ^ howto->dst_mask); +} + +/* Mask number of address bits according to relocation. */ + +static unsigned long +nds32_elf_irel_mask (Elf_Internal_Rela *irel) +{ + reloc_howto_type *howto = NULL; + + if (irel == NULL + || (ELF32_R_TYPE (irel->r_info) >= (int) ARRAY_SIZE (nds32_elf_howto_table) + && (ELF32_R_TYPE (irel->r_info) - R_NDS32_RELAX_ENTRY) + >= (int) ARRAY_SIZE (nds32_elf_relax_howto_table))) + return 0; + + howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info)); + return howto->dst_mask; +} + +static void +nds32_elf_insert_irel_entry (struct elf_nds32_irel_entry **irel_list, + struct elf_nds32_irel_entry *irel_ptr) +{ + if (*irel_list == NULL) + { + *irel_list = irel_ptr; + irel_ptr->next = NULL; + } + else + { + irel_ptr->next = *irel_list; + *irel_list = irel_ptr; + } +} + +static void +nds32_elf_ex9_insert_fix (asection * sec, Elf_Internal_Rela * irel, + struct elf_link_hash_entry *h, int order) +{ + struct elf_nds32_ex9_refix *ptr; + + ptr = bfd_malloc (sizeof (struct elf_nds32_ex9_refix)); + ptr->sec = sec; + ptr->irel = irel; + ptr->h = h; + ptr->order = order; + ptr->next = NULL; + + if (ex9_refix_head == NULL) + ex9_refix_head = ptr; + else + { + struct elf_nds32_ex9_refix *temp = ex9_refix_head; + + while (temp->next != NULL) + temp = temp->next; + temp->next = ptr; + } +} + +enum +{ + DATA_EXIST = 1, + CLEAN_PRE = 1 << 1, + PUSH_PRE = 1 << 2 +}; + +/* Check relocation type if supporting for ex9. */ + +static int +nds32_elf_ex9_relocation_check (struct bfd_link_info *info, + Elf_Internal_Rela **irel, + Elf_Internal_Rela *irelend, + nds32_elf_blank_t *relax_blank_list, + asection *sec,bfd_vma *off, + bfd_byte *contents) +{ + /* Suppress ex9 if `.no_relax ex9' or inner loop. */ + bfd_boolean nested_ex9, nested_loop; + bfd_boolean ex9_loop_aware; + /* We use the highest 1 byte of result to record + how many bytes location counter has to move. */ + int result = 0; + Elf_Internal_Rela *irel_save = NULL; + struct elf_nds32_link_hash_table *table; + + table = nds32_elf_hash_table (info); + ex9_loop_aware = table->ex9_loop_aware; + + while ((*irel) != NULL && (*irel) < irelend && *off == (*irel)->r_offset) + { + switch (ELF32_R_TYPE ((*irel)->r_info)) + { + case R_NDS32_RELAX_REGION_BEGIN: + /* Ignore code block. */ + nested_ex9 = FALSE; + nested_loop = FALSE; + if (((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG) + || (ex9_loop_aware + && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG))) + { + /* Check the region if loop or not. If it is true and + ex9-loop-aware is true, ignore the region till region end. */ + /* To save the status for in .no_relax ex9 region and + loop region to conform the block can do ex9 relaxation. */ + nested_ex9 = ((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG); + nested_loop = (ex9_loop_aware + && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG)); + while ((*irel) && (*irel) < irelend && (nested_ex9 || nested_loop)) + { + (*irel)++; + if (ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_RELAX_REGION_BEGIN) + { + /* There may be nested region. */ + if (((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG) != 0) + nested_ex9 = TRUE; + else if (ex9_loop_aware + && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG)) + nested_loop = TRUE; + } + else if (ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_RELAX_REGION_END) + { + /* The end of region. */ + if (((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG) != 0) + nested_ex9 = FALSE; + else if (ex9_loop_aware + && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG)) + nested_loop = FALSE; + } + else if (ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_LABEL + && ((*irel)->r_addend & 0x1f) == 2) + { + /* Alignment exist in the region. */ + result |= CLEAN_PRE; + if (((*irel)->r_offset - + get_nds32_elf_blank_total (&relax_blank_list, + (*irel)->r_offset, 0)) & 0x02) + result |= PUSH_PRE; + } + } + if ((*irel) >= irelend) + *off = sec->size; + else + *off = (*irel)->r_offset; + + /* The final instruction in the region, regard this one as data to ignore it. */ + result |= DATA_EXIST; + return result; + } + break; + + case R_NDS32_LABEL: + if (((*irel)->r_addend & 0x1f) == 2) + { + /* Check this point is align and decide to do ex9 or not. */ + result |= CLEAN_PRE; + if (((*irel)->r_offset - + get_nds32_elf_blank_total (&relax_blank_list, + (*irel)->r_offset, 0)) & 0x02) + result |= PUSH_PRE; + } + break; + case R_NDS32_32_RELA: + /* Data. */ + result |= (4 << 24); + result |= DATA_EXIST; + break; + case R_NDS32_16_RELA: + /* Data. */ + result |= (2 << 24); + result |= DATA_EXIST; + break; + case R_NDS32_DATA: + /* Data. */ + /* The least code alignment is 2. If the data is only one byte, + we have to shift one more byte. */ + if ((*irel)->r_addend == 1) + result |= ((*irel)->r_addend << 25) ; + else + result |= ((*irel)->r_addend << 24) ; + + result |= DATA_EXIST; + break; + + case R_NDS32_25_PCREL_RELA: + case R_NDS32_SDA16S3_RELA: + case R_NDS32_SDA15S3_RELA: + case R_NDS32_SDA15S3: + case R_NDS32_SDA17S2_RELA: + case R_NDS32_SDA15S2_RELA: + case R_NDS32_SDA12S2_SP_RELA: + case R_NDS32_SDA12S2_DP_RELA: + case R_NDS32_SDA15S2: + case R_NDS32_SDA18S1_RELA: + case R_NDS32_SDA15S1_RELA: + case R_NDS32_SDA15S1: + case R_NDS32_SDA19S0_RELA: + case R_NDS32_SDA15S0_RELA: + case R_NDS32_SDA15S0: + case R_NDS32_HI20_RELA: + case R_NDS32_LO12S0_ORI_RELA: + case R_NDS32_LO12S0_RELA: + case R_NDS32_LO12S1_RELA: + case R_NDS32_LO12S2_RELA: + /* These relocation is supported ex9 relaxation currently. */ + /* We have to save the relocation for using later, since we have + to check there is any alignment in the same address. */ + irel_save = *irel; + break; + default: + /* Not support relocations. */ + if (ELF32_R_TYPE ((*irel)->r_info) < ARRAY_SIZE (nds32_elf_howto_table) + && ELF32_R_TYPE ((*irel)->r_info) != R_NDS32_NONE + && ELF32_R_TYPE ((*irel)->r_info) != R_NDS32_INSN16) + { + /* Note: To optimize aggressively, it maybe can ignore R_NDS32_INSN16 here. + But we have to consider if there is any side-effect. */ + if (!(result & DATA_EXIST)) + { + /* We have to confirm there is no data relocation in the + same address. In general case, this won't happen. */ + /* We have to do ex9 conservative, for those relocation not + considerd we ignore instruction. */ + result |= DATA_EXIST; + if (*(contents + *off) & 0x80) + result |= (2 << 24); + else + result |= (4 << 24); + break; + } + } + } + if ((*irel) < irelend + && ((*irel) + 1) < irelend + && (*irel)->r_offset == ((*irel) + 1)->r_offset) + /* There are relocations pointing to the same address, we have to + check all of them. */ + (*irel)++; + else + { + if (irel_save) + *irel = irel_save; + return result; + } + } + return result; +} + +/* Replace with ex9 instruction. */ + +static bfd_boolean +nds32_elf_ex9_push_insn (uint16_t insn16, bfd_byte *contents, bfd_vma pre_off, + nds32_elf_blank_t **relax_blank_list, + struct elf_nds32_irel_entry *pre_irel_ptr, + struct elf_nds32_irel_entry **irel_list) +{ + if (insn16 != 0) + { + /* Implement the ex9 relaxation. */ + bfd_putb16 (insn16, contents + pre_off); + if (!insert_nds32_elf_blank_recalc_total (relax_blank_list, + pre_off + 2, 2)) + return FALSE; + if (pre_irel_ptr != NULL) + nds32_elf_insert_irel_entry (irel_list, pre_irel_ptr); + } + return TRUE; +} + +/* Replace input file instruction which is in ex9 itable. */ + +static bfd_boolean +nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asection *sec) +{ + struct elf_nds32_insn_times_entry *ex9_insn = ex9_insn_head; + bfd_byte *contents = NULL; + bfd_vma off; + uint16_t insn16, insn_ex9; + /* `pre_*' are used to track previous instruction that can use ex9.it. */ + bfd_vma pre_off = -1; + uint16_t pre_insn16 = 0; + struct elf_nds32_irel_entry *pre_irel_ptr = NULL; + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irel; + Elf_Internal_Rela *irelend; + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Sym *isym = NULL; + nds32_elf_blank_t *relax_blank_list = NULL; + uint32_t insn = 0; + uint32_t insn_with_reg = 0; + uint32_t it_insn; + uint32_t it_insn_with_reg; + unsigned long r_symndx; + asection *isec; + struct elf_nds32_irel_entry *irel_list = NULL; + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd); + int data_flag, do_replace, save_irel; + struct elf_link_hash_entry_list *h_list; + + + /* Load section instructions, relocations, and symbol table. */ + if (!nds32_get_section_contents (abfd, sec, &contents, TRUE) + || !nds32_get_local_syms (abfd, sec, &isym)) + return FALSE; + internal_relocs = + _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, TRUE /* keep_memory */); + irelend = internal_relocs + sec->reloc_count; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + off = 0; + + /* Check if the object enable ex9. */ + irel = find_relocs_at_address (internal_relocs, internal_relocs, + irelend, R_NDS32_RELAX_ENTRY); + + /* Check this section trigger ex9 relaxation. */ + if (irel == NULL + || irel >= irelend + || ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY + || (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY + && !(irel->r_addend & R_NDS32_RELAX_ENTRY_EX9_FLAG))) + return TRUE; + + irel = internal_relocs; + + /* Check alignment and fetch proper relocation. */ + while (off < sec->size) + { + struct elf_link_hash_entry *h = NULL; + struct elf_nds32_irel_entry *irel_ptr = NULL; + + /* Syn the instruction and the relocation. */ + while (irel != NULL && irel < irelend && irel->r_offset < off) + irel++; + + data_flag = nds32_elf_ex9_relocation_check (info, &irel, irelend, + relax_blank_list, sec, + &off, contents); + if (data_flag & PUSH_PRE) + if (!nds32_elf_ex9_push_insn (pre_insn16, contents, pre_off, + &relax_blank_list, pre_irel_ptr, + &irel_list)) + return FALSE; + + if (data_flag & CLEAN_PRE) + { + pre_off = 0; + pre_insn16 = 0; + pre_irel_ptr = NULL; + } + if (data_flag & DATA_EXIST) + { + /* We save the move offset in the highest byte. */ + off += (data_flag >> 24); + continue; + } + + if (*(contents + off) & 0x80) + { + /* 2-byte instruction. */ + off += 2; + continue; + } + + /* Load the instruction and its opcode with register for comparing. */ + ex9_insn = ex9_insn_head; + insn = bfd_getb32 (contents + off); + insn_with_reg = 0; + while (ex9_insn) + { + it_insn = strtol (ex9_insn->string, NULL, 16); + it_insn_with_reg = 0; + do_replace = 0; + save_irel = 0; + + if (irel != NULL && irel < irelend && irel->r_offset == off) + { + /* Insn with relocation. */ + nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg); + + if (ex9_insn->irel != NULL) + nds32_elf_get_insn_with_reg (ex9_insn->irel, it_insn, + &it_insn_with_reg); + + if (ex9_insn->irel != NULL + && (ELF32_R_TYPE (irel->r_info) == + ELF32_R_TYPE (ex9_insn->irel->r_info)) + && (insn_with_reg == it_insn_with_reg)) + { + /* Insn relocation and format is the same as table entry. */ + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_ORI_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S1_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_RELA + || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3 + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0) + || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3_RELA + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0_RELA) + || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA12S2_DP_RELA + && ELF32_R_TYPE (irel->r_info) <= + R_NDS32_SDA12S2_SP_RELA) + || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA16S3_RELA + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA19S0_RELA)) + { + r_symndx = ELF32_R_SYM (irel->r_info); + if (r_symndx < symtab_hdr->sh_info) + { + /* Local symbol. */ + int shndx = isym[r_symndx].st_shndx; + + isec = elf_elfsections (abfd)[shndx]->bfd_section; + if (ex9_insn->sec == isec + && ex9_insn->irel->r_addend == irel->r_addend + && ex9_insn->irel->r_info == irel->r_info) + { + do_replace = 1; + save_irel = 1; + } + } + else + { + /* External symbol. */ + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + if (ex9_insn->m_list) + { + h_list = ex9_insn->m_list->h_list; + while (h_list) + { + if (h == h_list->h + && (ex9_insn->m_list->irel->r_addend == + irel->r_addend)) + { + do_replace = 1; + save_irel = 1; + break; + } + h_list = h_list->next; + } + } + } + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_HI20_RELA) + { + r_symndx = ELF32_R_SYM (irel->r_info); + if (r_symndx < symtab_hdr->sh_info) + { + /* Local symbols. Compare its base symbol and offset. */ + int shndx = isym[r_symndx].st_shndx; + + isec = elf_elfsections (abfd)[shndx]->bfd_section; + if (ex9_insn->sec == isec + && ex9_insn->irel->r_addend == irel->r_addend + && ex9_insn->irel->r_info == irel->r_info) + { + do_replace = 1; + save_irel = 1; + } + } + else + { + /* External symbol. */ + struct elf_link_hash_entry_mul_list *m_list; + + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + m_list = ex9_insn->m_list; + + while (m_list) + { + h_list = m_list->h_list; + + while (h_list) + { + if (h == h_list->h + && (m_list->irel->r_addend + == irel->r_addend)) + { + do_replace = 1; + save_irel = 1; + if (ex9_insn->next + && ex9_insn->m_list + && ex9_insn->m_list == ex9_insn->next->m_list) + { + /* sethi multiple entry must be fixed */ + nds32_elf_ex9_insert_fix (sec, irel, + h, ex9_insn->order); + } + break; + } + h_list = h_list->next; + } + m_list = m_list->next; + } + } + } + } + + /* Import table: Check the symbol hash table and the + jump target. Only R_NDS32_25_PCREL_RELA now. */ + else if (ex9_insn->times == -1 + && ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA) + { + nds32_elf_get_insn_with_reg (irel, it_insn, &it_insn_with_reg); + if (insn_with_reg == it_insn_with_reg) + { + char code[10]; + bfd_vma relocation; + + r_symndx = ELF32_R_SYM (irel->r_info); + if (r_symndx >= symtab_hdr->sh_info) + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + if ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && h->root.u.def.section != NULL + && h->root.u.def.section->output_section != NULL + && h->root.u.def.section->gc_mark == 1 + && bfd_is_abs_section (h->root.u.def.section) + && h->root.u.def.value > sec->size) + { + relocation = h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset; + relocation += irel->r_addend; + insn = insn_with_reg + | ((relocation >> 1) & 0xffffff); + snprintf (code, sizeof (code), "%08x", insn); + if (strcmp (code, ex9_insn->string) == 0) + { + do_replace = 1; + save_irel = 1; + } + } + } + } + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN + || ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END + || ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE) + { + /* These relocations do not have to relocate contens, so it can + be regard as instruction without relocation. */ + if (insn == it_insn && ex9_insn->irel == NULL) + do_replace = 1; + } + } + else + { + /* Instruction without relocation, we only + have to compare their byte code. */ + if (insn == it_insn && ex9_insn->irel == NULL) + do_replace = 1; + } + + /* Insntruction match so replacing the code here. */ + if (do_replace == 1) + { + /* There are two formats of ex9 instruction. */ + if (ex9_insn->order < 32) + insn_ex9 = INSN_EX9_IT_2; + else + insn_ex9 = INSN_EX9_IT_1; + insn16 = insn_ex9 | ex9_insn->order; + + /* Insert ex9 instruction. */ + nds32_elf_ex9_push_insn (pre_insn16, contents, pre_off, + &relax_blank_list, pre_irel_ptr, + &irel_list); + pre_off = off; + pre_insn16 = insn16; + + if (save_irel) + { + /* For instuction with relocation do relax. */ + irel_ptr = (struct elf_nds32_irel_entry *) + bfd_malloc (sizeof (struct elf_nds32_irel_entry)); + irel_ptr->irel = irel; + irel_ptr->next = NULL; + pre_irel_ptr = irel_ptr; + } + else + pre_irel_ptr = NULL; + break; + } + ex9_insn = ex9_insn->next; + } + off += 4; + } + + /* Insert ex9 instruction. */ + nds32_elf_ex9_push_insn (pre_insn16, contents, pre_off, + &relax_blank_list, pre_irel_ptr, + &irel_list); + + /* Delete the redundant code. */ + if (relax_blank_list) + { + nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list); + relax_blank_list = NULL; + } + + /* Clear the relocation that is replaced by ex9. */ + while (irel_list) + { + struct elf_nds32_irel_entry *irel_ptr; + + irel_ptr = irel_list; + irel_list = irel_ptr->next; + irel_ptr->irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), R_NDS32_TRAN); + free (irel_ptr); + } + return TRUE; +} + +/* Initialize ex9 hash table. */ + +int +nds32_elf_ex9_init (void) +{ + if (!bfd_hash_table_init_n (&ex9_code_table, nds32_elf_code_hash_newfunc, + sizeof (struct elf_nds32_code_hash_entry), + 1023)) + { + (*_bfd_error_handler) (_("Linker: cannot init ex9 hash table error \n")); + return FALSE; + } + return TRUE; +} + +/* Predict how many bytes will be relaxed with ex9 and ifc. */ + +static void +nds32_elf_ex9_total_relax (struct bfd_link_info *info) +{ + struct elf_nds32_insn_times_entry *ex9_insn; + struct elf_nds32_insn_times_entry *temp; + int target_optimize; + struct elf_nds32_link_hash_table *table; + + if (ex9_insn_head == NULL) + return; + + table = nds32_elf_hash_table (info); + target_optimize = table->target_optimize; + ex9_insn = ex9_insn_head; + while (ex9_insn) + { + ex9_relax_size = ex9_insn->times * 2 + ex9_relax_size; + temp = ex9_insn; + ex9_insn = ex9_insn->next; + free (temp); + } + ex9_insn_head = NULL; + + if ((target_optimize & NDS32_RELAX_JUMP_IFC_ON)) + { + /* Examine ifc reduce size. */ + struct elf_nds32_ifc_symbol_entry *ifc_ent = ifc_symbol_head; + struct elf_nds32_ifc_irel_list *irel_ptr = NULL; + int size = 0; + + while (ifc_ent) + { + if (ifc_ent->enable == 0) + { + /* Not ifc yet. */ + irel_ptr = ifc_ent->irel_head; + while (irel_ptr) + { + size += 2; + irel_ptr = irel_ptr->next; + } + } + size -= 2; + ifc_ent = ifc_ent->next; + } + ex9_relax_size += size; + } +} + +/* Finish ex9 table. */ + +void +nds32_elf_ex9_finish (struct bfd_link_info *link_info) +{ + nds32_elf_code_hash_traverse (nds32_elf_examine_insn_times); + nds32_elf_order_insn_times (link_info); + nds32_elf_ex9_total_relax (link_info); + /* Traverse the hash table and count its times. */ + nds32_elf_code_hash_traverse (nds32_elf_count_insn_times); + nds32_elf_order_insn_times (link_info); + nds32_elf_ex9_build_itable (link_info); +} + +/* Relocate the entries in ex9 table. */ + +static bfd_vma +nds32_elf_ex9_reloc_insn (struct elf_nds32_insn_times_entry *ptr, + struct bfd_link_info *link_info) +{ + Elf_Internal_Sym *isym = NULL; + bfd_vma relocation = -1; + struct elf_link_hash_entry *h; + + if (ptr->m_list != NULL) + { + /* Global symbol. */ + h = ptr->m_list->h_list->h; + if ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && h->root.u.def.section != NULL + && h->root.u.def.section->output_section != NULL) + { + + relocation = h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset; + relocation += ptr->m_list->irel->r_addend; + } + else + relocation = 0; + } + else if (ptr->sec !=NULL) + { + /* Local symbol. */ + Elf_Internal_Sym sym; + asection *sec = NULL; + asection isec; + asection *isec_ptr = &isec; + Elf_Internal_Rela irel_backup = *(ptr->irel); + asection *sec_backup = ptr->sec; + bfd *abfd = ptr->sec->owner; + + if (!nds32_get_local_syms (abfd, sec, &isym)) + return FALSE; + isym = isym + ELF32_R_SYM (ptr->irel->r_info); + + sec = bfd_section_from_elf_index (abfd, isym->st_shndx); + if (sec != NULL) + *isec_ptr = *sec; + sym = *isym; + + /* The purpose is same as elf_link_input_bfd. */ + if (isec_ptr != NULL + && isec_ptr->sec_info_type == SEC_INFO_TYPE_MERGE + && ELF_ST_TYPE (isym->st_info) != STT_SECTION) + { + sym.st_value = + _bfd_merged_section_offset (ptr->sec->output_section->owner, &isec_ptr, + elf_section_data (isec_ptr)->sec_info, + isym->st_value); + } + relocation = _bfd_elf_rela_local_sym (link_info->output_bfd, &sym, + &ptr->sec, ptr->irel); + if (ptr->irel != NULL) + relocation += ptr->irel->r_addend; + + /* Restore origin value since there may be some insntructions that + could not be replaced with ex9.it. */ + *(ptr->irel) = irel_backup; + ptr->sec = sec_backup; + } + + return relocation; +} + +/* Import ex9 table and build list. */ + +void +nds32_elf_ex9_import_table (struct bfd_link_info *info) +{ + int num = 0; + bfd_byte *contents; + unsigned long insn; + FILE *ex9_import_file; + int update_ex9_table; + struct elf_nds32_link_hash_table *table; + + table = nds32_elf_hash_table (info); + ex9_import_file = table->ex9_import_file; + rewind (table->ex9_import_file); + + contents = bfd_malloc (sizeof (bfd_byte) * 4); + + /* Read instructions from the input file and build the list. */ + while (!feof (ex9_import_file)) + { + char *code; + struct elf_nds32_insn_times_entry *ptr; + size_t nread; + + nread = fread (contents, sizeof (bfd_byte) * 4, 1, ex9_import_file); + /* Ignore the final byte 0x0a. */ + if (nread < 1) + break; + insn = bfd_getb32 (contents); + code = bfd_malloc (sizeof (char) * 9); + snprintf (code, 9, "%08lx", insn); + ptr = bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); + ptr->string = code; + ptr->order = num; + ptr->times = -1; + ptr->sec = NULL; + ptr->m_list = NULL; + ptr->rel_backup.r_offset = 0; + ptr->rel_backup.r_info = 0; + ptr->rel_backup.r_addend = 0; + ptr->irel = NULL; + ptr->next = NULL; + nds32_elf_ex9_insert_entry (ptr); + num++; + } + + update_ex9_table = table->update_ex9_table; + if (update_ex9_table == 1) + { + /* It has to consider of sethi need to use multiple page + but it not be done yet. */ + nds32_elf_code_hash_traverse (nds32_elf_examine_insn_times); + nds32_elf_order_insn_times (info); + } +} + +/* Export ex9 table. */ + +static void +nds32_elf_ex9_export (struct bfd_link_info *info, + bfd_byte *contents, int size) +{ + FILE *ex9_export_file; + struct elf_nds32_link_hash_table *table; + + table = nds32_elf_hash_table (info); + ex9_export_file = table->ex9_export_file; + fwrite (contents, sizeof (bfd_byte), size, ex9_export_file); + fclose (ex9_export_file); +} + +/* Adjust relocations of J and JAL in ex9.itable. + Export ex9 table. */ + +static void +nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info) +{ + asection *table_sec = NULL; + struct elf_nds32_insn_times_entry *ex9_insn = ex9_insn_head; + struct elf_nds32_insn_times_entry *temp_ptr, *temp_ptr2; + bfd *it_abfd; + uint32_t insn, insn_with_reg, source_insn; + bfd_byte *contents = NULL, *source_contents = NULL; + int size = 0; + bfd_vma gp; + int shift, update_ex9_table, offset = 0; + reloc_howto_type *howto = NULL; + Elf_Internal_Rela rel_backup; + unsigned short insn_ex9; + struct elf_nds32_link_hash_table *table; + FILE *ex9_export_file; + static bfd_boolean done = FALSE; + + if (done) + return; + + done = TRUE; + + table = nds32_elf_hash_table (link_info); + if (table) + table->relax_status |= NDS32_RELAX_EX9_DONE; + + + update_ex9_table = table->update_ex9_table; + /* Generated ex9.itable exactly. */ + if (update_ex9_table == 0) + { + for (it_abfd = link_info->input_bfds; it_abfd != NULL; + it_abfd = it_abfd->link.next) + { + table_sec = bfd_get_section_by_name (it_abfd, ".ex9.itable"); + if (table_sec != NULL) + break; + } + + if (table_sec != NULL) + { + bfd *output_bfd; + + output_bfd = table_sec->output_section->owner; + nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE); + if (table_sec->size == 0) + return; + + if (!nds32_get_section_contents (it_abfd, table_sec, &contents, TRUE)) + return; + } + } + else + { + /* Set gp. */ + bfd *output_bfd; + + output_bfd = link_info->input_bfds->sections->output_section->owner; + nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE); + contents = bfd_malloc (sizeof (bfd_byte) * 2048); + } + + /* Relocate instruction. */ + while (ex9_insn) + { + bfd_vma relocation, min_relocation = 0xffffffff; + + insn = strtol (ex9_insn->string, NULL, 16); + insn_with_reg = 0; + if (ex9_insn->m_list != NULL || ex9_insn->sec != NULL) + { + if (ex9_insn->m_list) + rel_backup = ex9_insn->m_list->rel_backup; + else + rel_backup = ex9_insn->rel_backup; + + nds32_elf_get_insn_with_reg (&rel_backup, insn, &insn_with_reg); + howto = + bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE + (rel_backup.r_info)); + shift = howto->rightshift; + if (ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_25_PCREL_RELA + || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S0_ORI_RELA + || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S0_RELA + || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S1_RELA + || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S2_RELA) + { + relocation = nds32_elf_ex9_reloc_insn (ex9_insn, link_info); + insn = + insn_with_reg | ((relocation >> shift) & + nds32_elf_irel_mask (&rel_backup)); + bfd_putb32 (insn, contents + (ex9_insn->order) * 4); + } + else if ((ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA15S3 + && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA15S0) + || (ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA15S3_RELA + && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA15S0_RELA) + || (ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA12S2_DP_RELA + && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA12S2_SP_RELA) + || (ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA16S3_RELA + && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA19S0_RELA)) + { + relocation = nds32_elf_ex9_reloc_insn (ex9_insn, link_info); + insn = + insn_with_reg | (((relocation - gp) >> shift) & + nds32_elf_irel_mask (&rel_backup)); + bfd_putb32 (insn, contents + (ex9_insn->order) * 4); + } + else if (ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_HI20_RELA) + { + /* Sethi may be multiple entry for one insn. */ + if (ex9_insn->next && ex9_insn->m_list + && ex9_insn->m_list == ex9_insn->next->m_list) + { + struct elf_link_hash_entry_mul_list *m_list; + struct elf_nds32_ex9_refix *fix_ptr; + struct elf_link_hash_entry *h; + + temp_ptr = ex9_insn; + temp_ptr2 = ex9_insn; + m_list = ex9_insn->m_list; + while (m_list) + { + h = m_list->h_list->h; + relocation = h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset; + relocation += m_list->irel->r_addend; + + if (relocation < min_relocation) + min_relocation = relocation; + m_list = m_list->next; + } + relocation = min_relocation; + + /* Put insntruction into ex9 table. */ + insn = insn_with_reg + | ((relocation >> shift) & nds32_elf_irel_mask (&rel_backup)); + bfd_putb32 (insn, contents + (ex9_insn->order) * 4); + relocation = relocation + 0x1000; /* hi20 */ + + while (ex9_insn->next && ex9_insn->m_list + && ex9_insn->m_list == ex9_insn->next->m_list) + { + /* Multiple sethi. */ + ex9_insn = ex9_insn->next; + size += 4; + insn = + insn_with_reg | ((relocation >> shift) & + nds32_elf_irel_mask (&rel_backup)); + bfd_putb32 (insn, contents + (ex9_insn->order) * 4); + relocation = relocation + 0x1000; /* hi20 */ + } + + fix_ptr = ex9_refix_head; + while (fix_ptr) + { + /* Fix ex9 insn. */ + /* temp_ptr2 points to the head of multiple sethi. */ + temp_ptr = temp_ptr2; + while (fix_ptr->order != temp_ptr->order && fix_ptr->next) + { + fix_ptr = fix_ptr->next; + } + if (fix_ptr->order != temp_ptr->order) + break; + + /* Set source insn. */ + relocation = + fix_ptr->h->root.u.def.value + + fix_ptr->h->root.u.def.section->output_section->vma + + fix_ptr->h->root.u.def.section->output_offset; + relocation += fix_ptr->irel->r_addend; + /* sethi imm is imm20s. */ + source_insn = insn_with_reg | ((relocation >> shift) & 0xfffff); + + while (temp_ptr) + { + /* Match entry and source code. */ + insn = bfd_getb32 (contents + (temp_ptr->order) * 4 + offset); + if (insn == source_insn) + { + /* Fix the ex9 insn. */ + if (temp_ptr->order != fix_ptr->order) + { + if (!nds32_get_section_contents + (fix_ptr->sec->owner, fix_ptr->sec, + &source_contents, TRUE)) + (*_bfd_error_handler) + (_("Linker: error cannot fixed ex9 relocation \n")); + if (temp_ptr->order < 32) + insn_ex9 = INSN_EX9_IT_2; + else + insn_ex9 = INSN_EX9_IT_1; + insn_ex9 = insn_ex9 | temp_ptr->order; + bfd_putb16 (insn_ex9, source_contents + fix_ptr->irel->r_offset); + } + break; + } + else + { + if (!temp_ptr->next || temp_ptr->m_list != temp_ptr->next->m_list) + (*_bfd_error_handler) + (_("Linker: error cannot fixed ex9 relocation \n")); + else + temp_ptr = temp_ptr->next; + } + } + fix_ptr = fix_ptr->next; + } + } + else + { + relocation = nds32_elf_ex9_reloc_insn (ex9_insn, link_info); + insn = insn_with_reg + | ((relocation >> shift) & nds32_elf_irel_mask (&rel_backup)); + bfd_putb32 (insn, contents + (ex9_insn->order) * 4); + } + } + } + else + { + /* Insn without relocation does not have to be fixed + if need to update export table. */ + if (update_ex9_table == 1) + bfd_putb32 (insn, contents + (ex9_insn->order) * 4); + } + ex9_insn = ex9_insn->next; + size += 4; + } + + ex9_export_file = table->ex9_export_file; + if (ex9_export_file != NULL) + nds32_elf_ex9_export (link_info, contents, table_sec->size); + else if (update_ex9_table == 1) + { + table->ex9_export_file = table->ex9_import_file; + rewind (table->ex9_export_file); + nds32_elf_ex9_export (link_info, contents, size); + } +} + +/* Generate ex9 hash table. */ + +static bfd_boolean +nds32_elf_ex9_build_hash_table (bfd *abfd, asection *sec, + struct bfd_link_info *link_info) +{ + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irelend; + Elf_Internal_Rela *irel; + Elf_Internal_Rela *jrel; + Elf_Internal_Rela rel_backup; + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Sym *isym = NULL; + asection *isec; + struct elf_link_hash_entry **sym_hashes; + bfd_byte *contents = NULL; + bfd_vma off = 0; + unsigned long r_symndx; + uint32_t insn, insn_with_reg; + struct elf_link_hash_entry *h; + int data_flag, shift, align; + bfd_vma relocation; + /* Suppress ex9 if `.no_relax ex9' or inner loop. */ + reloc_howto_type *howto = NULL; + + sym_hashes = elf_sym_hashes (abfd); + /* Load section instructions, relocations, and symbol table. */ + if (!nds32_get_section_contents (abfd, sec, &contents, TRUE)) + return FALSE; + + internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, + TRUE /* keep_memory */); + irelend = internal_relocs + sec->reloc_count; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + if (!nds32_get_local_syms (abfd, sec, &isym)) + return FALSE; + + /* Check the object if enable ex9. */ + irel = find_relocs_at_address (internal_relocs, internal_relocs, irelend, + R_NDS32_RELAX_ENTRY); + + /* Check this section trigger ex9 relaxation. */ + if (irel == NULL + || irel >= irelend + || ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY + || (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY + && !(irel->r_addend & R_NDS32_RELAX_ENTRY_EX9_FLAG))) + return TRUE; + + irel = internal_relocs; + + /* Push each insn into hash table. */ + while (off < sec->size) + { + char code[10]; + struct elf_nds32_code_hash_entry *entry; + + while (irel != NULL && irel < irelend && irel->r_offset < off) + irel++; + + data_flag = nds32_elf_ex9_relocation_check (link_info, &irel, irelend, + NULL, sec, &off, contents); + if (data_flag & DATA_EXIST) + { + /* We save the move offset in the highest byte. */ + off += (data_flag >> 24); + continue; + } + + if (*(contents + off) & 0x80) + { + off += 2; + } + else + { + h = NULL; + isec = NULL; + jrel = NULL; + rel_backup.r_info = 0; + rel_backup.r_offset = 0; + rel_backup.r_addend = 0; + /* Load the instruction and its opcode with register for comparing. */ + insn = bfd_getb32 (contents + off); + insn_with_reg = 0; + if (irel != NULL && irel < irelend && irel->r_offset == off) + { + nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg); + howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info)); + shift = howto->rightshift; + align = (1 << shift) - 1; + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_HI20_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_ORI_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S1_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_RELA + ||(ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3 + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0) + || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3_RELA + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0_RELA) + || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA12S2_DP_RELA + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA12S2_SP_RELA) + || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA16S3_RELA + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA19S0_RELA)) + { + r_symndx = ELF32_R_SYM (irel->r_info); + jrel = irel; + rel_backup = *irel; + if (r_symndx < symtab_hdr->sh_info) + { + /* Local symbol. */ + int shndx = isym[r_symndx].st_shndx; + + bfd_vma st_value = (isym + r_symndx)->st_value; + isec = elf_elfsections (abfd)[shndx]->bfd_section; + relocation = (isec->output_section->vma + isec->output_offset + + st_value + irel->r_addend); + } + else + { + /* External symbol. */ + bfd_boolean warned ATTRIBUTE_UNUSED; + bfd_boolean ignored ATTRIBUTE_UNUSED; + bfd_boolean unresolved_reloc ATTRIBUTE_UNUSED; + asection *sym_sec; + + /* Maybe there is a better way to get h and relocation */ + RELOC_FOR_GLOBAL_SYMBOL (link_info, abfd, sec, irel, + r_symndx, symtab_hdr, sym_hashes, + h, sym_sec, relocation, + unresolved_reloc, warned, ignored); + relocation += irel->r_addend; + if ((h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + || strcmp (h->root.root.string, "_FP_BASE_") == 0) + { + off += 4; + continue; + } + } + + /* Check for gp relative instruction alignment. */ + if ((ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3 + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0) + || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3_RELA + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0_RELA) + || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA12S2_DP_RELA + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA12S2_SP_RELA) + || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA16S3_RELA + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA19S0_RELA)) + { + bfd_vma gp; + bfd *output_bfd = sec->output_section->owner; + bfd_reloc_status_type r; + + /* If the symbol is in the abs section, the out_bfd will be null. + This happens when the relocation has a symbol@GOTOFF. */ + r = nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE); + if (r != bfd_reloc_ok) + { + off += 4; + continue; + } + + relocation -= gp; + + /* Make sure alignment is correct. */ + if (relocation & align) + { + /* Incorrect alignment. */ + (*_bfd_error_handler) + (_("%s: warning: unaligned small data access. " + "For entry: {%d, %d, %d}, addr = 0x%x, align = 0x%x."), + bfd_get_filename (abfd), irel->r_offset, + irel->r_info, irel->r_addend, relocation, align); + off += 4; + continue; + } + } + + insn = insn_with_reg + | ((relocation >> shift) & nds32_elf_irel_mask (irel)); + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN + || ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END + || ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE) + { + /* These relocations do not have to relocate contens, so it can + be regard as instruction without relocation. */ + } + else + { + off += 4; + continue; + } + } + + snprintf (code, sizeof (code), "%08x", insn); + /* Copy "code". */ + entry = (struct elf_nds32_code_hash_entry*) + bfd_hash_lookup (&ex9_code_table, code, TRUE, TRUE); + if (entry == NULL) + { + (*_bfd_error_handler) + (_("%P%F: failed creating ex9.it %s hash table: %E\n"), code); + return FALSE; + } + if (h) + { + if (h->root.type == bfd_link_hash_undefined) + return TRUE; + /* Global symbol. */ + /* In order to do sethi with different symbol but same value. */ + if (entry->m_list == NULL) + { + struct elf_link_hash_entry_mul_list *m_list_new; + struct elf_link_hash_entry_list *h_list_new; + + m_list_new = (struct elf_link_hash_entry_mul_list *) + bfd_malloc (sizeof (struct elf_link_hash_entry_mul_list)); + h_list_new = (struct elf_link_hash_entry_list *) + bfd_malloc (sizeof (struct elf_link_hash_entry_list)); + entry->m_list = m_list_new; + m_list_new->h_list = h_list_new; + m_list_new->rel_backup = rel_backup; + m_list_new->times = 1; + m_list_new->irel = jrel; + m_list_new->next = NULL; + h_list_new->h = h; + h_list_new->next = NULL; + } + else + { + struct elf_link_hash_entry_mul_list *m_list = entry->m_list; + struct elf_link_hash_entry_list *h_list; + + while (m_list) + { + /* Build the different symbols that point to the same address. */ + h_list = m_list->h_list; + if (h_list->h->root.u.def.value == h->root.u.def.value + && h_list->h->root.u.def.section->output_section->vma + == h->root.u.def.section->output_section->vma + && h_list->h->root.u.def.section->output_offset + == h->root.u.def.section->output_offset + && m_list->rel_backup.r_addend == rel_backup.r_addend) + { + m_list->times++; + m_list->irel = jrel; + while (h_list->h != h && h_list->next) + h_list = h_list->next; + if (h_list->h != h) + { + struct elf_link_hash_entry_list *h_list_new; + + h_list_new = (struct elf_link_hash_entry_list *) + bfd_malloc (sizeof (struct elf_link_hash_entry_list)); + h_list->next = h_list_new; + h_list_new->h = h; + h_list_new->next = NULL; + } + break; + } + /* The sethi case may have different address but the + hi20 is the same. */ + else if (ELF32_R_TYPE (jrel->r_info) == R_NDS32_HI20_RELA + && m_list->next == NULL) + { + struct elf_link_hash_entry_mul_list *m_list_new; + struct elf_link_hash_entry_list *h_list_new; + + m_list_new = (struct elf_link_hash_entry_mul_list *) + bfd_malloc (sizeof (struct elf_link_hash_entry_mul_list)); + h_list_new = (struct elf_link_hash_entry_list *) + bfd_malloc (sizeof (struct elf_link_hash_entry_list)); + m_list->next = m_list_new; + m_list_new->h_list = h_list_new; + m_list_new->rel_backup = rel_backup; + m_list_new->times = 1; + m_list_new->irel = jrel; + m_list_new->next = NULL; + h_list_new->h = h; + h_list_new->next = NULL; + break; + } + m_list = m_list->next; + } + if (!m_list) + { + off += 4; + continue; + } + } + } + else + { + /* Local symbol and insn without relocation*/ + entry->times++; + entry->rel_backup = rel_backup; + } + + /* Use in sethi insn with constant and global symbol in same format. */ + if (!jrel) + entry->const_insn = 1; + else + entry->irel = jrel; + entry->sec = isec; + off += 4; + } + } + return TRUE; +} + +/* Set the _ITB_BASE, and point it to ex9 table. */ + +bfd_boolean +nds32_elf_ex9_itb_base (struct bfd_link_info *link_info) +{ + bfd *abfd; + asection *sec; + bfd *output_bfd = NULL; + struct bfd_link_hash_entry *bh = NULL; + + if (is_ITB_BASE_set == 1) + return TRUE; + + is_ITB_BASE_set = 1; + + bh = bfd_link_hash_lookup (link_info->hash, "_ITB_BASE_", FALSE, FALSE, TRUE); + + if (bh && (bh->type == bfd_link_hash_defined + || bh->type == bfd_link_hash_defweak)) + return TRUE; + + for (abfd = link_info->input_bfds; abfd != NULL; + abfd = abfd->link.next) + { + sec = bfd_get_section_by_name (abfd, ".ex9.itable"); + if (sec != NULL) + { + output_bfd = sec->output_section->owner; + break; + } + } + if (output_bfd == NULL) + { + output_bfd = link_info->output_bfd; + if (output_bfd->sections == NULL) + return TRUE; + else + sec = bfd_abs_section_ptr; + } + bh = bfd_link_hash_lookup (link_info->hash, "_ITB_BASE_", + FALSE, FALSE, TRUE); + return (_bfd_generic_link_add_one_symbol + (link_info, output_bfd, "_ITB_BASE_", + BSF_GLOBAL | BSF_WEAK, sec, 0, + (const char *) NULL, FALSE, get_elf_backend_data + (output_bfd)->collect, &bh)); +} /* End EX9.IT */ + + +#define ELF_ARCH bfd_arch_nds32 +#define ELF_MACHINE_CODE EM_NDS32 +#define ELF_MAXPAGESIZE 0x1000 +#define ELF_TARGET_ID NDS32_ELF_DATA + +#define TARGET_BIG_SYM nds32_elf32_be_vec +#define TARGET_BIG_NAME "elf32-nds32be" +#define TARGET_LITTLE_SYM nds32_elf32_le_vec +#define TARGET_LITTLE_NAME "elf32-nds32le" + +#define elf_info_to_howto nds32_info_to_howto +#define elf_info_to_howto_rel nds32_info_to_howto_rel + +#define bfd_elf32_bfd_link_hash_table_create nds32_elf_link_hash_table_create +#define bfd_elf32_bfd_merge_private_bfd_data nds32_elf_merge_private_bfd_data +#define bfd_elf32_bfd_print_private_bfd_data nds32_elf_print_private_bfd_data +#define bfd_elf32_bfd_relax_section nds32_elf_relax_section +#define bfd_elf32_bfd_set_private_flags nds32_elf_set_private_flags + +#define bfd_elf32_mkobject nds32_elf_mkobject +#define elf_backend_action_discarded nds32_elf_action_discarded +#define elf_backend_add_symbol_hook nds32_elf_add_symbol_hook +#define elf_backend_check_relocs nds32_elf_check_relocs +#define elf_backend_adjust_dynamic_symbol nds32_elf_adjust_dynamic_symbol +#define elf_backend_create_dynamic_sections nds32_elf_create_dynamic_sections +#define elf_backend_finish_dynamic_sections nds32_elf_finish_dynamic_sections +#define elf_backend_finish_dynamic_symbol nds32_elf_finish_dynamic_symbol +#define elf_backend_size_dynamic_sections nds32_elf_size_dynamic_sections +#define elf_backend_relocate_section nds32_elf_relocate_section +#define elf_backend_gc_mark_hook nds32_elf_gc_mark_hook +#define elf_backend_gc_sweep_hook nds32_elf_gc_sweep_hook +#define elf_backend_grok_prstatus nds32_elf_grok_prstatus +#define elf_backend_grok_psinfo nds32_elf_grok_psinfo +#define elf_backend_reloc_type_class nds32_elf_reloc_type_class +#define elf_backend_copy_indirect_symbol nds32_elf_copy_indirect_symbol +#define elf_backend_link_output_symbol_hook nds32_elf_output_symbol_hook +#define elf_backend_output_arch_syms nds32_elf_output_arch_syms +#define elf_backend_object_p nds32_elf_object_p +#define elf_backend_final_write_processing nds32_elf_final_write_processing +#define elf_backend_special_sections nds32_elf_special_sections +#define bfd_elf32_bfd_get_relocated_section_contents \ + nds32_elf_get_relocated_section_contents + +#define elf_backend_can_gc_sections 1 +#define elf_backend_can_refcount 1 +#define elf_backend_want_got_plt 1 +#define elf_backend_plt_readonly 1 +#define elf_backend_want_plt_sym 0 +#define elf_backend_got_header_size 12 +#define elf_backend_may_use_rel_p 1 +#define elf_backend_default_use_rela_p 1 +#define elf_backend_may_use_rela_p 1 + +#include "elf32-target.h" + +#undef ELF_MAXPAGESIZE +#define ELF_MAXPAGESIZE 0x2000 + +#undef TARGET_BIG_SYM +#define TARGET_BIG_SYM nds32_elf32_linux_be_vec +#undef TARGET_BIG_NAME +#define TARGET_BIG_NAME "elf32-nds32be-linux" +#undef TARGET_LITTLE_SYM +#define TARGET_LITTLE_SYM nds32_elf32_linux_le_vec +#undef TARGET_LITTLE_NAME +#define TARGET_LITTLE_NAME "elf32-nds32le-linux" +#undef elf32_bed +#define elf32_bed elf32_nds32_lin_bed + +#include "elf32-target.h" diff --git a/contrib/gdb-7/bfd/elf32-nds32.h b/contrib/gdb-7/bfd/elf32-nds32.h new file mode 100644 index 0000000000..210a4d31e3 --- /dev/null +++ b/contrib/gdb-7/bfd/elf32-nds32.h @@ -0,0 +1,155 @@ +/* NDS32-specific support for 32-bit ELF. + Copyright (C) 2012-2015 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 ELF32_NDS32_H +#define ELF32_NDS32_H + +/* Relocation flags encoded in r_addend. */ + +/* Relocation flags for R_NDS32_ERLAX_ENTRY. */ + +/* Set if relax on this section is done or disabled. */ +#define R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG (1 << 31) +/* Optimize for performance. */ +#define R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG (1 << 30) +/* Optimize for size. Branch destination 4-byte adjustment + may be disabled. */ +#define R_NDS32_RELAX_ENTRY_OPTIMIZE_FOR_SPACE_FLAG (1 << 29) +/* To distinguish the assembly code generated by compiler + or written manually. */ +#define R_NDS32_RELAX_ENTRY_VERBATIM_FLAG (1 << 28) +/* EX9 and link-time IFC must be explicitly enabled, so we + won't mess up handcraft assembly code. */ +/* Enable EX9 optimization for this section. */ +#define R_NDS32_RELAX_ENTRY_EX9_FLAG (1 << 2) +/* Enable IFC optimization for this section. */ +#define R_NDS32_RELAX_ENTRY_IFC_FLAG (1 << 3) + + +/* Relocation flags for R_NDS32_INSN16. */ + +/* Tag the nop16 can be removed. */ +#define R_NDS32_INSN16_CONVERT_FLAG (1 << 0) +/* Convert a gp-relative access (e.g., lwi.gp) + to fp-as-gp access (lwi37.fp). + This value is used by linker internally only. + It's fine to change the vlaue. */ +#define R_NDS32_INSN16_FP7U2_FLAG (1 << 1) + +/* Relocation flags for R_NDS32_RELAX_REGION_OMIT_FP_START/END. */ + +/* OMIT_FP_FLAG marks the region for applying fp-as-gp + optimization. */ +#define R_NDS32_RELAX_REGION_OMIT_FP_FLAG (1 << 0) +/* NOT_OMIT_FP_FLAG is set if this region is not worth + for fp-as-gp. */ +#define R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG (1 << 1) +/* Suppress EX9 optimization in the region. */ +#define R_NDS32_RELAX_REGION_NO_EX9_FLAG (1 << 2) +/* A Innermost loop region. Some optimizations is suppressed + in this region due to performance drop. */ +#define R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG (1 << 4) + +/* Tag range for LOADSTORE relocation. */ +enum +{ + NDS32_LOADSTORE_NONE = 0x0, + NDS32_LOADSTORE_BYTE = 0x1, + NDS32_LOADSTORE_HALF = 0x2, + NDS32_LOADSTORE_WORD = 0x4, + NDS32_LOADSTORE_FLOAT_S = 0x8, + NDS32_LOADSTORE_FLOAT_D = 0x10, + NDS32_LOADSTORE_IMM = 0x20 +}; + +/* Relax tag for nds32_elf_relax_section, we have to specify which + optimization do in this round. */ +enum +{ + NDS32_RELAX_NONE_ROUND = 0, + NDS32_RELAX_NORMAL_ROUND, + NDS32_RELAX_JUMP_IFC_ROUND, + NDS32_RELAX_EX9_BUILD_ROUND, + NDS32_RELAX_EX9_REPLACE_ROUND, + NDS32_RELAX_EMPTY_ROUND +}; + +/* Optimization status mask. */ +#define NDS32_RELAX_JUMP_IFC_DONE (1 << 0) +#define NDS32_RELAX_EX9_DONE (1 << 1) + +/* Optimization turn on mask. */ +#define NDS32_RELAX_JUMP_IFC_ON (1 << 0) +#define NDS32_RELAX_EX9_ON (1 << 1) + +extern void nds32_insertion_sort + (void *, size_t, size_t, int (*) (const void *, const void *)); + +extern int nds32_elf_ex9_init (void); +extern int nds32_convert_32_to_16 (bfd *, uint32_t, uint16_t *, int *); +extern int nds32_convert_16_to_32 (bfd *, uint16_t, uint32_t *); +extern void bfd_elf32_nds32_set_target_option (struct bfd_link_info *, + int, int, FILE *, int, + int, int, int, FILE *, + FILE *, int, int, + bfd_boolean, bfd_boolean); + +#define nds32_elf_hash_table(info) \ + (elf_hash_table_id ((struct elf_link_hash_table *) ((info)->hash)) \ + == NDS32_ELF_DATA ? \ + ((struct elf_nds32_link_hash_table *) ((info)->hash)) : NULL) + +/* Hash table structure for target nds32. There are some members to + save target options passed from nds32elf.em to bfd. */ + +struct elf_nds32_link_hash_table +{ + struct elf_link_hash_table root; + + /* Short-cuts to get to dynamic linker sections. */ + asection *sgot; + asection *sgotplt; + asection *srelgot; + asection *splt; + asection *srelplt; + asection *sdynbss; + asection *srelbss; + + /* Small local sym to section mapping cache. */ + struct sym_cache sym_cache; + + /* Target dependent options. */ + int relax_fp_as_gp; /* --mrelax-omit-fp */ + int eliminate_gc_relocs; /* --meliminate-gc-relocs */ + FILE *sym_ld_script; /* --mgen-symbol-ld-script= */ + /* Disable if linking a dynamically linked executable. */ + int load_store_relax; + int target_optimize; /* Switch optimization. */ + int relax_status; /* Finished optimization. */ + int relax_round; /* Going optimization. */ + FILE *ex9_export_file; /* --mexport-ex9= */ + FILE *ex9_import_file; /* --mimport-ex9= */ + int update_ex9_table; /* --mupdate-ex9. */ + int ex9_limit; + bfd_boolean ex9_loop_aware; /* Ignore ex9 if inside a loop. */ + bfd_boolean ifc_loop_aware; /* Ignore ifc if inside a loop. */ +}; +#endif diff --git a/contrib/gdb-7/include/mach-o/reloc.h b/contrib/gdb-7/bfd/elf32-nios2.h similarity index 57% copy from contrib/gdb-7/include/mach-o/reloc.h copy to contrib/gdb-7/bfd/elf32-nios2.h index bab31efeb9..d3e7a7d404 100644 --- a/contrib/gdb-7/include/mach-o/reloc.h +++ b/contrib/gdb-7/bfd/elf32-nios2.h @@ -1,6 +1,6 @@ -/* Mach-O support for BFD. - Copyright 2011, 2012 - Free Software Foundation, Inc. +/* Nios II support for 32-bit ELF + Copyright (C) 2013-2015 Free Software Foundation, Inc. + Contributed by Mentor Graphics This file is part of BFD, the Binary File Descriptor library. @@ -19,15 +19,20 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef _MACH_O_RELOC_H -#define _MACH_O_RELOC_H +#ifndef _ELF32_NIOS2_H +#define _ELF32_NIOS2_H -/* Generic relocation types (used by i386). */ -#define BFD_MACH_O_GENERIC_RELOC_VANILLA 0 -#define BFD_MACH_O_GENERIC_RELOC_PAIR 1 -#define BFD_MACH_O_GENERIC_RELOC_SECTDIFF 2 -#define BFD_MACH_O_GENERIC_RELOC_PB_LA_PTR 3 -#define BFD_MACH_O_GENERIC_RELOC_LOCAL_SECTDIFF 4 -#define BFD_MACH_O_GENERIC_RELOC_TLV 5 +extern int nios2_elf32_setup_section_lists + (bfd *, struct bfd_link_info *); -#endif /* _MACH_O_RELOC_H */ +extern void nios2_elf32_next_input_section + (struct bfd_link_info *, asection *); + +extern bfd_boolean nios2_elf32_size_stubs + (bfd *, bfd *, struct bfd_link_info *, + asection * (*) (const char *, asection *, bfd_boolean), void (*) (void)); + +extern bfd_boolean nios2_elf32_build_stubs + (struct bfd_link_info *); + +#endif /* _ELF32_NIOS2_H */ diff --git a/contrib/gdb-7/bfd/elf32-or1k.c b/contrib/gdb-7/bfd/elf32-or1k.c new file mode 100644 index 0000000000..efcefea454 --- /dev/null +++ b/contrib/gdb-7/bfd/elf32-or1k.c @@ -0,0 +1,2857 @@ +/* Or1k-specific support for 32-bit ELF. + Copyright (C) 2001-2015 Free Software Foundation, Inc. + Contributed for OR32 by Johan Rydberg, jrydberg@opencores.org + + PIC parts added by Stefan Kristiansson, stefan.kristiansson@saunalahti.fi, + largely based on elf32-m32r.c and elf32-microblaze.c. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/or1k.h" +#include "libiberty.h" + +#define PLT_ENTRY_SIZE 20 + +#define PLT0_ENTRY_WORD0 0x19800000 /* l.movhi r12, 0 <- hi(.got+4) */ +#define PLT0_ENTRY_WORD1 0xa98c0000 /* l.ori r12, r12, 0 <- lo(.got+4) */ +#define PLT0_ENTRY_WORD2 0x85ec0004 /* l.lwz r15, 4(r12) <- *(.got+8)*/ +#define PLT0_ENTRY_WORD3 0x44007800 /* l.jr r15 */ +#define PLT0_ENTRY_WORD4 0x858c0000 /* l.lwz r12, 0(r12) */ + +#define PLT0_PIC_ENTRY_WORD0 0x85900004 /* l.lwz r12, 4(r16) */ +#define PLT0_PIC_ENTRY_WORD1 0x85f00008 /* l.lwz r15, 8(r16) */ +#define PLT0_PIC_ENTRY_WORD2 0x44007800 /* l.jr r15 */ +#define PLT0_PIC_ENTRY_WORD3 0x15000000 /* l.nop */ +#define PLT0_PIC_ENTRY_WORD4 0x15000000 /* l.nop */ + +#define PLT_ENTRY_WORD0 0x19800000 /* l.movhi r12, 0 <- hi(got idx addr) */ +#define PLT_ENTRY_WORD1 0xa98c0000 /* l.ori r12, r12, 0 <- lo(got idx addr) */ +#define PLT_ENTRY_WORD2 0x858c0000 /* l.lwz r12, 0(r12) */ +#define PLT_ENTRY_WORD3 0x44006000 /* l.jr r12 */ +#define PLT_ENTRY_WORD4 0xa9600000 /* l.ori r11, r0, 0 <- reloc offset */ + +#define PLT_PIC_ENTRY_WORD0 0x85900000 /* l.lwz r12, 0(r16) <- index in got */ +#define PLT_PIC_ENTRY_WORD1 0xa9600000 /* l.ori r11, r0, 0 <- reloc offset */ +#define PLT_PIC_ENTRY_WORD2 0x44006000 /* l.jr r12 */ +#define PLT_PIC_ENTRY_WORD3 0x15000000 /* l.nop */ +#define PLT_PIC_ENTRY_WORD4 0x15000000 /* l.nop */ + +#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" + +static reloc_howto_type or1k_elf_howto_table[] = +{ + /* This reloc does nothing. */ + HOWTO (R_OR1K_NONE, /* type */ + 0, /* rightshift */ + 3, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_NONE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_32, + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_32", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_16, + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_16", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_8, + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_8", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_LO_16_IN_INSN, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_LO_16_IN_INSN", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_HI_16_IN_INSN, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_HI_16_IN_INSN", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A PC relative 26 bit relocation, right shifted by 2. */ + HOWTO (R_OR1K_INSN_REL_26, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_INSN_REL_26", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x03ffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* GNU extension to record C++ vtable hierarchy. */ + HOWTO (R_OR1K_GNU_VTINHERIT, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + NULL, /* special_function */ + "R_OR1K_GNU_VTINHERIT", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* GNU extension to record C++ vtable member usage. */ + HOWTO (R_OR1K_GNU_VTENTRY, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + _bfd_elf_rel_vtable_reloc_fn, /* special_function */ + "R_OR1K_GNU_VTENTRY", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_32_PCREL, + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_32_PCREL", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_16_PCREL, + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_16_PCREL", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_8_PCREL, + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_8_PCREL", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_GOTPC_HI16, /* Type. */ + 16, /* Rightshift. */ + 2, /* Size (0 = byte, 1 = short, 2 = long). */ + 16, /* Bitsize. */ + TRUE, /* PC_relative. */ + 0, /* Bitpos. */ + complain_overflow_dont, /* Complain on overflow. */ + bfd_elf_generic_reloc, /* Special Function. */ + "R_OR1K_GOTPC_HI16", /* Name. */ + FALSE, /* Partial Inplace. */ + 0, /* Source Mask. */ + 0xffff, /* Dest Mask. */ + TRUE), /* PC relative offset? */ + + HOWTO (R_OR1K_GOTPC_LO16, /* Type. */ + 0, /* Rightshift. */ + 2, /* Size (0 = byte, 1 = short, 2 = long). */ + 16, /* Bitsize. */ + TRUE, /* PC_relative. */ + 0, /* Bitpos. */ + complain_overflow_dont, /* Complain on overflow. */ + bfd_elf_generic_reloc, /* Special Function. */ + "R_OR1K_GOTPC_LO16", /* Name. */ + FALSE, /* Partial Inplace. */ + 0, /* Source Mask. */ + 0xffff, /* Dest Mask. */ + TRUE), /* PC relative offset? */ + + HOWTO (R_OR1K_GOT16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_GOT16", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 26 bit PLT relocation. Shifted by 2. */ + HOWTO (R_OR1K_PLT26, /* Type. */ + 2, /* Rightshift. */ + 2, /* Size (0 = byte, 1 = short, 2 = long). */ + 26, /* Bitsize. */ + TRUE, /* PC_relative. */ + 0, /* Bitpos. */ + complain_overflow_dont, /* Complain on overflow. */ + bfd_elf_generic_reloc,/* Special Function. */ + "R_OR1K_PLT26", /* Name. */ + FALSE, /* Partial Inplace. */ + 0, /* Source Mask. */ + 0x03ffffff, /* Dest Mask. */ + TRUE), /* PC relative offset? */ + + HOWTO (R_OR1K_GOTOFF_HI16, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_GOTOFF_HI16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_GOTOFF_LO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_GOTOFF_LO16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_COPY, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_COPY", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_GLOB_DAT, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_GLOB_DAT", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_JMP_SLOT, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_JMP_SLOT", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_RELATIVE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_RELATIVE", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_TLS_GD_HI16, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_TLS_GD_HI16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_TLS_GD_LO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_TLS_GD_LO16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_TLS_LDM_HI16, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_TLS_LDM_HI16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_TLS_LDM_LO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_TLS_LDM_LO16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_TLS_LDO_HI16, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_TLS_LDO_HI16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_TLS_LDO_LO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_TLS_LDO_LO16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_TLS_IE_HI16, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_TLS_IE_HI16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_TLS_IE_LO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_TLS_IE_LO16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_TLS_LE_HI16, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_TLS_LE_HI16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_OR1K_TLS_LE_LO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_OR1K_TLS_LE_LO16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + +}; + +/* Map BFD reloc types to Or1k ELF reloc types. */ + +struct or1k_reloc_map +{ + bfd_reloc_code_real_type bfd_reloc_val; + unsigned int or1k_reloc_val; +}; + +static const struct or1k_reloc_map or1k_reloc_map[] = +{ + { BFD_RELOC_NONE, R_OR1K_NONE }, + { BFD_RELOC_32, R_OR1K_32 }, + { BFD_RELOC_16, R_OR1K_16 }, + { BFD_RELOC_8, R_OR1K_8 }, + { BFD_RELOC_LO16, R_OR1K_LO_16_IN_INSN }, + { BFD_RELOC_HI16, R_OR1K_HI_16_IN_INSN }, + { BFD_RELOC_OR1K_REL_26, R_OR1K_INSN_REL_26 }, + { BFD_RELOC_VTABLE_ENTRY, R_OR1K_GNU_VTENTRY }, + { BFD_RELOC_VTABLE_INHERIT, R_OR1K_GNU_VTINHERIT }, + { BFD_RELOC_32_PCREL, R_OR1K_32_PCREL }, + { BFD_RELOC_16_PCREL, R_OR1K_16_PCREL }, + { BFD_RELOC_8_PCREL, R_OR1K_8_PCREL }, + { BFD_RELOC_OR1K_GOTPC_HI16, R_OR1K_GOTPC_HI16 }, + { BFD_RELOC_OR1K_GOTPC_LO16, R_OR1K_GOTPC_LO16 }, + { BFD_RELOC_OR1K_GOT16, R_OR1K_GOT16 }, + { BFD_RELOC_OR1K_PLT26, R_OR1K_PLT26 }, + { BFD_RELOC_OR1K_GOTOFF_HI16, R_OR1K_GOTOFF_HI16 }, + { BFD_RELOC_OR1K_GOTOFF_LO16, R_OR1K_GOTOFF_LO16 }, + { BFD_RELOC_OR1K_GLOB_DAT, R_OR1K_GLOB_DAT }, + { BFD_RELOC_OR1K_COPY, R_OR1K_COPY }, + { BFD_RELOC_OR1K_JMP_SLOT, R_OR1K_JMP_SLOT }, + { BFD_RELOC_OR1K_RELATIVE, R_OR1K_RELATIVE }, + { BFD_RELOC_OR1K_TLS_GD_HI16, R_OR1K_TLS_GD_HI16 }, + { BFD_RELOC_OR1K_TLS_GD_LO16, R_OR1K_TLS_GD_LO16 }, + { BFD_RELOC_OR1K_TLS_LDM_HI16, R_OR1K_TLS_LDM_HI16 }, + { BFD_RELOC_OR1K_TLS_LDM_LO16, R_OR1K_TLS_LDM_LO16 }, + { BFD_RELOC_OR1K_TLS_LDO_HI16, R_OR1K_TLS_LDO_HI16 }, + { BFD_RELOC_OR1K_TLS_LDO_LO16, R_OR1K_TLS_LDO_LO16 }, + { BFD_RELOC_OR1K_TLS_IE_HI16, R_OR1K_TLS_IE_HI16 }, + { BFD_RELOC_OR1K_TLS_IE_LO16, R_OR1K_TLS_IE_LO16 }, + { BFD_RELOC_OR1K_TLS_LE_HI16, R_OR1K_TLS_LE_HI16 }, + { BFD_RELOC_OR1K_TLS_LE_LO16, R_OR1K_TLS_LE_LO16 }, +}; + +/* The linker needs to keep track of the number of relocs that it + decides to copy as dynamic relocs in check_relocs for each symbol. + This is so that it can later discard them if they are found to be + unnecessary. We store the information in a field extending the + regular ELF linker hash table. */ + +struct elf_or1k_dyn_relocs +{ + struct elf_or1k_dyn_relocs *next; + + /* The input section of the reloc. */ + asection *sec; + + /* Total number of relocs copied for the input section. */ + bfd_size_type count; + + /* Number of pc-relative relocs copied for the input section. */ + bfd_size_type pc_count; +}; + +#define TLS_UNKNOWN 0 +#define TLS_NONE 1 +#define TLS_GD 2 +#define TLS_LD 3 +#define TLS_IE 4 +#define TLS_LE 5 + +/* ELF linker hash entry. */ +struct elf_or1k_link_hash_entry +{ + struct elf_link_hash_entry root; + + /* Track dynamic relocs copied for this symbol. */ + struct elf_or1k_dyn_relocs *dyn_relocs; + + /* Track type of TLS access. */ + unsigned char tls_type; +}; + +/* ELF object data. */ +struct elf_or1k_obj_tdata +{ + struct elf_obj_tdata root; + + /* tls_type for each local got entry. */ + unsigned char *local_tls_type; +}; + +#define elf_or1k_tdata(abfd) \ + ((struct elf_or1k_obj_tdata *) (abfd)->tdata.any) + +#define elf_or1k_local_tls_type(abfd) \ + (elf_or1k_tdata (abfd)->local_tls_type) + +/* ELF linker hash table. */ +struct elf_or1k_link_hash_table +{ + struct elf_link_hash_table root; + + /* Short-cuts to get to dynamic linker sections. */ + asection *sgot; + asection *sgotplt; + asection *srelgot; + asection *splt; + asection *srelplt; + asection *sdynbss; + asection *srelbss; + + /* Small local sym to section mapping cache. */ + struct sym_cache sym_sec; +}; + +/* Get the ELF linker hash table from a link_info structure. */ +#define or1k_elf_hash_table(p) \ + (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ + == OR1K_ELF_DATA ? ((struct elf_or1k_link_hash_table *) ((p)->hash)) : NULL) + +static bfd_boolean +elf_or1k_mkobject (bfd *abfd) +{ + return bfd_elf_allocate_object (abfd, sizeof (struct elf_or1k_obj_tdata), + OR1K_ELF_DATA); +} + +/* Create an entry in an or1k ELF linker hash table. */ + +static struct bfd_hash_entry * +or1k_elf_link_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string) +{ + struct elf_or1k_link_hash_entry *ret = + (struct elf_or1k_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == NULL) + ret = bfd_hash_allocate (table, + sizeof (struct elf_or1k_link_hash_entry)); + if (ret == NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct elf_or1k_link_hash_entry *) + _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + if (ret != NULL) + { + struct elf_or1k_link_hash_entry *eh; + + eh = (struct elf_or1k_link_hash_entry *) ret; + eh->dyn_relocs = NULL; + eh->tls_type = TLS_UNKNOWN; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Create an or1k ELF linker hash table. */ + +static struct bfd_link_hash_table * +or1k_elf_link_hash_table_create (bfd *abfd) +{ + struct elf_or1k_link_hash_table *ret; + bfd_size_type amt = sizeof (struct elf_or1k_link_hash_table); + + ret = bfd_zmalloc (amt); + if (ret == NULL) + return NULL; + + if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, + or1k_elf_link_hash_newfunc, + sizeof (struct elf_or1k_link_hash_entry), + OR1K_ELF_DATA)) + { + free (ret); + return NULL; + } + + return &ret->root.root; +} + +static reloc_howto_type * +or1k_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) +{ + unsigned int i; + + for (i = ARRAY_SIZE (or1k_reloc_map); i--;) + if (or1k_reloc_map[i].bfd_reloc_val == code) + return & or1k_elf_howto_table[or1k_reloc_map[i].or1k_reloc_val]; + + return NULL; +} + +static reloc_howto_type * +or1k_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 0; + i < (sizeof (or1k_elf_howto_table) + / sizeof (or1k_elf_howto_table[0])); + i++) + if (or1k_elf_howto_table[i].name != NULL + && strcasecmp (or1k_elf_howto_table[i].name, r_name) == 0) + return &or1k_elf_howto_table[i]; + + return NULL; +} + +/* Set the howto pointer for an Or1k ELF reloc. */ + +static void +or1k_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, + arelent * cache_ptr, + Elf_Internal_Rela * dst) +{ + unsigned int r_type; + + r_type = ELF32_R_TYPE (dst->r_info); + if (r_type >= (unsigned int) R_OR1K_max) + { + _bfd_error_handler (_("%B: invalid OR1K reloc number: %d"), abfd, r_type); + r_type = 0; + } + cache_ptr->howto = & or1k_elf_howto_table[r_type]; +} + + +/* Return the relocation value for @tpoff relocations.. */ +static bfd_vma +tpoff (struct bfd_link_info *info, bfd_vma address) +{ + /* If tls_sec is NULL, we should have signalled an error already. */ + if (elf_hash_table (info)->tls_sec == NULL) + return 0; + + /* The thread pointer on or1k stores the address after the TCB where + the data is, just compute the difference. No need to compensate + for the size of TCB. */ + return (address - elf_hash_table (info)->tls_sec->vma); +} + +/* Relocate an Or1k ELF section. + + The RELOCATE_SECTION function is called by the new ELF backend linker + to handle the relocations for a section. + + The relocs are always passed as Rela structures; if the section + actually uses Rel structures, the r_addend field will always be + zero. + + This function is responsible for adjusting the section contents as + necessary, and (if using Rela relocs and generating a relocatable + output file) adjusting the reloc addend as necessary. + + This function does not have to worry about setting the reloc + address or the reloc symbol index. + + LOCAL_SYMS is a pointer to the swapped in local symbols. + + LOCAL_SECTIONS is an array giving the section in the input file + corresponding to the st_shndx field of each local symbol. + + The global hash table entry for the global symbols can be found + via elf_sym_hashes (input_bfd). + + When generating relocatable output, this function must handle + STB_LOCAL/STT_SECTION symbols specially. The output symbol is + going to be the section symbol corresponding to the output + section, which means that the addend must be adjusted + accordingly. */ + +static bfd_boolean +or1k_elf_relocate_section (bfd *output_bfd, + struct bfd_link_info *info, + bfd *input_bfd, + asection *input_section, + bfd_byte *contents, + Elf_Internal_Rela *relocs, + Elf_Internal_Sym *local_syms, + asection **local_sections) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + struct elf_or1k_link_hash_table *htab = or1k_elf_hash_table (info); + bfd *dynobj; + asection *sreloc; + bfd_vma *local_got_offsets; + asection *sgot; + + if (htab == NULL) + return FALSE; + + dynobj = htab->root.dynobj; + local_got_offsets = elf_local_got_offsets (input_bfd); + + sreloc = elf_section_data (input_section)->sreloc; + + sgot = htab->sgot; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + relend = relocs + input_section->reloc_count; + + for (rel = relocs; rel < relend; rel++) + { + reloc_howto_type *howto; + unsigned long r_symndx; + Elf_Internal_Sym *sym; + asection *sec; + struct elf_link_hash_entry *h; + bfd_vma relocation; + bfd_reloc_status_type r; + const char *name = NULL; + int r_type; + + r_type = ELF32_R_TYPE (rel->r_info); + r_symndx = ELF32_R_SYM (rel->r_info); + + if (r_type == R_OR1K_GNU_VTINHERIT + || r_type == R_OR1K_GNU_VTENTRY) + continue; + + if (r_type < 0 || r_type >= (int) R_OR1K_max) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + howto = or1k_elf_howto_table + ELF32_R_TYPE (rel->r_info); + h = NULL; + sym = NULL; + sec = NULL; + + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); + name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; + } + else + { + bfd_boolean unresolved_reloc, warned, ignored; + + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, + r_symndx, symtab_hdr, sym_hashes, + h, sec, relocation, + unresolved_reloc, warned, ignored); + } + + if (sec != NULL && discarded_section (sec)) + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, + rel, 1, relend, howto, 0, contents); + + if (info->relocatable) + continue; + + switch (howto->type) + { + case R_OR1K_PLT26: + { + if (htab->splt != NULL && h != NULL + && h->plt.offset != (bfd_vma) -1) + { + relocation = (htab->splt->output_section->vma + + htab->splt->output_offset + + h->plt.offset); + } + break; + } + + case R_OR1K_GOT16: + /* Relocation is to the entry for this symbol in the global + offset table. */ + BFD_ASSERT (sgot != NULL); + if (h != NULL) + { + bfd_boolean dyn; + bfd_vma off; + + off = h->got.offset; + BFD_ASSERT (off != (bfd_vma) -1); + + dyn = htab->root.dynamic_sections_created; + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) + || (info->shared + && SYMBOL_REFERENCES_LOCAL (info, h))) + { + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally, or the symbol was forced to be local + because of a version file. We must initialize + this entry in the global offset table. Since the + offset must always be a multiple of 4, we use the + least significant bit to record whether we have + initialized it already. + + When doing a dynamic link, we create a .rela.got + relocation entry to initialize the value. This + is done in the finish_dynamic_symbol routine. */ + if ((off & 1) != 0) + off &= ~1; + else + { + /* Write entry in GOT. */ + bfd_put_32 (output_bfd, relocation, + sgot->contents + off); + /* Mark GOT entry as having been written. */ + h->got.offset |= 1; + } + } + + relocation = sgot->output_offset + off; + } + else + { + bfd_vma off; + bfd_byte *loc; + + BFD_ASSERT (local_got_offsets != NULL + && local_got_offsets[r_symndx] != (bfd_vma) -1); + + /* Get offset into GOT table. */ + off = local_got_offsets[r_symndx]; + + /* The offset must always be a multiple of 4. We use + the least significant bit to record whether we have + already processed this entry. */ + if ((off & 1) != 0) + off &= ~1; + else + { + /* Write entry in GOT. */ + bfd_put_32 (output_bfd, relocation, sgot->contents + off); + if (info->shared) + { + asection *srelgot; + Elf_Internal_Rela outrel; + + /* We need to generate a R_OR1K_RELATIVE reloc + for the dynamic linker. */ + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (srelgot != NULL); + + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + off); + outrel.r_info = ELF32_R_INFO (0, R_OR1K_RELATIVE); + outrel.r_addend = relocation; + loc = srelgot->contents; + loc += srelgot->reloc_count * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &outrel,loc); + ++srelgot->reloc_count; + } + + local_got_offsets[r_symndx] |= 1; + } + relocation = sgot->output_offset + off; + } + + /* Addend should be zero. */ + if (rel->r_addend != 0) + (*_bfd_error_handler) + (_("internal error: addend should be zero for R_OR1K_GOT16")); + + break; + + case R_OR1K_GOTOFF_LO16: + case R_OR1K_GOTOFF_HI16: + /* Relocation is offset from GOT. */ + BFD_ASSERT (sgot != NULL); + relocation -= sgot->output_section->vma; + break; + + case R_OR1K_INSN_REL_26: + case R_OR1K_HI_16_IN_INSN: + case R_OR1K_LO_16_IN_INSN: + case R_OR1K_32: + /* R_OR1K_16? */ + { + /* r_symndx will be STN_UNDEF (zero) only for relocs against symbols + from removed linkonce sections, or sections discarded by + a linker script. */ + if (r_symndx == STN_UNDEF + || (input_section->flags & SEC_ALLOC) == 0) + break; + + if ((info->shared + && (h == NULL + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak) + && (howto->type != R_OR1K_INSN_REL_26 + || !SYMBOL_CALLS_LOCAL (info, h))) + || (!info->shared + && h != NULL + && h->dynindx != -1 + && !h->non_got_ref + && ((h->def_dynamic + && !h->def_regular) + || h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined))) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + bfd_boolean skip; + + /* When generating a shared object, these relocations + are copied into the output file to be resolved at run + time. */ + + BFD_ASSERT (sreloc != NULL); + + skip = FALSE; + + outrel.r_offset = + _bfd_elf_section_offset (output_bfd, info, input_section, + rel->r_offset); + if (outrel.r_offset == (bfd_vma) -1) + skip = TRUE; + else if (outrel.r_offset == (bfd_vma) -2) + skip = TRUE; + outrel.r_offset += (input_section->output_section->vma + + input_section->output_offset); + + if (skip) + memset (&outrel, 0, sizeof outrel); + /* h->dynindx may be -1 if the symbol was marked to + become local. */ + else if (h != NULL + && ((! info->symbolic && h->dynindx != -1) + || !h->def_regular)) + { + BFD_ASSERT (h->dynindx != -1); + outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); + outrel.r_addend = rel->r_addend; + } + else + { + if (r_type == R_OR1K_32) + { + outrel.r_info = ELF32_R_INFO (0, R_OR1K_RELATIVE); + outrel.r_addend = relocation + rel->r_addend; + } + else + { + BFD_FAIL (); + (*_bfd_error_handler) + (_("%B: probably compiled without -fPIC?"), + input_bfd); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + } + + loc = sreloc->contents; + loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + break; + } + break; + } + + case R_OR1K_TLS_LDM_HI16: + case R_OR1K_TLS_LDM_LO16: + case R_OR1K_TLS_LDO_HI16: + case R_OR1K_TLS_LDO_LO16: + /* TODO: implement support for local dynamic. */ + BFD_FAIL (); + (*_bfd_error_handler) + (_("%B: support for local dynamic not implemented"), + input_bfd); + bfd_set_error (bfd_error_bad_value); + return FALSE; + + + case R_OR1K_TLS_GD_HI16: + case R_OR1K_TLS_GD_LO16: + case R_OR1K_TLS_IE_HI16: + case R_OR1K_TLS_IE_LO16: + { + bfd_vma gotoff; + Elf_Internal_Rela rela; + bfd_byte *loc; + int dynamic; + + sreloc = bfd_get_section_by_name (dynobj, ".rela.got"); + + /* Mark as TLS related GOT entry by setting + bit 2 as well as bit 1. */ + if (h != NULL) + { + gotoff = h->got.offset; + h->got.offset |= 3; + } + else + { + gotoff = local_got_offsets[r_symndx]; + local_got_offsets[r_symndx] |= 3; + } + + /* Only process the relocation once. */ + if (gotoff & 1) + { + relocation = sgot->output_offset + (gotoff & ~3); + break; + } + + BFD_ASSERT (elf_hash_table (info)->hgot == NULL + || elf_hash_table (info)->hgot->root.u.def.value == 0); + + /* Dynamic entries will require relocations. if we do not need + them we will just use the default R_OR1K_NONE and + not set anything. */ + dynamic = info->shared + || (sec && (sec->flags & SEC_ALLOC) != 0 + && h != NULL + && (h->root.type == bfd_link_hash_defweak || !h->def_regular)); + + /* Shared GD. */ + if (dynamic && (howto->type == R_OR1K_TLS_GD_HI16 + || howto->type == R_OR1K_TLS_GD_LO16)) + { + int i; + + /* Add DTPMOD and DTPOFF GOT and rela entries. */ + for (i = 0; i < 2; ++i) + { + rela.r_offset = sgot->output_section->vma + + sgot->output_offset + gotoff + i*4; + if (h != NULL && h->dynindx != -1) + { + rela.r_info = ELF32_R_INFO (h->dynindx, + (i == 0 ? R_OR1K_TLS_DTPMOD : R_OR1K_TLS_DTPOFF)); + rela.r_addend = 0; + } + else + { + rela.r_info = ELF32_R_INFO (0, + (i == 0 ? R_OR1K_TLS_DTPMOD : R_OR1K_TLS_DTPOFF)); + rela.r_addend = tpoff (info, relocation); + } + + loc = sreloc->contents; + loc += sreloc->reloc_count++ * + sizeof (Elf32_External_Rela); + + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + bfd_put_32 (output_bfd, 0, sgot->contents + gotoff + i*4); + } + } + /* Static GD. */ + else if (howto->type == R_OR1K_TLS_GD_HI16 + || howto->type == R_OR1K_TLS_GD_LO16) + { + bfd_put_32 (output_bfd, 1, sgot->contents + gotoff); + bfd_put_32 (output_bfd, tpoff (info, relocation), + sgot->contents + gotoff + 4); + } + /* Shared IE. */ + else if (dynamic) + { + /* Add TPOFF GOT and rela entries. */ + rela.r_offset = sgot->output_section->vma + + sgot->output_offset + gotoff; + if (h != NULL && h->dynindx != -1) + { + rela.r_info = ELF32_R_INFO (h->dynindx, R_OR1K_TLS_TPOFF); + rela.r_addend = 0; + } + else + { + rela.r_info = ELF32_R_INFO (0, R_OR1K_TLS_TPOFF); + rela.r_addend = tpoff (info, relocation); + } + + loc = sreloc->contents; + loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); + + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + bfd_put_32 (output_bfd, 0, sgot->contents + gotoff); + } + /* Static IE. */ + else + { + bfd_put_32 (output_bfd, tpoff (info, relocation), + sgot->contents + gotoff); + } + relocation = sgot->output_offset + gotoff; + break; + } + case R_OR1K_TLS_LE_HI16: + case R_OR1K_TLS_LE_LO16: + + /* Relocation is offset from TP. */ + relocation = tpoff (info, relocation); + break; + + case R_OR1K_TLS_DTPMOD: + case R_OR1K_TLS_DTPOFF: + case R_OR1K_TLS_TPOFF: + /* These are resolved dynamically on load and shouldn't + be used as linker input. */ + BFD_FAIL (); + (*_bfd_error_handler) + (_("%B: will not resolve runtime TLS relocation"), + input_bfd); + bfd_set_error (bfd_error_bad_value); + return FALSE; + + default: + break; + } + r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, + rel->r_offset, relocation, rel->r_addend); + + if (r != bfd_reloc_ok) + { + const char *msg = NULL; + + switch (r) + { + case bfd_reloc_overflow: + r = info->callbacks->reloc_overflow + (info, (h ? &h->root : NULL), name, howto->name, + (bfd_vma) 0, input_bfd, input_section, rel->r_offset); + break; + + case bfd_reloc_undefined: + r = info->callbacks->undefined_symbol + (info, name, input_bfd, input_section, rel->r_offset, TRUE); + break; + + case bfd_reloc_outofrange: + msg = _("internal error: out of range error"); + break; + + case bfd_reloc_notsupported: + msg = _("internal error: unsupported relocation error"); + break; + + case bfd_reloc_dangerous: + msg = _("internal error: dangerous relocation"); + break; + + default: + msg = _("internal error: unknown error"); + break; + } + + if (msg) + r = info->callbacks->warning + (info, msg, name, input_bfd, input_section, rel->r_offset); + + if (!r) + return FALSE; + } + } + + return TRUE; +} + +/* Return the section that should be marked against GC for a given + relocation. */ + +static asection * +or1k_elf_gc_mark_hook (asection *sec, + struct bfd_link_info *info, + Elf_Internal_Rela *rel, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) +{ + if (h != NULL) + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_OR1K_GNU_VTINHERIT: + case R_OR1K_GNU_VTENTRY: + return NULL; + } + + return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); +} + +static bfd_boolean +or1k_elf_gc_sweep_hook (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + asection *sec, + const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED) +{ + /* Update the got entry reference counts for the section being removed. */ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_signed_vma *local_got_refcounts; + const Elf_Internal_Rela *rel, *relend; + + elf_section_data (sec)->local_dynrel = NULL; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + local_got_refcounts = elf_local_got_refcounts (abfd); + + relend = relocs + sec->reloc_count; + for (rel = relocs; rel < relend; rel++) + { + unsigned long r_symndx; + struct elf_link_hash_entry *h = NULL; + + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx >= symtab_hdr->sh_info) + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + } + + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_OR1K_GOT16: + if (h != NULL) + { + if (h->got.refcount > 0) + h->got.refcount--; + } + else + { + if (local_got_refcounts && local_got_refcounts[r_symndx] > 0) + local_got_refcounts[r_symndx]--; + } + break; + + default: + break; + } + } + return TRUE; +} + +/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up + shortcuts to them in our hash table. */ + +static bfd_boolean +create_got_section (bfd *dynobj, struct bfd_link_info *info) +{ + struct elf_or1k_link_hash_table *htab; + asection *s; + + /* This function may be called more than once. */ + s = bfd_get_section_by_name (dynobj, ".got"); + if (s != NULL && (s->flags & SEC_LINKER_CREATED) != 0) + return TRUE; + + htab = or1k_elf_hash_table (info); + if (htab == NULL) + return FALSE; + + if (! _bfd_elf_create_got_section (dynobj, info)) + return FALSE; + + htab->sgot = bfd_get_section_by_name (dynobj, ".got"); + htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt"); + htab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + + if (! htab->sgot || ! htab->sgotplt || ! htab->srelgot) + abort (); + + if (! bfd_set_section_flags (dynobj, htab->srelgot, SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY) + || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2)) + return FALSE; + + return TRUE; +} + +/* Look through the relocs for a section during the first phase. */ + +static bfd_boolean +or1k_elf_check_relocs (bfd *abfd, + struct bfd_link_info *info, + asection *sec, + const Elf_Internal_Rela *relocs) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + const Elf_Internal_Rela *rel; + + const Elf_Internal_Rela *rel_end; + struct elf_or1k_link_hash_table *htab; + bfd *dynobj; + asection *sreloc = NULL; + + if (info->relocatable) + return TRUE; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + + htab = or1k_elf_hash_table (info); + if (htab == NULL) + return FALSE; + + dynobj = htab->root.dynobj; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + struct elf_link_hash_entry *h; + unsigned long r_symndx; + unsigned char tls_type; + + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + /* PR15323, ref flags aren't set for references in the same + object. */ + h->root.non_ir_ref = 1; + } + + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_OR1K_TLS_GD_HI16: + case R_OR1K_TLS_GD_LO16: + tls_type = TLS_GD; + break; + case R_OR1K_TLS_LDM_HI16: + case R_OR1K_TLS_LDM_LO16: + case R_OR1K_TLS_LDO_HI16: + case R_OR1K_TLS_LDO_LO16: + tls_type = TLS_LD; + break; + case R_OR1K_TLS_IE_HI16: + case R_OR1K_TLS_IE_LO16: + tls_type = TLS_IE; + break; + case R_OR1K_TLS_LE_HI16: + case R_OR1K_TLS_LE_LO16: + tls_type = TLS_LE; + break; + default: + tls_type = TLS_NONE; + } + + /* Record TLS type. */ + if (h != NULL) + ((struct elf_or1k_link_hash_entry *) h)->tls_type = tls_type; + else + { + unsigned char *local_tls_type; + + /* This is a TLS type record for a local symbol. */ + local_tls_type = (unsigned char *) elf_or1k_local_tls_type (abfd); + if (local_tls_type == NULL) + { + bfd_size_type size; + + size = symtab_hdr->sh_info; + local_tls_type = bfd_zalloc (abfd, size); + if (local_tls_type == NULL) + return FALSE; + elf_or1k_local_tls_type (abfd) = local_tls_type; + } + local_tls_type[r_symndx] = tls_type; + } + + switch (ELF32_R_TYPE (rel->r_info)) + { + /* This relocation describes the C++ object vtable hierarchy. + Reconstruct it for later use during GC. */ + case R_OR1K_GNU_VTINHERIT: + if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) + return FALSE; + break; + + /* This relocation describes which C++ vtable entries are actually + used. Record for later use during GC. */ + case R_OR1K_GNU_VTENTRY: + BFD_ASSERT (h != NULL); + if (h != NULL + && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) + return FALSE; + break; + + /* This relocation requires .plt entry. */ + case R_OR1K_PLT26: + if (h != NULL) + { + h->needs_plt = 1; + h->plt.refcount += 1; + } + break; + + case R_OR1K_GOT16: + case R_OR1K_GOTOFF_HI16: + case R_OR1K_GOTOFF_LO16: + case R_OR1K_TLS_GD_HI16: + case R_OR1K_TLS_GD_LO16: + case R_OR1K_TLS_IE_HI16: + case R_OR1K_TLS_IE_LO16: + if (htab->sgot == NULL) + { + if (dynobj == NULL) + htab->root.dynobj = dynobj = abfd; + if (! create_got_section (dynobj, info)) + return FALSE; + } + + if (ELF32_R_TYPE (rel->r_info) != R_OR1K_GOTOFF_HI16 && + ELF32_R_TYPE (rel->r_info) != R_OR1K_GOTOFF_LO16) + { + if (h != NULL) + h->got.refcount += 1; + else + { + bfd_signed_vma *local_got_refcounts; + + /* This is a global offset table entry for a local symbol. */ + local_got_refcounts = elf_local_got_refcounts (abfd); + if (local_got_refcounts == NULL) + { + bfd_size_type size; + + size = symtab_hdr->sh_info; + size *= sizeof (bfd_signed_vma); + local_got_refcounts = bfd_zalloc (abfd, size); + if (local_got_refcounts == NULL) + return FALSE; + elf_local_got_refcounts (abfd) = local_got_refcounts; + } + local_got_refcounts[r_symndx] += 1; + } + } + break; + + case R_OR1K_INSN_REL_26: + case R_OR1K_HI_16_IN_INSN: + case R_OR1K_LO_16_IN_INSN: + case R_OR1K_32: + /* R_OR1K_16? */ + { + if (h != NULL && !info->shared) + { + /* We may need a copy reloc. */ + h->non_got_ref = 1; + + /* We may also need a .plt entry. */ + h->plt.refcount += 1; + if (ELF32_R_TYPE (rel->r_info) != R_OR1K_INSN_REL_26) + h->pointer_equality_needed = 1; + } + + /* If we are creating a shared library, and this is a reloc + against a global symbol, or a non PC relative reloc + against a local symbol, then we need to copy the reloc + into the shared library. However, if we are linking with + -Bsymbolic, we do not need to copy a reloc against a + global symbol which is defined in an object we are + including in the link (i.e., DEF_REGULAR is set). At + this point we have not seen all the input files, so it is + possible that DEF_REGULAR is not set now but will be set + later (it is never cleared). In case of a weak definition, + DEF_REGULAR may be cleared later by a strong definition in + a shared library. We account for that possibility below by + storing information in the relocs_copied field of the hash + table entry. A similar situation occurs when creating + shared libraries and symbol visibility changes render the + symbol local. + + If on the other hand, we are creating an executable, we + may need to keep relocations for symbols satisfied by a + dynamic library if we manage to avoid copy relocs for the + symbol. */ + + if ((info->shared + && (sec->flags & SEC_ALLOC) != 0 + && (ELF32_R_TYPE (rel->r_info) != R_OR1K_INSN_REL_26 + || (h != NULL + && (!SYMBOLIC_BIND (info, h) + || h->root.type == bfd_link_hash_defweak + || !h->def_regular)))) + || (!info->shared + && (sec->flags & SEC_ALLOC) != 0 + && h != NULL + && (h->root.type == bfd_link_hash_defweak + || !h->def_regular))) + { + struct elf_or1k_dyn_relocs *p; + struct elf_or1k_dyn_relocs **head; + + /* When creating a shared object, we must copy these + relocs into the output file. We create a reloc + section in dynobj and make room for the reloc. */ + if (sreloc == NULL) + { + const char *name; + unsigned int strndx = elf_elfheader (abfd)->e_shstrndx; + unsigned int shnam = _bfd_elf_single_rel_hdr (sec)->sh_name; + + name = bfd_elf_string_from_elf_section (abfd, strndx, shnam); + if (name == NULL) + return FALSE; + + if (strncmp (name, ".rela", 5) != 0 + || strcmp (bfd_get_section_name (abfd, sec), + name + 5) != 0) + { + (*_bfd_error_handler) + (_("%B: bad relocation section name `%s\'"), + abfd, name); + } + + if (htab->root.dynobj == NULL) + htab->root.dynobj = abfd; + dynobj = htab->root.dynobj; + + sreloc = bfd_get_section_by_name (dynobj, name); + if (sreloc == NULL) + { + sreloc = _bfd_elf_make_dynamic_reloc_section + (sec, dynobj, 2, abfd, /*rela?*/ TRUE); + + if (sreloc == NULL) + return FALSE; + } + elf_section_data (sec)->sreloc = sreloc; + } + + /* If this is a global symbol, we count the number of + relocations we need for this symbol. */ + if (h != NULL) + head = &((struct elf_or1k_link_hash_entry *) h)->dyn_relocs; + else + { + /* Track dynamic relocs needed for local syms too. + We really need local syms available to do this + easily. Oh well. */ + + asection *s; + Elf_Internal_Sym *isym; + void *vpp; + + isym = bfd_sym_from_r_symndx (&htab->sym_sec, + abfd, r_symndx); + if (isym == NULL) + return FALSE; + + s = bfd_section_from_elf_index (abfd, isym->st_shndx); + if (s == NULL) + return FALSE; + + vpp = &elf_section_data (s)->local_dynrel; + head = (struct elf_or1k_dyn_relocs **) vpp; + } + + p = *head; + if (p == NULL || p->sec != sec) + { + bfd_size_type amt = sizeof *p; + p = ((struct elf_or1k_dyn_relocs *) + bfd_alloc (htab->root.dynobj, amt)); + if (p == NULL) + return FALSE; + p->next = *head; + *head = p; + p->sec = sec; + p->count = 0; + p->pc_count = 0; + } + + p->count += 1; + if (ELF32_R_TYPE (rel->r_info) == R_OR1K_INSN_REL_26) + p->pc_count += 1; + } + } + break; + } + } + + return TRUE; +} + +/* Finish up the dynamic sections. */ + +static bfd_boolean +or1k_elf_finish_dynamic_sections (bfd *output_bfd, + struct bfd_link_info *info) +{ + bfd *dynobj; + asection *sdyn, *sgot; + struct elf_or1k_link_hash_table *htab; + + htab = or1k_elf_hash_table (info); + if (htab == NULL) + return FALSE; + + dynobj = htab->root.dynobj; + + sgot = htab->sgotplt; + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + + if (htab->root.dynamic_sections_created) + { + asection *splt; + Elf32_External_Dyn *dyncon, *dynconend; + + BFD_ASSERT (sgot != NULL && sdyn != NULL); + + dyncon = (Elf32_External_Dyn *) sdyn->contents; + dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); + + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + asection *s; + + bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + default: + continue; + + case DT_PLTGOT: + s = htab->sgot->output_section; + BFD_ASSERT (s != NULL); + dyn.d_un.d_ptr = s->vma; + break; + + case DT_JMPREL: + s = htab->srelplt->output_section; + BFD_ASSERT (s != NULL); + dyn.d_un.d_ptr = s->vma; + break; + + case DT_PLTRELSZ: + s = htab->srelplt->output_section; + BFD_ASSERT (s != NULL); + dyn.d_un.d_val = s->size; + break; + + case DT_RELASZ: + /* My reading of the SVR4 ABI indicates that the + procedure linkage table relocs (DT_JMPREL) should be + included in the overall relocs (DT_RELA). This is + what Solaris does. However, UnixWare can not handle + that case. Therefore, we override the DT_RELASZ entry + here to make it not include the JMPREL relocs. Since + the linker script arranges for .rela.plt to follow all + other relocation sections, we don't have to worry + about changing the DT_RELA entry. */ + if (htab->srelplt != NULL) + { + /* FIXME: this calculation sometimes produces + wrong result, the problem is that the dyn.d_un.d_val + is not always correct, needs investigation why + that happens. In the meantime, reading the + ".rela.dyn" section by name seems to yield + correct result. + + s = htab->srelplt->output_section; + dyn.d_un.d_val -= s->size; + */ + + s = bfd_get_section_by_name (output_bfd, ".rela.dyn"); + dyn.d_un.d_val = s ? s->size : 0; + } + break; + } + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + } + + + /* Fill in the first entry in the procedure linkage table. */ + splt = htab->splt; + if (splt && splt->size > 0) + { + if (info->shared) + { + bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD0, + splt->contents); + bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD1, + splt->contents + 4); + bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD2, + splt->contents + 8); + bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD3, + splt->contents + 12); + bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD4, + splt->contents + 16); + } + else + { + unsigned long addr; + /* addr = .got + 4 */ + addr = sgot->output_section->vma + sgot->output_offset + 4; + bfd_put_32 (output_bfd, + PLT0_ENTRY_WORD0 | ((addr >> 16) & 0xffff), + splt->contents); + bfd_put_32 (output_bfd, + PLT0_ENTRY_WORD1 | (addr & 0xffff), + splt->contents + 4); + bfd_put_32 (output_bfd, PLT0_ENTRY_WORD2, splt->contents + 8); + bfd_put_32 (output_bfd, PLT0_ENTRY_WORD3, splt->contents + 12); + bfd_put_32 (output_bfd, PLT0_ENTRY_WORD4, splt->contents + 16); + } + + elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4; + } + } + + /* Set the first entry in the global offset table to the address of + the dynamic section. */ + if (sgot && sgot->size > 0) + { + if (sdyn == NULL) + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); + else + bfd_put_32 (output_bfd, + sdyn->output_section->vma + sdyn->output_offset, + sgot->contents); + elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; + } + + if (htab->sgot && htab->sgot->size > 0) + elf_section_data (htab->sgot->output_section)->this_hdr.sh_entsize = 4; + + return TRUE; +} + +/* Finish up dynamic symbol handling. We set the contents of various + dynamic sections here. */ + +static bfd_boolean +or1k_elf_finish_dynamic_symbol (bfd *output_bfd, + struct bfd_link_info *info, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) +{ + struct elf_or1k_link_hash_table *htab; + bfd_byte *loc; + + htab = or1k_elf_hash_table (info); + if (htab == NULL) + return FALSE; + + if (h->plt.offset != (bfd_vma) -1) + { + asection *splt; + asection *sgot; + asection *srela; + + bfd_vma plt_index; + bfd_vma got_offset; + bfd_vma got_addr; + Elf_Internal_Rela rela; + + /* This symbol has an entry in the procedure linkage table. Set + it up. */ + BFD_ASSERT (h->dynindx != -1); + + splt = htab->splt; + sgot = htab->sgotplt; + srela = htab->srelplt; + BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL); + + /* Get the index in the procedure linkage table which + corresponds to this symbol. This is the index of this symbol + in all the symbols for which we are making plt entries. The + first entry in the procedure linkage table is reserved. */ + plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; + + /* Get the offset into the .got table of the entry that + corresponds to this function. Each .got entry is 4 bytes. + The first three are reserved. */ + got_offset = (plt_index + 3) * 4; + got_addr = got_offset; + + /* Fill in the entry in the procedure linkage table. */ + if (! info->shared) + { + got_addr += htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset; + bfd_put_32 (output_bfd, PLT_ENTRY_WORD0 | ((got_addr >> 16) & 0xffff), + splt->contents + h->plt.offset); + bfd_put_32 (output_bfd, PLT_ENTRY_WORD1 | (got_addr & 0xffff), + splt->contents + h->plt.offset + 4); + bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD2, + splt->contents + h->plt.offset + 8); + bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD3, + splt->contents + h->plt.offset + 12); + bfd_put_32 (output_bfd, PLT_ENTRY_WORD4 + | plt_index * sizeof (Elf32_External_Rela), + splt->contents + h->plt.offset + 16); + } + else + { + bfd_put_32 (output_bfd, PLT_PIC_ENTRY_WORD0 | (got_addr & 0xffff), + splt->contents + h->plt.offset); + bfd_put_32 (output_bfd, PLT_PIC_ENTRY_WORD1 + | plt_index * sizeof (Elf32_External_Rela), + splt->contents + h->plt.offset + 4); + bfd_put_32 (output_bfd, (bfd_vma) PLT_PIC_ENTRY_WORD2, + splt->contents + h->plt.offset + 8); + bfd_put_32 (output_bfd, (bfd_vma) PLT_PIC_ENTRY_WORD3, + splt->contents + h->plt.offset + 12); + bfd_put_32 (output_bfd, (bfd_vma) PLT_PIC_ENTRY_WORD4, + splt->contents + h->plt.offset + 16); + } + + /* Fill in the entry in the global offset table. */ + bfd_put_32 (output_bfd, + (splt->output_section->vma + + splt->output_offset), /* Same offset. */ + sgot->contents + got_offset); + + /* Fill in the entry in the .rela.plt section. */ + rela.r_offset = (sgot->output_section->vma + + sgot->output_offset + + got_offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_OR1K_JMP_SLOT); + rela.r_addend = 0; + loc = srela->contents; + loc += plt_index * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + + if (!h->def_regular) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value alone. */ + sym->st_shndx = SHN_UNDEF; + } + + } + + if (h->got.offset != (bfd_vma) -1 + && (h->got.offset & 2) == 0) /* Homemade TLS check. */ + { + asection *sgot; + asection *srela; + Elf_Internal_Rela rela; + + /* This symbol has an entry in the global offset table. Set it + up. */ + sgot = htab->sgot; + srela = htab->srelgot; + BFD_ASSERT (sgot != NULL && srela != NULL); + + rela.r_offset = (sgot->output_section->vma + + sgot->output_offset + + (h->got.offset &~ 1)); + + /* If this is a -Bsymbolic link, and the symbol is defined + locally, we just want to emit a RELATIVE reloc. Likewise if + the symbol was forced to be local because of a version file. + The entry in the global offset table will already have been + initialized in the relocate_section function. */ + if (info->shared && SYMBOL_REFERENCES_LOCAL (info, h)) + { + rela.r_info = ELF32_R_INFO (0, R_OR1K_RELATIVE); + rela.r_addend = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + } + else + { + BFD_ASSERT ((h->got.offset & 1) == 0); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_OR1K_GLOB_DAT); + rela.r_addend = 0; + } + + loc = srela->contents; + loc += srela->reloc_count * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + ++srela->reloc_count; + } + + if (h->needs_copy) + { + asection *s; + Elf_Internal_Rela rela; + + /* This symbols needs a copy reloc. Set it up. */ + BFD_ASSERT (h->dynindx != -1 + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)); + + s = bfd_get_section_by_name (h->root.u.def.section->owner, + ".rela.bss"); + BFD_ASSERT (s != NULL); + + rela.r_offset = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_OR1K_COPY); + rela.r_addend = 0; + loc = s->contents; + loc += s->reloc_count * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + ++s->reloc_count; + } + + /* Mark some specially defined symbols as absolute. */ + if (strcmp (h->root.root.string, "_DYNAMIC") == 0 + || h == htab->root.hgot) + sym->st_shndx = SHN_ABS; + + return TRUE; +} + +static enum elf_reloc_type_class +or1k_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, + const asection *rel_sec ATTRIBUTE_UNUSED, + const Elf_Internal_Rela *rela) +{ + switch ((int) ELF32_R_TYPE (rela->r_info)) + { + case R_OR1K_RELATIVE: return reloc_class_relative; + case R_OR1K_JMP_SLOT: return reloc_class_plt; + case R_OR1K_COPY: return reloc_class_copy; + default: return reloc_class_normal; + } +} + +/* Adjust a symbol defined by a dynamic object and referenced by a + regular object. The current definition is in some section of the + dynamic object, but we're not including those sections. We have to + change the definition to something the rest of the link can + understand. */ + +static bfd_boolean +or1k_elf_adjust_dynamic_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h) +{ + struct elf_or1k_link_hash_table *htab; + struct elf_or1k_link_hash_entry *eh; + struct elf_or1k_dyn_relocs *p; + bfd *dynobj; + asection *s; + + dynobj = elf_hash_table (info)->dynobj; + + /* Make sure we know what is going on here. */ + BFD_ASSERT (dynobj != NULL + && (h->needs_plt + || h->u.weakdef != NULL + || (h->def_dynamic + && h->ref_regular + && !h->def_regular))); + + /* If this is a function, put it in the procedure linkage table. We + will fill in the contents of the procedure linkage table later, + when we know the address of the .got section. */ + if (h->type == STT_FUNC + || h->needs_plt) + { + if (! info->shared + && !h->def_dynamic + && !h->ref_dynamic + && h->root.type != bfd_link_hash_undefweak + && h->root.type != bfd_link_hash_undefined) + { + /* This case can occur if we saw a PLT reloc in an input + file, but the symbol was never referred to by a dynamic + object. In such a case, we don't actually need to build + a procedure linkage table, and we can just do a PCREL + reloc instead. */ + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + + return TRUE; + } + else + h->plt.offset = (bfd_vma) -1; + + /* If this is a weak symbol, and there is a real definition, the + processor independent code will have arranged for us to see the + real definition first, and we can just use the same value. */ + if (h->u.weakdef != NULL) + { + BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined + || h->u.weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->u.weakdef->root.u.def.section; + h->root.u.def.value = h->u.weakdef->root.u.def.value; + return TRUE; + } + + /* This is a reference to a symbol defined by a dynamic object which + is not a function. */ + + /* If we are creating a shared library, we must presume that the + only references to the symbol are via the global offset table. + For such cases we need not do anything here; the relocations will + be handled correctly by relocate_section. */ + if (info->shared) + return TRUE; + + /* If there are no references to this symbol that do not use the + GOT, we don't need to generate a copy reloc. */ + if (!h->non_got_ref) + return TRUE; + + /* If -z nocopyreloc was given, we won't generate them either. */ + if (info->nocopyreloc) + { + h->non_got_ref = 0; + return TRUE; + } + + eh = (struct elf_or1k_link_hash_entry *) h; + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + s = p->sec->output_section; + if (s != NULL && (s->flags & (SEC_READONLY | SEC_HAS_CONTENTS)) != 0) + break; + } + + /* If we didn't find any dynamic relocs in sections which needs the + copy reloc, then we'll be keeping the dynamic relocs and avoiding + the copy reloc. */ + if (p == NULL) + { + h->non_got_ref = 0; + return TRUE; + } + + /* We must allocate the symbol in our .dynbss section, which will + become part of the .bss section of the executable. There will be + an entry for this symbol in the .dynsym section. The dynamic + object will contain position independent code, so all references + from the dynamic object to this symbol will go through the global + offset table. The dynamic linker will use the .dynsym entry to + determine the address it must put in the global offset table, so + both the dynamic object and the regular object will refer to the + same memory location for the variable. */ + + htab = or1k_elf_hash_table (info); + if (htab == NULL) + return FALSE; + + s = htab->sdynbss; + BFD_ASSERT (s != NULL); + + /* We must generate a R_OR1K_COPY reloc to tell the dynamic linker + to copy the initial value out of the dynamic object and into the + runtime process image. We need to remember the offset into the + .rela.bss section we are going to use. */ + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) + { + asection *srel; + + srel = htab->srelbss; + BFD_ASSERT (srel != NULL); + srel->size += sizeof (Elf32_External_Rela); + h->needs_copy = 1; + } + + return _bfd_elf_adjust_dynamic_copy (info, h, s); +} + +/* Allocate space in .plt, .got and associated reloc sections for + dynamic relocs. */ + +static bfd_boolean +allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) +{ + struct bfd_link_info *info; + struct elf_or1k_link_hash_table *htab; + struct elf_or1k_link_hash_entry *eh; + struct elf_or1k_dyn_relocs *p; + + if (h->root.type == bfd_link_hash_indirect) + return TRUE; + + info = (struct bfd_link_info *) inf; + htab = or1k_elf_hash_table (info); + if (htab == NULL) + return FALSE; + + eh = (struct elf_or1k_link_hash_entry *) h; + + if (htab->root.dynamic_sections_created + && h->plt.refcount > 0) + { + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h)) + { + asection *s = htab->splt; + + /* If this is the first .plt entry, make room for the special + first entry. */ + if (s->size == 0) + s->size = PLT_ENTRY_SIZE; + + h->plt.offset = s->size; + + /* If this symbol is not defined in a regular file, and we are + not generating a shared library, then set the symbol to this + location in the .plt. This is required to make function + pointers compare as equal between the normal executable and + the shared library. */ + if (! info->shared + && !h->def_regular) + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } + + /* Make room for this entry. */ + s->size += PLT_ENTRY_SIZE; + + /* We also need to make an entry in the .got.plt section, which + will be placed in the .got section by the linker script. */ + htab->sgotplt->size += 4; + + /* We also need to make an entry in the .rel.plt section. */ + htab->srelplt->size += sizeof (Elf32_External_Rela); + } + else + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + } + else + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + + if (h->got.refcount > 0) + { + asection *s; + bfd_boolean dyn; + unsigned char tls_type; + + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + s = htab->sgot; + + h->got.offset = s->size; + + tls_type = ((struct elf_or1k_link_hash_entry *) h)->tls_type; + + /* TLS GD requires two GOT and two relocs. */ + if (tls_type == TLS_GD) + s->size += 8; + else + s->size += 4; + dyn = htab->root.dynamic_sections_created; + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)) + { + if (tls_type == TLS_GD) + htab->srelgot->size += 2 * sizeof (Elf32_External_Rela); + else + htab->srelgot->size += sizeof (Elf32_External_Rela); + } + } + else + h->got.offset = (bfd_vma) -1; + + if (eh->dyn_relocs == NULL) + return TRUE; + + /* In the shared -Bsymbolic case, discard space allocated for + dynamic pc-relative relocs against symbols which turn out to be + defined in regular objects. For the normal shared case, discard + space for pc-relative relocs that have become local due to symbol + visibility changes. */ + + if (info->shared) + { + if (SYMBOL_CALLS_LOCAL (info, h)) + { + struct elf_or1k_dyn_relocs **pp; + + for (pp = &eh->dyn_relocs; (p = *pp) != NULL;) + { + p->count -= p->pc_count; + p->pc_count = 0; + if (p->count == 0) + *pp = p->next; + else + pp = &p->next; + } + } + + /* Also discard relocs on undefined weak syms with non-default + visibility. */ + if (eh->dyn_relocs != NULL + && h->root.type == bfd_link_hash_undefweak) + { + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + eh->dyn_relocs = NULL; + + /* Make sure undefined weak symbols are output as a dynamic + symbol in PIEs. */ + else if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + } + } + else + { + /* For the non-shared case, discard space for relocs against + symbols which turn out to need copy relocs or are not + dynamic. */ + + if (!h->non_got_ref + && ((h->def_dynamic + && !h->def_regular) + || (htab->root.dynamic_sections_created + && (h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined)))) + { + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + /* If that succeeded, we know we'll be keeping all the + relocs. */ + if (h->dynindx != -1) + goto keep; + } + + eh->dyn_relocs = NULL; + + keep: ; + } + + /* Finally, allocate space. */ + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + asection *sreloc = elf_section_data (p->sec)->sreloc; + sreloc->size += p->count * sizeof (Elf32_External_Rela); + } + + return TRUE; +} + +/* Find any dynamic relocs that apply to read-only sections. */ + +static bfd_boolean +readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf) +{ + struct elf_or1k_link_hash_entry *eh; + struct elf_or1k_dyn_relocs *p; + + eh = (struct elf_or1k_link_hash_entry *) h; + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + asection *s = p->sec->output_section; + + if (s != NULL && (s->flags & SEC_READONLY) != 0) + { + struct bfd_link_info *info = (struct bfd_link_info *) inf; + + info->flags |= DF_TEXTREL; + + /* Not an error, just cut short the traversal. */ + return FALSE; + } + } + return TRUE; +} + +/* Set the sizes of the dynamic sections. */ + +static bfd_boolean +or1k_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) +{ + struct elf_or1k_link_hash_table *htab; + bfd *dynobj; + asection *s; + bfd_boolean relocs; + bfd *ibfd; + + htab = or1k_elf_hash_table (info); + if (htab == NULL) + return FALSE; + + dynobj = htab->root.dynobj; + BFD_ASSERT (dynobj != NULL); + + if (htab->root.dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (info->executable) + { + s = bfd_get_section_by_name (dynobj, ".interp"); + BFD_ASSERT (s != NULL); + s->size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + } + } + + /* Set up .got offsets for local syms, and space for local dynamic + relocs. */ + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + bfd_signed_vma *local_got; + bfd_signed_vma *end_local_got; + bfd_size_type locsymcount; + Elf_Internal_Shdr *symtab_hdr; + unsigned char *local_tls_type; + asection *srel; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) + continue; + + for (s = ibfd->sections; s != NULL; s = s->next) + { + struct elf_or1k_dyn_relocs *p; + + for (p = ((struct elf_or1k_dyn_relocs *) + elf_section_data (s)->local_dynrel); + p != NULL; + p = p->next) + { + if (! bfd_is_abs_section (p->sec) + && bfd_is_abs_section (p->sec->output_section)) + { + /* Input section has been discarded, either because + it is a copy of a linkonce section or due to + linker script /DISCARD/, so we'll be discarding + the relocs too. */ + } + else if (p->count != 0) + { + srel = elf_section_data (p->sec)->sreloc; + srel->size += p->count * sizeof (Elf32_External_Rela); + if ((p->sec->output_section->flags & SEC_READONLY) != 0) + info->flags |= DF_TEXTREL; + } + } + } + + local_got = elf_local_got_refcounts (ibfd); + if (!local_got) + continue; + + symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; + locsymcount = symtab_hdr->sh_info; + end_local_got = local_got + locsymcount; + s = htab->sgot; + srel = htab->srelgot; + local_tls_type = (unsigned char *) elf_or1k_local_tls_type (ibfd); + for (; local_got < end_local_got; ++local_got) + { + if (*local_got > 0) + { + *local_got = s->size; + + /* TLS GD requires two GOT and two relocs. */ + if (local_tls_type != NULL && *local_tls_type == TLS_GD) + s->size += 8; + else + s->size += 4; + if (info->shared) + { + if (local_tls_type != NULL && *local_tls_type == TLS_GD) + srel->size += 2 * sizeof (Elf32_External_Rela); + else + srel->size += sizeof (Elf32_External_Rela); + } + } + else + + *local_got = (bfd_vma) -1; + + if (local_tls_type) + ++local_tls_type; + } + } + + /* Allocate global sym .plt and .got entries, and space for global + sym dynamic relocs. */ + elf_link_hash_traverse (&htab->root, allocate_dynrelocs, info); + + /* We now have determined the sizes of the various dynamic sections. + Allocate memory for them. */ + relocs = FALSE; + for (s = dynobj->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_LINKER_CREATED) == 0) + continue; + + if (s == htab->splt + || s == htab->sgot + || s == htab->sgotplt + || s == htab->sdynbss) + { + /* Strip this section if we don't need it; see the + comment below. */ + } + else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) + { + if (s->size != 0 && s != htab->srelplt) + relocs = TRUE; + + /* We use the reloc_count field as a counter if we need + to copy relocs into the output file. */ + s->reloc_count = 0; + } + else + /* It's not one of our sections, so don't allocate space. */ + continue; + + if (s->size == 0) + { + /* If we don't need this section, strip it from the + output file. This is mostly to handle .rela.bss and + .rela.plt. We must create both sections in + create_dynamic_sections, because they must be created + before the linker maps input sections to output + sections. The linker does that before + adjust_dynamic_symbol is called, and it is that + function which decides whether anything needs to go + into these sections. */ + s->flags |= SEC_EXCLUDE; + continue; + } + + if ((s->flags & SEC_HAS_CONTENTS) == 0) + continue; + + /* Allocate memory for the section contents. We use bfd_zalloc + here in case unused entries are not reclaimed before the + section's contents are written out. This should not happen, + but this way if it does, we get a R_OR1K_NONE reloc instead + of garbage. */ + s->contents = bfd_zalloc (dynobj, s->size); + + if (s->contents == NULL) + return FALSE; + } + + if (htab->root.dynamic_sections_created) + { + /* Add some entries to the .dynamic section. We fill in the + values later, in or1k_elf_finish_dynamic_sections, but we + must add the entries now so that we get the correct size for + the .dynamic section. The DT_DEBUG entry is filled in by the + dynamic linker and used by the debugger. */ +#define add_dynamic_entry(TAG, VAL) \ + _bfd_elf_add_dynamic_entry (info, TAG, VAL) + + if (info->executable) + { + if (! add_dynamic_entry (DT_DEBUG, 0)) + return FALSE; + } + + if (htab->splt->size != 0) + { + if (! add_dynamic_entry (DT_PLTGOT, 0) + || ! add_dynamic_entry (DT_PLTRELSZ, 0) + || ! add_dynamic_entry (DT_PLTREL, DT_RELA) + || ! add_dynamic_entry (DT_JMPREL, 0)) + return FALSE; + } + + if (relocs) + { + if (! add_dynamic_entry (DT_RELA, 0) + || ! add_dynamic_entry (DT_RELASZ, 0) + || ! add_dynamic_entry (DT_RELAENT, + sizeof (Elf32_External_Rela))) + return FALSE; + + /* If any dynamic relocs apply to a read-only section, + then we need a DT_TEXTREL entry. */ + if ((info->flags & DF_TEXTREL) == 0) + elf_link_hash_traverse (&htab->root, readonly_dynrelocs, + info); + + if ((info->flags & DF_TEXTREL) != 0) + { + if (! add_dynamic_entry (DT_TEXTREL, 0)) + return FALSE; + } + } + } + +#undef add_dynamic_entry + return TRUE; +} + +/* Create dynamic sections when linking against a dynamic object. */ + +static bfd_boolean +or1k_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) +{ + struct elf_or1k_link_hash_table *htab; + + htab = or1k_elf_hash_table (info); + if (htab == NULL) + return FALSE; + + if (!htab->sgot && !create_got_section (dynobj, info)) + return FALSE; + + if (!_bfd_elf_create_dynamic_sections (dynobj, info)) + return FALSE; + + htab->splt = bfd_get_section_by_name (dynobj, ".plt"); + htab->srelplt = bfd_get_section_by_name (dynobj, ".rela.plt"); + htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss"); + if (!info->shared) + htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss"); + + if (!htab->splt || !htab->srelplt || !htab->sdynbss + || (!info->shared && !htab->srelbss)) + abort (); + + return TRUE; +} + +/* Copy the extra info we tack onto an elf_link_hash_entry. */ + +static void +or1k_elf_copy_indirect_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *dir, + struct elf_link_hash_entry *ind) +{ + struct elf_or1k_link_hash_entry * edir; + struct elf_or1k_link_hash_entry * eind; + + edir = (struct elf_or1k_link_hash_entry *) dir; + eind = (struct elf_or1k_link_hash_entry *) ind; + + if (eind->dyn_relocs != NULL) + { + if (edir->dyn_relocs != NULL) + { + struct elf_or1k_dyn_relocs **pp; + struct elf_or1k_dyn_relocs *p; + + /* Add reloc counts against the indirect sym to the direct sym + list. Merge any entries against the same section. */ + for (pp = &eind->dyn_relocs; (p = *pp) != NULL;) + { + struct elf_or1k_dyn_relocs *q; + + for (q = edir->dyn_relocs; q != NULL; q = q->next) + if (q->sec == p->sec) + { + q->pc_count += p->pc_count; + q->count += p->count; + *pp = p->next; + break; + } + if (q == NULL) + pp = &p->next; + } + *pp = edir->dyn_relocs; + } + + edir->dyn_relocs = eind->dyn_relocs; + eind->dyn_relocs = NULL; + } + + if (ind->root.type == bfd_link_hash_indirect) + { + if (dir->got.refcount <= 0) + { + edir->tls_type = eind->tls_type; + eind->tls_type = TLS_UNKNOWN; + } + } + + _bfd_elf_link_hash_copy_indirect (info, dir, ind); +} + +/* Set the right machine number. */ + +static bfd_boolean +or1k_elf_object_p (bfd *abfd) +{ + unsigned long mach = bfd_mach_or1k; + + if (elf_elfheader (abfd)->e_flags & EF_OR1K_NODELAY) + mach = bfd_mach_or1knd; + + return bfd_default_set_arch_mach (abfd, bfd_arch_or1k, mach); +} + +/* Store the machine number in the flags field. */ + +static void +or1k_elf_final_write_processing (bfd *abfd, + bfd_boolean linker ATTRIBUTE_UNUSED) +{ + switch (bfd_get_mach (abfd)) + { + default: + case bfd_mach_or1k: + break; + case bfd_mach_or1knd: + elf_elfheader (abfd)->e_flags |= EF_OR1K_NODELAY; + break; + } +} + +static bfd_boolean +or1k_elf_set_private_flags (bfd *abfd, flagword flags) +{ + BFD_ASSERT (!elf_flags_init (abfd) + || elf_elfheader (abfd)->e_flags == flags); + + elf_elfheader (abfd)->e_flags = flags; + elf_flags_init (abfd) = TRUE; + return TRUE; +} + +/* Make sure all input files are consistent with respect to + EF_OR1K_NODELAY flag setting. */ + +static bfd_boolean +elf32_or1k_merge_private_bfd_data (bfd *ibfd, bfd *obfd) +{ + flagword out_flags; + flagword in_flags; + + in_flags = elf_elfheader (ibfd)->e_flags; + out_flags = elf_elfheader (obfd)->e_flags; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return TRUE; + + if (!elf_flags_init (obfd)) + { + elf_flags_init (obfd) = TRUE; + elf_elfheader (obfd)->e_flags = in_flags; + + return TRUE; + } + + if (in_flags == out_flags) + return TRUE; + + if ((in_flags & EF_OR1K_NODELAY) != (out_flags & EF_OR1K_NODELAY)) + { + (*_bfd_error_handler) + (_("%B: EF_OR1K_NODELAY flag mismatch with previous modules"), ibfd); + + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + return TRUE; + +} + +#define ELF_ARCH bfd_arch_or1k +#define ELF_MACHINE_CODE EM_OR1K +#define ELF_TARGET_ID OR1K_ELF_DATA +#define ELF_MAXPAGESIZE 0x2000 + +#define TARGET_BIG_SYM or1k_elf32_vec +#define TARGET_BIG_NAME "elf32-or1k" + +#define elf_info_to_howto_rel NULL +#define elf_info_to_howto or1k_info_to_howto_rela +#define elf_backend_relocate_section or1k_elf_relocate_section +#define elf_backend_gc_mark_hook or1k_elf_gc_mark_hook +#define elf_backend_gc_sweep_hook or1k_elf_gc_sweep_hook +#define elf_backend_check_relocs or1k_elf_check_relocs +#define elf_backend_reloc_type_class or1k_elf_reloc_type_class +#define elf_backend_can_gc_sections 1 +#define elf_backend_rela_normal 1 + +#define bfd_elf32_mkobject elf_or1k_mkobject + +#define bfd_elf32_bfd_merge_private_bfd_data elf32_or1k_merge_private_bfd_data +#define bfd_elf32_bfd_set_private_flags or1k_elf_set_private_flags +#define bfd_elf32_bfd_reloc_type_lookup or1k_reloc_type_lookup +#define bfd_elf32_bfd_reloc_name_lookup or1k_reloc_name_lookup + +#define elf_backend_object_p or1k_elf_object_p +#define elf_backend_final_write_processing or1k_elf_final_write_processing +#define elf_backend_can_refcount 1 + +#define elf_backend_plt_readonly 1 +#define elf_backend_want_got_plt 1 +#define elf_backend_want_plt_sym 0 +#define elf_backend_got_header_size 12 +#define bfd_elf32_bfd_link_hash_table_create or1k_elf_link_hash_table_create +#define elf_backend_copy_indirect_symbol or1k_elf_copy_indirect_symbol +#define elf_backend_create_dynamic_sections or1k_elf_create_dynamic_sections +#define elf_backend_finish_dynamic_sections or1k_elf_finish_dynamic_sections +#define elf_backend_size_dynamic_sections or1k_elf_size_dynamic_sections +#define elf_backend_adjust_dynamic_symbol or1k_elf_adjust_dynamic_symbol +#define elf_backend_finish_dynamic_symbol or1k_elf_finish_dynamic_symbol + +#include "elf32-target.h" diff --git a/contrib/gdb-7/bfd/elf32.c b/contrib/gdb-7/bfd/elf32-rx.h similarity index 71% copy from contrib/gdb-7/bfd/elf32.c copy to contrib/gdb-7/bfd/elf32-rx.h index 98dacc1f36..465942665c 100644 --- a/contrib/gdb-7/bfd/elf32.c +++ b/contrib/gdb-7/bfd/elf32-rx.h @@ -1,6 +1,5 @@ -/* ELF 32-bit executable support for BFD. - Copyright 1993, 2001, 2004, 2005, 2006, 2007, 2008, 2009 - Free Software Foundation, Inc. +/* Renesas RX specific support for 32-bit ELF. + Copyright (C) 2014-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -16,9 +15,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#define ARCH_SIZE 32 -#include "elfcode.h" +void rx_additional_link_map_text (bfd *obfd, struct bfd_link_info *info, FILE *mapfile); diff --git a/contrib/gdb-7/bfd/elf32-visium.c b/contrib/gdb-7/bfd/elf32-visium.c new file mode 100644 index 0000000000..d6256f6301 --- /dev/null +++ b/contrib/gdb-7/bfd/elf32-visium.c @@ -0,0 +1,903 @@ +/* Visium-specific support for 32-bit ELF. + + Copyright (C) 2003-2015 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 "sysdep.h" +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/visium.h" + +static bfd_reloc_status_type visium_elf_howto_parity_reloc + (bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **); + +static reloc_howto_type visium_elf_howto_table[] = { + /* This reloc does nothing. */ + HOWTO (R_VISIUM_NONE, /* type */ + 0, /* rightshift */ + 3, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_VISIUM_NONE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 8 bit absolute relocation. */ + HOWTO (R_VISIUM_8, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_VISIUM_8", /* name */ + FALSE, /* partial_inplace */ + 0x00, /* src_mask */ + 0xff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 16 bit absolute relocation. */ + HOWTO (R_VISIUM_16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_VISIUM_16", /* name */ + FALSE, /* partial_inplace */ + 0x0000, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 32 bit absolute relocation. */ + HOWTO (R_VISIUM_32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_VISIUM_32", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + + /* A 8 bit PC relative relocation. */ + HOWTO (R_VISIUM_8_PCREL, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_VISIUM_8_PCREL", /* name */ + FALSE, /* partial_inplace */ + 0x00, /* src_mask */ + 0xff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A 16 bit PC relative relocation. */ + HOWTO (R_VISIUM_16_PCREL, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_VISIUM_16_PCREL", /* name */ + FALSE, /* partial inplace */ + 0x0000, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A 32-bit PC relative relocation. */ + HOWTO (R_VISIUM_32_PCREL, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_VISIUM_32_PCREL", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A 16-bit PC word relative offset, relative to start of instruction + and always in the second half of the instruction. */ + HOWTO (R_VISIUM_PC16, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + visium_elf_howto_parity_reloc, /* special_function */ + "R_VISIUM_PC16", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x0000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* The high 16 bits of symbol value. */ + HOWTO (R_VISIUM_HI16, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + visium_elf_howto_parity_reloc, /* special_function */ + "R_VISIUM_HI16", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* The low 16 bits of symbol value. */ + HOWTO (R_VISIUM_LO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + visium_elf_howto_parity_reloc, /* special_function */ + "R_VISIUM_LO16", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 16 bit immediate value. */ + HOWTO (R_VISIUM_IM16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + visium_elf_howto_parity_reloc, /* special_function */ + "R_VISIUM_IM16", /* name */ + FALSE, /* partial_inplace */ + 0x0000000, /* src_mask */ + 0x000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* The high 16 bits of symbol value, pc relative. */ + HOWTO (R_VISIUM_HI16_PCREL, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + visium_elf_howto_parity_reloc, /* special_function */ + "R_VISIUM_HI16_PCREL", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x0000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* The low 16 bits of symbol value, pc relative. */ + HOWTO (R_VISIUM_LO16_PCREL, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + visium_elf_howto_parity_reloc, /* special_function */ + "R_VISIUM_LO16_PCREL", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x0000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A 16 bit immediate value, pc relative. */ + HOWTO (R_VISIUM_IM16_PCREL, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + visium_elf_howto_parity_reloc, /* special_function */ + "R_VISIUM_IM16_PCREL", /* name */ + FALSE, /* partial_inplace */ + 0x0000000, /* src_mask */ + 0x000ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + +}; + +/* GNU extension to record C++ vtable hierarchy. */ +static reloc_howto_type visium_elf_vtinherit_howto = + HOWTO (R_VISIUM_GNU_VTINHERIT, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + NULL, /* special_function */ + "R_VISIUM_GNU_VTINHERIT", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE); /* pcrel_offset */ + +/* GNU extension to record C++ vtable member usage. */ +static reloc_howto_type visium_elf_vtentry_howto = + HOWTO (R_VISIUM_GNU_VTENTRY, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + NULL, /* special_function */ + "R_VISIUM_GNU_VTENTRY", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE); /* pcrel_offset */ + +/* Map BFD reloc types to VISIUM ELF reloc types. */ +struct visium_reloc_map +{ + bfd_reloc_code_real_type bfd_reloc_val; + unsigned int visium_reloc_val; +}; + +static const struct visium_reloc_map visium_reloc_map[] = { + {BFD_RELOC_NONE, R_VISIUM_NONE}, + {BFD_RELOC_8, R_VISIUM_8}, + {BFD_RELOC_16, R_VISIUM_16}, + {BFD_RELOC_32, R_VISIUM_32}, + {BFD_RELOC_8_PCREL, R_VISIUM_8_PCREL}, + {BFD_RELOC_16_PCREL, R_VISIUM_16_PCREL}, + {BFD_RELOC_32_PCREL, R_VISIUM_32_PCREL}, + {BFD_RELOC_VISIUM_REL16, R_VISIUM_PC16}, + {BFD_RELOC_VISIUM_HI16, R_VISIUM_HI16}, + {BFD_RELOC_VISIUM_LO16, R_VISIUM_LO16}, + {BFD_RELOC_VISIUM_IM16, R_VISIUM_IM16}, + {BFD_RELOC_VISIUM_HI16_PCREL, R_VISIUM_HI16_PCREL}, + {BFD_RELOC_VISIUM_LO16_PCREL, R_VISIUM_LO16_PCREL}, + {BFD_RELOC_VISIUM_IM16_PCREL, R_VISIUM_IM16_PCREL}, + {BFD_RELOC_VTABLE_INHERIT, R_VISIUM_GNU_VTINHERIT}, + {BFD_RELOC_VTABLE_ENTRY, R_VISIUM_GNU_VTENTRY}, +}; + +/* Return the parity bit for INSN shifted to its final position. */ + +static bfd_vma +visium_parity_bit (bfd_vma insn) +{ + bfd_vma p = 0; + int i; + + for (i = 0; i < 31; i++) + { + p ^= (insn & 1); + insn >>= 1; + } + + return p << 31; +} + +/* This "special function" will only be used when the input and + output files have different formats ie. when generating S-records + directly using "--oformat srec". Otherwise we use + _bfd_final_link_relocate which uses a howto structure, but does + not use the special_function field. + + It sets instruction parity to even. This cannot be done by a howto. */ + +static bfd_reloc_status_type +visium_elf_howto_parity_reloc (bfd * input_bfd, arelent *reloc_entry, + asymbol *symbol, PTR data, + asection *input_section, bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + bfd_reloc_status_type ret; + bfd_vma relocation; + bfd_byte *inplace_address; + bfd_vma insn; + const bfd_vma signmask = 0xffff8000; + + /* This part is from bfd_elf_generic_reloc. + If we're relocating, and this an external symbol, we don't want + to change anything. */ + if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* Now do the reloc in the usual way. */ + + /* Sanity check the address (offset in section). */ + if (reloc_entry->address > bfd_get_section_limit (input_bfd, input_section)) + return bfd_reloc_outofrange; + + ret = bfd_reloc_ok; + if (bfd_is_und_section (symbol->section) && output_bfd == (bfd *) NULL) + ret = bfd_reloc_undefined; + + if (bfd_is_com_section (symbol->section) || output_bfd != (bfd *) NULL) + relocation = 0; + else + relocation = symbol->value; + + /* Only do this for a final link. */ + if (output_bfd == (bfd *) NULL) + { + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + } + + relocation += reloc_entry->addend; + inplace_address = (bfd_byte *) data + reloc_entry->address; + insn = bfd_get_32 (input_bfd, inplace_address); + + if (reloc_entry->howto->pc_relative) + { + relocation -= input_section->output_section->vma + + input_section->output_offset; + relocation -= reloc_entry->address; + } + + switch (reloc_entry->howto->type) + { + case R_VISIUM_PC16: + relocation >>= 2; + if (ret == bfd_reloc_ok && (relocation & signmask) != 0 + && (relocation & signmask) != signmask) + ret = bfd_reloc_overflow; + relocation &= 0xffff; + break; + case R_VISIUM_HI16: + case R_VISIUM_HI16_PCREL: + relocation = (relocation >> 16) & 0xffff; + break; + case R_VISIUM_LO16: + case R_VISIUM_LO16_PCREL: + relocation &= 0xffff; + break; + case R_VISIUM_IM16: + case R_VISIUM_IM16_PCREL: + if (ret == bfd_reloc_ok && (relocation & 0xffff0000) != 0) + ret = bfd_reloc_overflow; + relocation &= 0xffff; + break; + } + insn = (insn & 0x7fff0000) | relocation; + insn |= visium_parity_bit (insn); + bfd_put_32 (input_bfd, insn, inplace_address); + + if (output_bfd != (bfd *) NULL) + reloc_entry->address += input_section->output_offset; + + return ret; +} + +static reloc_howto_type * +visium_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) +{ + /* Note that the visium_elf_howto_table is indexed by the R_ + constants. Thus, the order that the howto records appear in the + table *must* match the order of the relocation types defined in + include/elf/visium.h. */ + switch (code) + { + case BFD_RELOC_NONE: + return &visium_elf_howto_table[(int) R_VISIUM_NONE]; + case BFD_RELOC_8: + return &visium_elf_howto_table[(int) R_VISIUM_8]; + case BFD_RELOC_16: + return &visium_elf_howto_table[(int) R_VISIUM_16]; + case BFD_RELOC_32: + return &visium_elf_howto_table[(int) R_VISIUM_32]; + case BFD_RELOC_8_PCREL: + return &visium_elf_howto_table[(int) R_VISIUM_8_PCREL]; + case BFD_RELOC_16_PCREL: + return &visium_elf_howto_table[(int) R_VISIUM_16_PCREL]; + case BFD_RELOC_32_PCREL: + return &visium_elf_howto_table[(int) R_VISIUM_32_PCREL]; + case BFD_RELOC_VISIUM_REL16: + return &visium_elf_howto_table[(int) R_VISIUM_PC16]; + case BFD_RELOC_VISIUM_HI16: + return &visium_elf_howto_table[(int) R_VISIUM_HI16]; + case BFD_RELOC_VISIUM_LO16: + return &visium_elf_howto_table[(int) R_VISIUM_LO16]; + case BFD_RELOC_VISIUM_IM16: + return &visium_elf_howto_table[(int) R_VISIUM_IM16]; + case BFD_RELOC_VISIUM_HI16_PCREL: + return &visium_elf_howto_table[(int) R_VISIUM_HI16_PCREL]; + case BFD_RELOC_VISIUM_LO16_PCREL: + return &visium_elf_howto_table[(int) R_VISIUM_LO16_PCREL]; + case BFD_RELOC_VISIUM_IM16_PCREL: + return &visium_elf_howto_table[(int) R_VISIUM_IM16_PCREL]; + case BFD_RELOC_VTABLE_INHERIT: + return &visium_elf_vtinherit_howto; + case BFD_RELOC_VTABLE_ENTRY: + return &visium_elf_vtentry_howto; + default: + return NULL; + } +} + +static reloc_howto_type * +visium_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) +{ + unsigned int i; + + for (i = 0; + i < (sizeof (visium_elf_howto_table) + / sizeof (visium_elf_howto_table[0])); i++) + if (visium_elf_howto_table[i].name != NULL + && strcasecmp (visium_elf_howto_table[i].name, r_name) == 0) + return &visium_elf_howto_table[i]; + + if (strcasecmp (visium_elf_vtinherit_howto.name, r_name) == 0) + return &visium_elf_vtinherit_howto; + if (strcasecmp (visium_elf_vtentry_howto.name, r_name) == 0) + return &visium_elf_vtentry_howto; + + return NULL; +} + +/* Set the howto pointer for a VISIUM ELF reloc. */ + +static void +visium_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, + Elf_Internal_Rela *dst) +{ + unsigned int r_type = ELF32_R_TYPE (dst->r_info); + + switch (r_type) + { + case R_VISIUM_GNU_VTINHERIT: + cache_ptr->howto = &visium_elf_vtinherit_howto; + break; + + case R_VISIUM_GNU_VTENTRY: + cache_ptr->howto = &visium_elf_vtentry_howto; + break; + + default: + if (r_type >= (unsigned int) R_VISIUM_max) + { + _bfd_error_handler (_("%B: invalid Visium reloc number: %d"), abfd, r_type); + r_type = 0; + } + cache_ptr->howto = &visium_elf_howto_table[r_type]; + break; + } +} + +/* Look through the relocs for a section during the first phase. + Since we don't do .gots or .plts, we just need to consider the + virtual table relocs for gc. */ + +static bfd_boolean +visium_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, + asection *sec, const Elf_Internal_Rela *relocs) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + + if (info->relocatable) + return TRUE; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + struct elf_link_hash_entry *h; + unsigned long r_symndx; + + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + } + + switch (ELF32_R_TYPE (rel->r_info)) + { + /* This relocation describes the C++ object vtable hierarchy. + Reconstruct it for later use during GC. */ + case R_VISIUM_GNU_VTINHERIT: + if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) + return FALSE; + break; + + /* This relocation describes which C++ vtable entries are actually + used. Record for later use during GC. */ + case R_VISIUM_GNU_VTENTRY: + if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) + return FALSE; + break; + } + } + + return TRUE; +} + +/* Relocate a VISIUM ELF section. */ + +static bfd_boolean +visium_elf_relocate_section (bfd *output_bfd, + struct bfd_link_info *info, bfd *input_bfd, + asection *input_section, bfd_byte *contents, + Elf_Internal_Rela *relocs, + Elf_Internal_Sym *local_syms, + asection **local_sections) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + relend = relocs + input_section->reloc_count; + + for (rel = relocs; rel < relend; rel++) + { + reloc_howto_type *howto; + unsigned long r_symndx; + Elf_Internal_Sym *sym; + asection *sec; + struct elf_link_hash_entry *h; + bfd_vma relocation; + bfd_reloc_status_type r; + const char *name = NULL; + int r_type; + bfd_vma insn; + + r_type = ELF32_R_TYPE (rel->r_info); + + if (r_type == R_VISIUM_GNU_VTINHERIT || r_type == R_VISIUM_GNU_VTENTRY) + continue; + + r_symndx = ELF32_R_SYM (rel->r_info); + + howto = visium_elf_howto_table + ELF32_R_TYPE (rel->r_info); + h = NULL; + sym = NULL; + sec = NULL; + + if (r_symndx < symtab_hdr->sh_info) + { + /* This is a local symbol. */ + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); + name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; + } + else + { + bfd_boolean unresolved_reloc; + bfd_boolean warned, ignored; + + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, + r_symndx, symtab_hdr, sym_hashes, + h, sec, relocation, + unresolved_reloc, warned, ignored); + + name = h->root.root.string; + } + + if (sec != NULL && discarded_section (sec)) + { + /* For relocs against symbols from removed linkonce sections, + or sections discarded by a linker script, we just want the + section contents zeroed. Avoid any special processing. */ + _bfd_clear_contents (howto, input_bfd, input_section, + contents + rel->r_offset); + + rel->r_info = 0; + rel->r_addend = 0; + continue; + } + + if (info->relocatable) + continue; + + switch (r_type) + { + case R_VISIUM_PC16: + case R_VISIUM_HI16: + case R_VISIUM_LO16: + case R_VISIUM_IM16: + case R_VISIUM_HI16_PCREL: + case R_VISIUM_LO16_PCREL: + case R_VISIUM_IM16_PCREL: + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + + /* For instruction relocations, the parity needs correcting. */ + if (r == bfd_reloc_ok) + { + insn = bfd_get_32 (input_bfd, contents + rel->r_offset); + insn = (insn & 0x7fffffff) | visium_parity_bit (insn); + bfd_put_32 (input_bfd, insn, contents + rel->r_offset); + } + break; + + default: + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + } + + if (r != bfd_reloc_ok) + { + const char *msg = (const char *) NULL; + + switch (r) + { + case bfd_reloc_overflow: + r = info->callbacks->reloc_overflow + (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset); + break; + + case bfd_reloc_undefined: + r = info->callbacks->undefined_symbol + (info, name, input_bfd, input_section, rel->r_offset, TRUE); + break; + + case bfd_reloc_outofrange: + msg = _("internal error: out of range error"); + break; + + case bfd_reloc_notsupported: + msg = _("internal error: unsupported relocation error"); + break; + + case bfd_reloc_dangerous: + msg = _("internal error: dangerous relocation"); + break; + + default: + msg = _("internal error: unknown error"); + break; + } + + if (msg) + r = info->callbacks->warning + (info, msg, name, input_bfd, input_section, rel->r_offset); + + if (!r) + return FALSE; + } + } + + return TRUE; +} + +/* This function is called during section gc to discover the section a + to which a particular relocation refers. Return the section that + should be marked against GC for a given relocation. */ + +static asection * +visium_elf_gc_mark_hook (asection *sec, struct bfd_link_info *info, + Elf_Internal_Rela *rel, struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) +{ + if (h != NULL) + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_VISIUM_GNU_VTINHERIT: + case R_VISIUM_GNU_VTENTRY: + return NULL; + } + + return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); +} + +static void +visium_elf_post_process_headers (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); + i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_STANDALONE; + i_ehdrp->e_ident[EI_ABIVERSION] = 1; +} + +/* Function to set the ELF flag bits. */ + +static bfd_boolean +visium_elf_set_private_flags (bfd *abfd, flagword flags) +{ + elf_elfheader (abfd)->e_flags = flags; + elf_flags_init (abfd) = TRUE; + return TRUE; +} + +/* Copy backend specific data from one object module to another. */ + +static bfd_boolean +visium_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) +{ + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return TRUE; + + BFD_ASSERT (!elf_flags_init (obfd) + || elf_elfheader (obfd)->e_flags == + elf_elfheader (ibfd)->e_flags); + + elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; + elf_flags_init (obfd) = TRUE; + + /* Copy object attributes. */ + _bfd_elf_copy_obj_attributes (ibfd, obfd); + + return TRUE; +} + +/* Merge backend specific data from an object + file to the output object file when linking. */ + +static bfd_boolean +visium_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) +{ + flagword old_flags; + flagword new_flags; + flagword mismatch; + const char *opt_arch = NULL; + const char *new_opt_with = NULL; + const char *old_opt_with = NULL; + const char *with = "with"; + const char *without = "without"; + const char *mcm = "mcm"; + const char *mcm24 = "mcm24"; + const char *gr6 = "gr6"; + + new_flags = elf_elfheader (ibfd)->e_flags; + old_flags = elf_elfheader (obfd)->e_flags; + + if (!elf_flags_init (obfd)) + { + /* First call, no flags set. */ + elf_flags_init (obfd) = TRUE; + elf_elfheader (obfd)->e_flags = new_flags; + } + else + { + mismatch = (new_flags ^ old_flags) + & (EF_VISIUM_ARCH_MCM | EF_VISIUM_ARCH_MCM24 | EF_VISIUM_ARCH_GR6); + if (mismatch & EF_VISIUM_ARCH_GR6) + { + opt_arch = gr6; + new_opt_with = new_flags & EF_VISIUM_ARCH_GR6 ? with : without; + old_opt_with = old_flags & EF_VISIUM_ARCH_GR6 ? with : without; + } + else if (mismatch & EF_VISIUM_ARCH_MCM) + { + opt_arch = mcm; + new_opt_with = new_flags & EF_VISIUM_ARCH_MCM ? with : without; + old_opt_with = old_flags & EF_VISIUM_ARCH_MCM ? with : without; + } + else if (mismatch & EF_VISIUM_ARCH_MCM24) + { + opt_arch = mcm24; + new_opt_with = new_flags & EF_VISIUM_ARCH_MCM24 ? with : without; + old_opt_with = old_flags & EF_VISIUM_ARCH_MCM24 ? with : without; + } + + if (mismatch) + _bfd_error_handler + (_ + ("%s: compiled %s -mtune=%s and linked with modules" + " compiled %s -mtune=%s"), + bfd_get_filename (ibfd), new_opt_with, opt_arch, old_opt_with, + opt_arch); + } + + return TRUE; +} + +static bfd_boolean +visium_elf_print_private_bfd_data (bfd *abfd, void *ptr) +{ + FILE *file = (FILE *) ptr; + flagword flags; + + BFD_ASSERT (abfd != NULL && ptr != NULL); + + /* Print normal ELF private data. */ + _bfd_elf_print_private_bfd_data (abfd, ptr); + + flags = elf_elfheader (abfd)->e_flags; + fprintf (file, _("private flags = 0x%lx:"), (long) flags); + + if (flags & EF_VISIUM_ARCH_GR6) + fprintf (file, " -mtune=gr6"); + else if (flags & EF_VISIUM_ARCH_MCM) + fprintf (file, " -mtune=mcm"); + else if (flags & EF_VISIUM_ARCH_MCM24) + fprintf (file, " -mtune=mcm24"); + + fputc ('\n', file); + return TRUE; +} + +#define ELF_ARCH bfd_arch_visium +#define ELF_MACHINE_CODE EM_VISIUM +#define ELF_MAXPAGESIZE 1 + +#define TARGET_BIG_SYM visium_elf32_vec +#define TARGET_BIG_NAME "elf32-visium" + +#define elf_info_to_howto_rel NULL +#define elf_info_to_howto visium_info_to_howto_rela +#define elf_backend_relocate_section visium_elf_relocate_section +#define elf_backend_gc_mark_hook visium_elf_gc_mark_hook +#define elf_backend_check_relocs visium_elf_check_relocs +#define elf_backend_rela_normal 1 + +#define elf_backend_can_gc_sections 1 + +#define bfd_elf32_bfd_reloc_type_lookup visium_reloc_type_lookup +#define bfd_elf32_bfd_reloc_name_lookup visium_reloc_name_lookup + +#define bfd_elf32_bfd_set_private_flags visium_elf_set_private_flags +#define bfd_elf32_bfd_copy_private_bfd_data visium_elf_copy_private_bfd_data +#define bfd_elf32_bfd_merge_private_bfd_data visium_elf_merge_private_bfd_data +#define bfd_elf32_bfd_print_private_bfd_data visium_elf_print_private_bfd_data +#define elf_backend_post_process_headers visium_elf_post_process_headers + +#include "elf32-target.h" diff --git a/contrib/gdb-7/bfd/elf32.c b/contrib/gdb-7/bfd/elf32.c index 98dacc1f36..e9c5e57919 100644 --- a/contrib/gdb-7/bfd/elf32.c +++ b/contrib/gdb-7/bfd/elf32.c @@ -1,6 +1,5 @@ /* ELF 32-bit executable support for BFD. - Copyright 1993, 2001, 2004, 2005, 2006, 2007, 2008, 2009 - Free Software Foundation, Inc. + Copyright (C) 1993-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. diff --git a/contrib/gdb-7/bfd/elf64-gen.c b/contrib/gdb-7/bfd/elf64-gen.c index 1b0dadebe6..4a8a7c6ee1 100644 --- a/contrib/gdb-7/bfd/elf64-gen.c +++ b/contrib/gdb-7/bfd/elf64-gen.c @@ -1,6 +1,5 @@ /* Generic support for 64-bit ELF - Copyright 1993, 1995, 1998, 1999, 2001, 2002, 2004, 2005, 2007 - Free Software Foundation, Inc. + Copyright (C) 1993-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -87,9 +86,9 @@ elf64_generic_link_add_symbols (bfd *abfd, struct bfd_link_info *info) return bfd_elf_link_add_symbols (abfd, info); } -#define TARGET_LITTLE_SYM bfd_elf64_little_generic_vec +#define TARGET_LITTLE_SYM elf64_le_vec #define TARGET_LITTLE_NAME "elf64-little" -#define TARGET_BIG_SYM bfd_elf64_big_generic_vec +#define TARGET_BIG_SYM elf64_be_vec #define TARGET_BIG_NAME "elf64-big" #define ELF_ARCH bfd_arch_unknown #define ELF_MACHINE_CODE EM_NONE diff --git a/contrib/gdb-7/bfd/elf64-x86-64.c b/contrib/gdb-7/bfd/elf64-x86-64.c index 9406479d66..a4dfdc830c 100644 --- a/contrib/gdb-7/bfd/elf64-x86-64.c +++ b/contrib/gdb-7/bfd/elf64-x86-64.c @@ -1,7 +1,5 @@ /* X86-64 specific support for ELF - Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, - 2010, 2011, 2012 - Free Software Foundation, Inc. + Copyright (C) 2000-2015 Free Software Foundation, Inc. Contributed by Jan Hubicka . This file is part of BFD, the Binary File Descriptor library. @@ -56,7 +54,7 @@ special_function, name, partial_inplace, src_mask, dst_mask, pcrel_offset. */ static reloc_howto_type x86_64_elf_howto_table[] = { - HOWTO(R_X86_64_NONE, 0, 0, 0, FALSE, 0, complain_overflow_dont, + HOWTO(R_X86_64_NONE, 0, 3, 0, FALSE, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_X86_64_NONE", FALSE, 0x00000000, 0x00000000, FALSE), HOWTO(R_X86_64_64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, @@ -172,12 +170,18 @@ static reloc_howto_type x86_64_elf_howto_table[] = HOWTO(R_X86_64_RELATIVE64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_X86_64_RELATIVE64", FALSE, MINUS_ONE, MINUS_ONE, FALSE), + HOWTO(R_X86_64_PC32_BND, 0, 2, 32, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_PC32_BND", FALSE, 0xffffffff, 0xffffffff, + TRUE), + HOWTO(R_X86_64_PLT32_BND, 0, 2, 32, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_PLT32_BND", FALSE, 0xffffffff, 0xffffffff, + TRUE), /* We have a gap in the reloc numbers here. R_X86_64_standard counts the number up to this point, and R_X86_64_vt_offset is the value to subtract from a reloc type of R_X86_64_GNU_VT* to form an index into this table. */ -#define R_X86_64_standard (R_X86_64_RELATIVE64 + 1) +#define R_X86_64_standard (R_X86_64_PLT32_BND + 1) #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard) /* GNU extension to record C++ vtable hierarchy. */ @@ -199,6 +203,7 @@ static reloc_howto_type x86_64_elf_howto_table[] = ( ((TYPE) == R_X86_64_PC8) \ || ((TYPE) == R_X86_64_PC16) \ || ((TYPE) == R_X86_64_PC32) \ + || ((TYPE) == R_X86_64_PC32_BND) \ || ((TYPE) == R_X86_64_PC64)) /* Map BFD relocs to the x86_64 elf relocs. */ @@ -248,6 +253,8 @@ static const struct elf_reloc_map x86_64_reloc_map[] = { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, }, { BFD_RELOC_X86_64_TLSDESC, R_X86_64_TLSDESC, }, { BFD_RELOC_X86_64_IRELATIVE, R_X86_64_IRELATIVE, }, + { BFD_RELOC_X86_64_PC32_BND, R_X86_64_PC32_BND,}, + { BFD_RELOC_X86_64_PLT32_BND, R_X86_64_PLT32_BND,}, { BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, }, { BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, }, }; @@ -295,7 +302,7 @@ elf_x86_64_reloc_type_lookup (bfd *abfd, return elf_x86_64_rtype_to_howto (abfd, x86_64_reloc_map[i].elf_reloc_val); } - return 0; + return NULL; } static reloc_howto_type * @@ -553,6 +560,56 @@ static const bfd_byte elf_x86_64_plt_entry[PLT_ENTRY_SIZE] = 0, 0, 0, 0 /* replaced with offset to start of .plt0. */ }; +/* The first entry in a procedure linkage table with BND relocations + like this. */ + +static const bfd_byte elf_x86_64_bnd_plt0_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0x35, 8, 0, 0, 0, /* pushq GOT+8(%rip) */ + 0xf2, 0xff, 0x25, 16, 0, 0, 0, /* bnd jmpq *GOT+16(%rip) */ + 0x0f, 0x1f, 0 /* nopl (%rax) */ +}; + +/* Subsequent entries for legacy branches in a procedure linkage table + with BND relocations look like this. */ + +static const bfd_byte elf_x86_64_legacy_plt_entry[PLT_ENTRY_SIZE] = +{ + 0x68, 0, 0, 0, 0, /* pushq immediate */ + 0xe9, 0, 0, 0, 0, /* jmpq relative */ + 0x66, 0x0f, 0x1f, 0x44, 0, 0 /* nopw (%rax,%rax,1) */ +}; + +/* Subsequent entries for branches with BND prefx in a procedure linkage + table with BND relocations look like this. */ + +static const bfd_byte elf_x86_64_bnd_plt_entry[PLT_ENTRY_SIZE] = +{ + 0x68, 0, 0, 0, 0, /* pushq immediate */ + 0xf2, 0xe9, 0, 0, 0, 0, /* bnd jmpq relative */ + 0x0f, 0x1f, 0x44, 0, 0 /* nopl 0(%rax,%rax,1) */ +}; + +/* Entries for legacy branches in the second procedure linkage table + look like this. */ + +static const bfd_byte elf_x86_64_legacy_plt2_entry[8] = +{ + 0xff, 0x25, /* jmpq *name@GOTPC(%rip) */ + 0, 0, 0, 0, /* replaced with offset to this symbol in .got. */ + 0x66, 0x90 /* xchg %ax,%ax */ +}; + +/* Entries for branches with BND prefix in the second procedure linkage + table look like this. */ + +static const bfd_byte elf_x86_64_bnd_plt2_entry[8] = +{ + 0xf2, 0xff, 0x25, /* bnd jmpq *name@GOTPC(%rip) */ + 0, 0, 0, 0, /* replaced with offset to this symbol in .got. */ + 0x90 /* nop */ +}; + /* .eh_frame covering the .plt section. */ static const bfd_byte elf_x86_64_eh_frame_plt[] = @@ -628,9 +685,11 @@ struct elf_x86_64_backend_data unsigned int eh_frame_plt_size; }; +#define get_elf_x86_64_arch_data(bed) \ + ((const struct elf_x86_64_backend_data *) (bed)->arch_data) + #define get_elf_x86_64_backend_data(abfd) \ - ((const struct elf_x86_64_backend_data *) \ - get_elf_backend_data (abfd)->arch_data) + get_elf_x86_64_arch_data (get_elf_backend_data (abfd)) #define GET_PLT_ENTRY_SIZE(abfd) \ get_elf_x86_64_backend_data (abfd)->plt_entry_size @@ -654,6 +713,24 @@ static const struct elf_x86_64_backend_data elf_x86_64_arch_bed = sizeof (elf_x86_64_eh_frame_plt), /* eh_frame_plt_size */ }; +static const struct elf_x86_64_backend_data elf_x86_64_bnd_arch_bed = + { + elf_x86_64_bnd_plt0_entry, /* plt0_entry */ + elf_x86_64_bnd_plt_entry, /* plt_entry */ + sizeof (elf_x86_64_bnd_plt_entry), /* plt_entry_size */ + 2, /* plt0_got1_offset */ + 1+8, /* plt0_got2_offset */ + 1+12, /* plt0_got2_insn_end */ + 1+2, /* plt_got_offset */ + 1, /* plt_reloc_offset */ + 7, /* plt_plt_offset */ + 1+6, /* plt_got_insn_size */ + 11, /* plt_plt_insn_end */ + 0, /* plt_lazy_offset */ + elf_x86_64_eh_frame_plt, /* eh_frame_plt */ + sizeof (elf_x86_64_eh_frame_plt), /* eh_frame_plt_size */ + }; + #define elf_backend_arch_data &elf_x86_64_arch_bed /* x86-64 ELF linker hash entry. */ @@ -680,6 +757,24 @@ struct elf_x86_64_link_hash_entry (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type)) unsigned char tls_type; + /* TRUE if a weak symbol with a real definition needs a copy reloc. + When there is a weak symbol with a real definition, the processor + independent code will have arranged for us to see the real + definition first. We need to copy the needs_copy bit from the + real definition and check it when allowing copy reloc in PIE. */ + unsigned int needs_copy : 1; + + /* TRUE if symbol has at least one BND relocation. */ + unsigned int has_bnd_reloc : 1; + + /* Information about the GOT PLT entry. Filled when there are both + GOT and PLT relocations against the same function. */ + union gotplt_union plt_got; + + /* Information about the second PLT entry. Filled when has_bnd_reloc is + set. */ + union gotplt_union plt_bnd; + /* Offset of the GOTPLT entry reserved for the TLS descriptor, starting at the end of the jump table. */ bfd_vma tlsdesc_got; @@ -730,6 +825,8 @@ struct elf_x86_64_link_hash_table asection *sdynbss; asection *srelbss; asection *plt_eh_frame; + asection *plt_bnd; + asection *plt_got; union { @@ -807,6 +904,10 @@ elf_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry, eh = (struct elf_x86_64_link_hash_entry *) entry; eh->dyn_relocs = NULL; eh->tls_type = GOT_UNKNOWN; + eh->needs_copy = 0; + eh->has_bnd_reloc = 0; + eh->plt_bnd.offset = (bfd_vma) -1; + eh->plt_got.offset = (bfd_vma) -1; eh->tlsdesc_got = (bfd_vma) -1; } @@ -875,11 +976,27 @@ elf_x86_64_get_local_sym_hash (struct elf_x86_64_link_hash_table *htab, ret->elf.indx = sec->id; ret->elf.dynstr_index = htab->r_sym (rel->r_info); ret->elf.dynindx = -1; + ret->plt_got.offset = (bfd_vma) -1; *slot = ret; } return &ret->elf; } +/* Destroy an X86-64 ELF linker hash table. */ + +static void +elf_x86_64_link_hash_table_free (bfd *obfd) +{ + struct elf_x86_64_link_hash_table *htab + = (struct elf_x86_64_link_hash_table *) obfd->link.hash; + + if (htab->loc_hash_table) + htab_delete (htab->loc_hash_table); + if (htab->loc_hash_memory) + objalloc_free ((struct objalloc *) htab->loc_hash_memory); + _bfd_elf_link_hash_table_free (obfd); +} + /* Create an X86-64 ELF linker hash table. */ static struct bfd_link_hash_table * @@ -925,28 +1042,14 @@ elf_x86_64_link_hash_table_create (bfd *abfd) ret->loc_hash_memory = objalloc_create (); if (!ret->loc_hash_table || !ret->loc_hash_memory) { - free (ret); + elf_x86_64_link_hash_table_free (abfd); return NULL; } + ret->elf.root.hash_table_free = elf_x86_64_link_hash_table_free; return &ret->elf.root; } -/* Destroy an X86-64 ELF linker hash table. */ - -static void -elf_x86_64_link_hash_table_free (struct bfd_link_hash_table *hash) -{ - struct elf_x86_64_link_hash_table *htab - = (struct elf_x86_64_link_hash_table *) hash; - - if (htab->loc_hash_table) - htab_delete (htab->loc_hash_table); - if (htab->loc_hash_memory) - objalloc_free ((struct objalloc *) htab->loc_hash_memory); - _bfd_elf_link_hash_table_free (hash); -} - /* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and .rela.bss sections in DYNOBJ, and set up shortcuts to them in our hash table. */ @@ -965,13 +1068,28 @@ elf_x86_64_create_dynamic_sections (bfd *dynobj, return FALSE; htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss"); - if (!info->shared) - htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss"); - - if (!htab->sdynbss - || (!info->shared && !htab->srelbss)) + if (!htab->sdynbss) abort (); + if (info->executable) + { + /* Always allow copy relocs for building executables. */ + asection *s = bfd_get_linker_section (dynobj, ".rela.bss"); + if (s == NULL) + { + const struct elf_backend_data *bed = get_elf_backend_data (dynobj); + s = bfd_make_section_anyway_with_flags (dynobj, + ".rela.bss", + (bed->dynamic_sec_flags + | SEC_READONLY)); + if (s == NULL + || ! bfd_set_section_alignment (dynobj, s, + bed->s->log_file_align)) + return FALSE; + } + htab->srelbss = s; + } + if (!info->no_ld_generated_unwind_info && htab->plt_eh_frame == NULL && htab->elf.splt != NULL) @@ -1000,6 +1118,9 @@ elf_x86_64_copy_indirect_symbol (struct bfd_link_info *info, edir = (struct elf_x86_64_link_hash_entry *) dir; eind = (struct elf_x86_64_link_hash_entry *) ind; + if (!edir->has_bnd_reloc) + edir->has_bnd_reloc = eind->has_bnd_reloc; + if (eind->dyn_relocs != NULL) { if (edir->dyn_relocs != NULL) @@ -1087,6 +1208,7 @@ elf_x86_64_check_tls_transition (bfd *abfd, { unsigned int val; unsigned long r_symndx; + bfd_boolean largepic = FALSE; struct elf_link_hash_entry *h; bfd_vma offset; struct elf_x86_64_link_hash_table *htab; @@ -1124,16 +1246,32 @@ elf_x86_64_check_tls_transition (bfd *abfd, can transit to different access model. For 32bit, only leaq foo@tlsgd(%rip), %rdi .word 0x6666; rex64; call __tls_get_addr - can transit to different access model. */ + can transit to different access model. For largepic + we also support: + leaq foo@tlsgd(%rip), %rdi + movabsq $__tls_get_addr@pltoff, %rax + addq $rbx, %rax + call *%rax. */ static const unsigned char call[] = { 0x66, 0x66, 0x48, 0xe8 }; static const unsigned char leaq[] = { 0x66, 0x48, 0x8d, 0x3d }; - if ((offset + 12) > sec->size - || memcmp (contents + offset + 4, call, 4) != 0) + if ((offset + 12) > sec->size) return FALSE; - if (ABI_64_P (abfd)) + if (memcmp (contents + offset + 4, call, 4) != 0) + { + if (!ABI_64_P (abfd) + || (offset + 19) > sec->size + || offset < 3 + || memcmp (contents + offset - 3, leaq + 1, 3) != 0 + || memcmp (contents + offset + 4, "\x48\xb8", 2) != 0 + || memcmp (contents + offset + 14, "\x48\x01\xd8\xff\xd0", 5) + != 0) + return FALSE; + largepic = TRUE; + } + else if (ABI_64_P (abfd)) { if (offset < 4 || memcmp (contents + offset - 4, leaq, 4) != 0) @@ -1151,16 +1289,31 @@ elf_x86_64_check_tls_transition (bfd *abfd, /* Check transition from LD access model. Only leaq foo@tlsld(%rip), %rdi; call __tls_get_addr - can transit to different access model. */ + can transit to different access model. For largepic + we also support: + leaq foo@tlsld(%rip), %rdi + movabsq $__tls_get_addr@pltoff, %rax + addq $rbx, %rax + call *%rax. */ static const unsigned char lea[] = { 0x48, 0x8d, 0x3d }; if (offset < 3 || (offset + 9) > sec->size) return FALSE; - if (memcmp (contents + offset - 3, lea, 3) != 0 - || 0xe8 != *(contents + offset + 4)) + if (memcmp (contents + offset - 3, lea, 3) != 0) return FALSE; + + if (0xe8 != *(contents + offset + 4)) + { + if (!ABI_64_P (abfd) + || (offset + 19) > sec->size + || memcmp (contents + offset + 4, "\x48\xb8", 2) != 0 + || memcmp (contents + offset + 14, "\x48\x01\xd8\xff\xd0", 5) + != 0) + return FALSE; + largepic = TRUE; + } } r_symndx = htab->r_sym (rel[1].r_info); @@ -1172,8 +1325,10 @@ elf_x86_64_check_tls_transition (bfd *abfd, may be versioned. */ return (h != NULL && h->root.root.string != NULL - && (ELF32_R_TYPE (rel[1].r_info) == R_X86_64_PC32 - || ELF32_R_TYPE (rel[1].r_info) == R_X86_64_PLT32) + && (largepic + ? ELF32_R_TYPE (rel[1].r_info) == R_X86_64_PLTOFF64 + : (ELF32_R_TYPE (rel[1].r_info) == R_X86_64_PC32 + || ELF32_R_TYPE (rel[1].r_info) == R_X86_64_PLT32)) && (strncmp (h->root.root.string, "__tls_get_addr", 14) == 0)); @@ -1374,6 +1529,10 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd, return TRUE; } +/* Rename some of the generic section flags to better document how they + are used here. */ +#define need_convert_mov_to_lea sec_flg0 + /* Look through the relocs for a section during the first phase, and calculate needed space in the global offset table, procedure linkage table, and dynamic reloc sections. */ @@ -1389,6 +1548,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; asection *sreloc; + bfd_boolean use_plt_got; if (info->relocatable) return TRUE; @@ -1399,6 +1559,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, if (htab == NULL) return FALSE; + use_plt_got = get_elf_x86_64_backend_data (abfd) == &elf_x86_64_arch_bed; + symtab_hdr = &elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); @@ -1502,12 +1664,53 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, default: break; - case R_X86_64_32S: + case R_X86_64_PC32_BND: + case R_X86_64_PLT32_BND: + case R_X86_64_PC32: + case R_X86_64_PLT32: case R_X86_64_32: case R_X86_64_64: - case R_X86_64_PC32: + /* MPX PLT is supported only if elf_x86_64_arch_bed + is used in 64-bit mode. */ + if (ABI_64_P (abfd) + && info->bndplt + && (get_elf_x86_64_backend_data (abfd) + == &elf_x86_64_arch_bed)) + { + elf_x86_64_hash_entry (h)->has_bnd_reloc = 1; + + /* Create the second PLT for Intel MPX support. */ + if (htab->plt_bnd == NULL) + { + unsigned int plt_bnd_align; + const struct elf_backend_data *bed; + + bed = get_elf_backend_data (info->output_bfd); + BFD_ASSERT (sizeof (elf_x86_64_bnd_plt2_entry) == 8 + && (sizeof (elf_x86_64_bnd_plt2_entry) + == sizeof (elf_x86_64_legacy_plt2_entry))); + plt_bnd_align = 3; + + if (htab->elf.dynobj == NULL) + htab->elf.dynobj = abfd; + htab->plt_bnd + = bfd_make_section_anyway_with_flags (htab->elf.dynobj, + ".plt.bnd", + (bed->dynamic_sec_flags + | SEC_ALLOC + | SEC_CODE + | SEC_LOAD + | SEC_READONLY)); + if (htab->plt_bnd == NULL + || !bfd_set_section_alignment (htab->elf.dynobj, + htab->plt_bnd, + plt_bnd_align)) + return FALSE; + } + } + + case R_X86_64_32S: case R_X86_64_PC64: - case R_X86_64_PLT32: case R_X86_64_GOTPCREL: case R_X86_64_GOTPCREL64: if (htab->elf.dynobj == NULL) @@ -1519,6 +1722,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, /* It is referenced by a non-shared object. */ h->ref_regular = 1; + h->root.non_ir_ref = 1; } if (! elf_x86_64_tls_transition (info, abfd, sec, NULL, @@ -1579,14 +1783,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, if (h != NULL) { - if (r_type == R_X86_64_GOTPLT64) - { - /* This relocation indicates that we also need - a PLT entry, as this is a function. We don't need - a PLT entry for local symbols. */ - h->needs_plt = 1; - h->plt.refcount += 1; - } h->got.refcount += 1; old_tls_type = elf_x86_64_hash_entry (h)->tls_type; } @@ -1669,6 +1865,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, break; case R_X86_64_PLT32: + case R_X86_64_PLT32_BND: /* This symbol requires a procedure linkage table entry. We actually build the entry in adjust_dynamic_symbol, because this might be a case of linking PIC code which is @@ -1729,6 +1926,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_X86_64_PC8: case R_X86_64_PC16: case R_X86_64_PC32: + case R_X86_64_PC32_BND: case R_X86_64_PC64: case R_X86_64_64: pointer: @@ -1745,7 +1943,9 @@ pointer: /* We may need a .plt entry if the function this reloc refers to is in a shared lib. */ h->plt.refcount += 1; - if (r_type != R_X86_64_PC32 && r_type != R_X86_64_PC64) + if (r_type != R_X86_64_PC32 + && r_type != R_X86_64_PC32_BND + && r_type != R_X86_64_PC64) h->pointer_equality_needed = 1; } @@ -1876,6 +2076,44 @@ do_size: default: break; } + + if (use_plt_got + && h != NULL + && h->plt.refcount > 0 + && (((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed) + || h->got.refcount > 0) + && htab->plt_got == NULL) + { + /* Create the GOT procedure linkage table. */ + unsigned int plt_got_align; + const struct elf_backend_data *bed; + + bed = get_elf_backend_data (info->output_bfd); + BFD_ASSERT (sizeof (elf_x86_64_legacy_plt2_entry) == 8 + && (sizeof (elf_x86_64_bnd_plt2_entry) + == sizeof (elf_x86_64_legacy_plt2_entry))); + plt_got_align = 3; + + if (htab->elf.dynobj == NULL) + htab->elf.dynobj = abfd; + htab->plt_got + = bfd_make_section_anyway_with_flags (htab->elf.dynobj, + ".plt.got", + (bed->dynamic_sec_flags + | SEC_ALLOC + | SEC_CODE + | SEC_LOAD + | SEC_READONLY)); + if (htab->plt_got == NULL + || !bfd_set_section_alignment (htab->elf.dynobj, + htab->plt_got, + plt_got_align)) + return FALSE; + } + + if (r_type == R_X86_64_GOTPCREL + && (h == NULL || h->type != STT_GNU_IFUNC)) + sec->need_convert_mov_to_lea = 1; } return TRUE; @@ -2004,8 +2242,6 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_X86_64_GOTPLT64: if (h != NULL) { - if (r_type == R_X86_64_GOTPLT64 && h->plt.refcount > 0) - h->plt.refcount -= 1; if (h->got.refcount > 0) h->got.refcount -= 1; if (h->type == STT_GNU_IFUNC) @@ -2029,6 +2265,7 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_X86_64_PC8: case R_X86_64_PC16: case R_X86_64_PC32: + case R_X86_64_PC32_BND: case R_X86_64_PC64: case R_X86_64_SIZE32: case R_X86_64_SIZE64: @@ -2038,6 +2275,7 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, /* Fall thru */ case R_X86_64_PLT32: + case R_X86_64_PLT32_BND: case R_X86_64_PLTOFF64: if (h != NULL) { @@ -2152,7 +2390,11 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, h->root.u.def.section = h->u.weakdef->root.u.def.section; h->root.u.def.value = h->u.weakdef->root.u.def.value; if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) - h->non_got_ref = h->u.weakdef->non_got_ref; + { + eh = (struct elf_x86_64_link_hash_entry *) h; + h->non_got_ref = h->u.weakdef->non_got_ref; + eh->needs_copy = h->u.weakdef->needs_copy; + } return TRUE; } @@ -2163,7 +2405,7 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, only references to the symbol are via the global offset table. For such cases we need not do anything here; the relocations will be handled correctly by relocate_section. */ - if (info->shared) + if (!info->executable) return TRUE; /* If there are no references to this symbol that do not use the @@ -2224,7 +2466,7 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, s = htab->sdynbss; - return _bfd_elf_adjust_dynamic_copy (h, s); + return _bfd_elf_adjust_dynamic_copy (info, h, s); } /* Allocate space in .plt, .got and associated reloc sections for @@ -2252,17 +2494,67 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) bed = get_elf_backend_data (info->output_bfd); plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd); + /* We can't use the GOT PLT if pointer equality is needed since + finish_dynamic_symbol won't clear symbol value and the dynamic + linker won't update the GOT slot. We will get into an infinite + loop at run-time. */ + if (htab->plt_got != NULL + && h->type != STT_GNU_IFUNC + && !h->pointer_equality_needed + && h->plt.refcount > 0 + && h->got.refcount > 0) + { + /* Don't use the regular PLT if there are both GOT and GOTPLT + reloctions. */ + h->plt.offset = (bfd_vma) -1; + + /* Use the GOT PLT. */ + eh->plt_got.refcount = 1; + } + /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it here if it is defined and referenced in a non-shared object. */ if (h->type == STT_GNU_IFUNC && h->def_regular) - return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, - &eh->dyn_relocs, - plt_entry_size, - GOT_ENTRY_SIZE); + { + if (_bfd_elf_allocate_ifunc_dyn_relocs (info, h, + &eh->dyn_relocs, + plt_entry_size, + plt_entry_size, + GOT_ENTRY_SIZE)) + { + asection *s = htab->plt_bnd; + if (h->plt.offset != (bfd_vma) -1 && s != NULL) + { + /* Use the .plt.bnd section if it is created. */ + eh->plt_bnd.offset = s->size; + + /* Make room for this entry in the .plt.bnd section. */ + s->size += sizeof (elf_x86_64_legacy_plt2_entry); + } + + return TRUE; + } + else + return FALSE; + } else if (htab->elf.dynamic_sections_created - && h->plt.refcount > 0) + && (h->plt.refcount > 0 || eh->plt_got.refcount > 0)) { + bfd_boolean use_plt_got; + + if ((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed) + { + /* Don't use the regular PLT for DF_BIND_NOW. */ + h->plt.offset = (bfd_vma) -1; + + /* Use the GOT PLT. */ + h->got.refcount = 1; + eh->plt_got.refcount = 1; + } + + use_plt_got = eh->plt_got.refcount > 0; + /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ if (h->dynindx == -1 @@ -2276,13 +2568,23 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) { asection *s = htab->elf.splt; + asection *bnd_s = htab->plt_bnd; + asection *got_s = htab->plt_got; /* If this is the first .plt entry, make room for the special - first entry. */ + first entry. The .plt section is used by prelink to undo + prelinking for dynamic relocations. */ if (s->size == 0) - s->size += plt_entry_size; + s->size = plt_entry_size; - h->plt.offset = s->size; + if (use_plt_got) + eh->plt_got.offset = got_s->size; + else + { + h->plt.offset = s->size; + if (bnd_s) + eh->plt_bnd.offset = bnd_s->size; + } /* If this symbol is not defined in a regular file, and we are not generating a shared library, then set the symbol to this @@ -2292,20 +2594,49 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) if (! info->shared && !h->def_regular) { - h->root.u.def.section = s; - h->root.u.def.value = h->plt.offset; + if (use_plt_got) + { + /* We need to make a call to the entry of the GOT PLT + instead of regular PLT entry. */ + h->root.u.def.section = got_s; + h->root.u.def.value = eh->plt_got.offset; + } + else + { + if (bnd_s) + { + /* We need to make a call to the entry of the second + PLT instead of regular PLT entry. */ + h->root.u.def.section = bnd_s; + h->root.u.def.value = eh->plt_bnd.offset; + } + else + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } + } } /* Make room for this entry. */ - s->size += plt_entry_size; - - /* We also need to make an entry in the .got.plt section, which - will be placed in the .got section by the linker script. */ - htab->elf.sgotplt->size += GOT_ENTRY_SIZE; - - /* We also need to make an entry in the .rela.plt section. */ - htab->elf.srelplt->size += bed->s->sizeof_rela; - htab->elf.srelplt->reloc_count++; + if (use_plt_got) + got_s->size += sizeof (elf_x86_64_legacy_plt2_entry); + else + { + s->size += plt_entry_size; + if (bnd_s) + bnd_s->size += sizeof (elf_x86_64_legacy_plt2_entry); + + /* We also need to make an entry in the .got.plt section, + which will be placed in the .got section by the linker + script. */ + htab->elf.sgotplt->size += GOT_ENTRY_SIZE; + + /* We also need to make an entry in the .rela.plt + section. */ + htab->elf.srelplt->size += bed->s->sizeof_rela; + htab->elf.srelplt->reloc_count++; + } } else { @@ -2419,20 +2750,38 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* Also discard relocs on undefined weak syms with non-default visibility. */ - if (eh->dyn_relocs != NULL - && h->root.type == bfd_link_hash_undefweak) + if (eh->dyn_relocs != NULL) { - if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - eh->dyn_relocs = NULL; - - /* Make sure undefined weak symbols are output as a dynamic - symbol in PIEs. */ - else if (h->dynindx == -1 - && ! h->forced_local - && ! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } + if (h->root.type == bfd_link_hash_undefweak) + { + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + eh->dyn_relocs = NULL; + + /* Make sure undefined weak symbols are output as a dynamic + symbol in PIEs. */ + else if (h->dynindx == -1 + && ! h->forced_local + && ! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + /* For PIE, discard space for pc-relative relocs against + symbols which turn out to need copy relocs. */ + else if (info->executable + && (h->needs_copy || eh->needs_copy) + && h->def_dynamic + && !h->def_regular) + { + struct elf_dyn_relocs **pp; + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + if (p->pc_count != 0) + *pp = p->next; + else + pp = &p->next; + } + } + } } else if (ELIMINATE_COPY_RELOCS) { @@ -2523,8 +2872,9 @@ elf_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h, info->flags |= DF_TEXTREL; - if (info->warn_shared_textrel && info->shared) - info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'.\n"), + if ((info->warn_shared_textrel && info->shared) + || info->error_textrel) + info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'\n"), p->sec->owner, h->root.root.string, p->sec); @@ -2553,15 +2903,16 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec, bfd_boolean changed_contents; bfd_boolean changed_relocs; bfd_signed_vma *local_got_refcounts; + bfd_vma maxpagesize; /* Don't even try to convert non-ELF outputs. */ if (!is_elf_hash_table (link_info->hash)) return FALSE; - /* Nothing to do if there are no codes, no relocations or no output. */ + /* Nothing to do if there is no need or no output. */ if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC) - || sec->reloc_count == 0 - || discarded_section (sec)) + || sec->need_convert_mov_to_lea == 0 + || bfd_is_abs_section (sec->output_section)) return TRUE; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; @@ -2577,6 +2928,7 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec, changed_contents = FALSE; changed_relocs = FALSE; local_got_refcounts = elf_local_got_refcounts (abfd); + maxpagesize = get_elf_backend_data (abfd)->maxpagesize; /* Get the section contents. */ if (elf_section_data (sec)->this_hdr.contents != NULL) @@ -2594,60 +2946,177 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec, unsigned int r_symndx = htab->r_sym (irel->r_info); unsigned int indx; struct elf_link_hash_entry *h; + asection *tsec; + char symtype; + bfd_vma toff, roff; + enum { + none, local, global + } convert_mov_to_lea; + unsigned int opcode; if (r_type != R_X86_64_GOTPCREL) continue; + roff = irel->r_offset; + + if (roff < 2) + continue; + + opcode = bfd_get_8 (abfd, contents + roff - 2); + + /* PR ld/18591: Don't convert R_X86_64_GOTPCREL relocation if it + isn't for mov instruction. */ + if (opcode != 0x8b) + continue; + + tsec = NULL; + convert_mov_to_lea = none; + /* Get the symbol referred to by the reloc. */ if (r_symndx < symtab_hdr->sh_info) { Elf_Internal_Sym *isym; + /* Silence older GCC warning. */ + h = NULL; + isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, r_symndx); - /* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation. */ - if (ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC - && bfd_get_8 (input_bfd, - contents + irel->r_offset - 2) == 0x8b) + symtype = ELF_ST_TYPE (isym->st_info); + + /* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation and + skip relocation against undefined symbols. */ + if (symtype != STT_GNU_IFUNC && isym->st_shndx != SHN_UNDEF) { - bfd_put_8 (output_bfd, 0x8d, - contents + irel->r_offset - 2); - irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32); - if (local_got_refcounts != NULL - && local_got_refcounts[r_symndx] > 0) - local_got_refcounts[r_symndx] -= 1; - changed_contents = TRUE; - changed_relocs = TRUE; + if (isym->st_shndx == SHN_ABS) + tsec = bfd_abs_section_ptr; + else if (isym->st_shndx == SHN_COMMON) + tsec = bfd_com_section_ptr; + else if (isym->st_shndx == SHN_X86_64_LCOMMON) + tsec = &_bfd_elf_large_com_section; + else + tsec = bfd_section_from_elf_index (abfd, isym->st_shndx); + + toff = isym->st_value; + convert_mov_to_lea = local; } - continue; } + else + { + indx = r_symndx - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + BFD_ASSERT (h != NULL); - indx = r_symndx - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; + /* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation. We also + avoid optimizing _DYNAMIC since ld.so may use its link-time + address. */ + if (h->def_regular + && h->type != STT_GNU_IFUNC + && h != htab->elf.hdynamic + && SYMBOL_REFERENCES_LOCAL (link_info, h)) + { + tsec = h->root.u.def.section; + toff = h->root.u.def.value; + symtype = h->type; + convert_mov_to_lea = global; + } + } - /* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation. We also - avoid optimizing _DYNAMIC since ld.so may use its link-time - address. */ - if (h->def_regular - && h->type != STT_GNU_IFUNC - && h != htab->elf.hdynamic - && SYMBOL_REFERENCES_LOCAL (link_info, h) - && bfd_get_8 (input_bfd, - contents + irel->r_offset - 2) == 0x8b) + if (convert_mov_to_lea == none) + continue; + + if (tsec->sec_info_type == SEC_INFO_TYPE_MERGE) + { + /* At this stage in linking, no SEC_MERGE symbol has been + adjusted, so all references to such symbols need to be + passed through _bfd_merged_section_offset. (Later, in + relocate_section, all SEC_MERGE symbols *except* for + section symbols have been adjusted.) + + gas may reduce relocations against symbols in SEC_MERGE + sections to a relocation against the section symbol when + the original addend was zero. When the reloc is against + a section symbol we should include the addend in the + offset passed to _bfd_merged_section_offset, since the + location of interest is the original symbol. On the + other hand, an access to "sym+addend" where "sym" is not + a section symbol should not include the addend; Such an + access is presumed to be an offset from "sym"; The + location of interest is just "sym". */ + if (symtype == STT_SECTION) + toff += irel->r_addend; + + toff = _bfd_merged_section_offset (abfd, &tsec, + elf_section_data (tsec)->sec_info, + toff); + + if (symtype != STT_SECTION) + toff += irel->r_addend; + } + else + toff += irel->r_addend; + + /* Don't convert if R_X86_64_PC32 relocation overflows. */ + if (tsec->output_section == sec->output_section) + { + if ((toff - roff + 0x80000000) > 0xffffffff) + continue; + } + else + { + asection *asect; + bfd_size_type size; + + /* At this point, we don't know the load addresses of TSEC + section nor SEC section. We estimate the distrance between + SEC and TSEC. */ + size = 0; + for (asect = sec->output_section; + asect != NULL && asect != tsec->output_section; + asect = asect->next) + { + asection *i; + for (i = asect->output_section->map_head.s; + i != NULL; + i = i->map_head.s) + { + size = align_power (size, i->alignment_power); + size += i->size; + } + } + + /* Don't convert R_X86_64_GOTPCREL if TSEC isn't placed after + SEC. */ + if (asect == NULL) + continue; + + /* Take PT_GNU_RELRO segment into account by adding + maxpagesize. */ + if ((toff + size + maxpagesize - roff + 0x80000000) + > 0xffffffff) + continue; + } + + bfd_put_8 (abfd, 0x8d, contents + roff - 2); + irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32); + changed_contents = TRUE; + changed_relocs = TRUE; + + if (convert_mov_to_lea == local) + { + if (local_got_refcounts != NULL + && local_got_refcounts[r_symndx] > 0) + local_got_refcounts[r_symndx] -= 1; + } + else { - bfd_put_8 (output_bfd, 0x8d, - contents + irel->r_offset - 2); - irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32); if (h->got.refcount > 0) h->got.refcount -= 1; - changed_contents = TRUE; - changed_relocs = TRUE; } } @@ -2720,7 +3189,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, /* Set up .got offsets for local syms, and space for local dynamic relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { bfd_signed_vma *local_got; bfd_signed_vma *end_local_got; @@ -2761,8 +3230,9 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, && (info->flags & DF_TEXTREL) == 0) { info->flags |= DF_TEXTREL; - if (info->warn_shared_textrel && info->shared) - info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'.\n"), + if ((info->warn_shared_textrel && info->shared) + || info->error_textrel) + info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'\n"), p->sec->owner, p->sec); } } @@ -2904,7 +3374,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, && _bfd_elf_eh_frame_present (info)) { const struct elf_x86_64_backend_data *arch_data - = (const struct elf_x86_64_backend_data *) bed->arch_data; + = get_elf_x86_64_arch_data (bed); htab->plt_eh_frame->size = arch_data->eh_frame_plt_size; } @@ -2921,6 +3391,8 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, || s == htab->elf.sgotplt || s == htab->elf.iplt || s == htab->elf.igotplt + || s == htab->plt_bnd + || s == htab->plt_got || s == htab->plt_eh_frame || s == htab->sdynbss) { @@ -2976,7 +3448,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, && htab->plt_eh_frame->contents != NULL) { const struct elf_x86_64_backend_data *arch_data - = (const struct elf_x86_64_backend_data *) bed->arch_data; + = get_elf_x86_64_arch_data (bed); memcpy (htab->plt_eh_frame->contents, arch_data->eh_frame_plt, htab->plt_eh_frame->size); @@ -3002,12 +3474,19 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, if (htab->elf.splt->size != 0) { - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) + /* DT_PLTGOT is used by prelink even if there is no PLT + relocation. */ + if (!add_dynamic_entry (DT_PLTGOT, 0)) return FALSE; + if (htab->elf.srelplt->size != 0) + { + if (!add_dynamic_entry (DT_PLTRELSZ, 0) + || !add_dynamic_entry (DT_PLTREL, DT_RELA) + || !add_dynamic_entry (DT_JMPREL, 0)) + return FALSE; + } + if (htab->tlsdesc_plt && (!add_dynamic_entry (DT_TLSDESC_PLT, 0) || !add_dynamic_entry (DT_TLSDESC_GOT, 0))) @@ -3076,6 +3555,7 @@ elf_x86_64_always_size_sections (bfd *output_bfd, tlsbase = (struct elf_link_hash_entry *)bh; tlsbase->def_regular = 1; tlsbase->other = STV_HIDDEN; + tlsbase->root.linker_def = 1; (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE); } } @@ -3199,14 +3679,15 @@ elf_x86_64_relocate_section (bfd *output_bfd, reloc_howto_type *howto; unsigned long r_symndx; struct elf_link_hash_entry *h; + struct elf_x86_64_link_hash_entry *eh; Elf_Internal_Sym *sym; asection *sec; - bfd_vma off, offplt; + bfd_vma off, offplt, plt_offset; bfd_vma relocation; bfd_boolean unresolved_reloc; bfd_reloc_status_type r; int tls_type; - asection *base_got; + asection *base_got, *resolved_plt; bfd_vma st_size; r_type = ELF32_R_TYPE (rel->r_info); @@ -3260,11 +3741,12 @@ elf_x86_64_relocate_section (bfd *output_bfd, else { bfd_boolean warned ATTRIBUTE_UNUSED; + bfd_boolean ignored ATTRIBUTE_UNUSED; RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, r_symndx, symtab_hdr, sym_hashes, h, sec, relocation, - unresolved_reloc, warned); + unresolved_reloc, warned, ignored); st_size = h->size; } @@ -3293,13 +3775,14 @@ elf_x86_64_relocate_section (bfd *output_bfd, } } + eh = (struct elf_x86_64_link_hash_entry *) h; + /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it here if it is defined in a non-shared object. */ if (h != NULL && h->type == STT_GNU_IFUNC && h->def_regular) { - asection *plt; bfd_vma plt_index; const char *name; @@ -3308,9 +3791,27 @@ elf_x86_64_relocate_section (bfd *output_bfd, abort (); /* STT_GNU_IFUNC symbol must go through PLT. */ - plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt; - relocation = (plt->output_section->vma - + plt->output_offset + h->plt.offset); + if (htab->elf.splt != NULL) + { + if (htab->plt_bnd != NULL) + { + resolved_plt = htab->plt_bnd; + plt_offset = eh->plt_bnd.offset; + } + else + { + resolved_plt = htab->elf.splt; + plt_offset = h->plt.offset; + } + } + else + { + resolved_plt = htab->elf.iplt; + plt_offset = h->plt.offset; + } + + relocation = (resolved_plt->output_section->vma + + resolved_plt->output_offset + plt_offset); switch (r_type) { @@ -3402,8 +3903,10 @@ elf_x86_64_relocate_section (bfd *output_bfd, } /* FALLTHROUGH */ case R_X86_64_PC32: + case R_X86_64_PC32_BND: case R_X86_64_PC64: case R_X86_64_PLT32: + case R_X86_64_PLT32_BND: goto do_relocation; case R_X86_64_GOTPCREL: @@ -3478,12 +3981,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, case R_X86_64_GOTPCREL64: /* Use global offset table entry as symbol value. */ case R_X86_64_GOTPLT64: - /* This is the same as GOT64 for relocation purposes, but - indicates the existence of a PLT entry. The difficulty is, - that we must calculate the GOT slot offset from the PLT - offset, if this symbol got a PLT entry (it was global). - Additionally if it's computed from the PLT entry, then that - GOT offset is relative to .got.plt, not to .got. */ + /* This is obsolete and treated the the same as GOT64. */ base_got = htab->elf.sgot; if (htab->elf.sgot == NULL) @@ -3595,21 +4093,52 @@ elf_x86_64_relocate_section (bfd *output_bfd, /* Relocation is relative to the start of the global offset table. */ - /* Check to make sure it isn't a protected function symbol - for shared library since it may not be local when used - as function address. */ - if (!info->executable - && h - && !SYMBOLIC_BIND (info, h) - && h->def_regular - && h->type == STT_FUNC - && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) + /* Check to make sure it isn't a protected function or data + symbol for shared library since it may not be local when + used as function address or with copy relocation. We also + need to make sure that a symbol is referenced locally. */ + if (info->shared && h) { - (*_bfd_error_handler) - (_("%B: relocation R_X86_64_GOTOFF64 against protected function `%s' can not be used when making a shared object"), - input_bfd, h->root.root.string); - bfd_set_error (bfd_error_bad_value); + if (!h->def_regular) + { + const char *v; + + switch (ELF_ST_VISIBILITY (h->other)) + { + case STV_HIDDEN: + v = _("hidden symbol"); + break; + case STV_INTERNAL: + v = _("internal symbol"); + break; + case STV_PROTECTED: + v = _("protected symbol"); + break; + default: + v = _("symbol"); + break; + } + + (*_bfd_error_handler) + (_("%B: relocation R_X86_64_GOTOFF64 against undefined %s `%s' can not be used when making a shared object"), + input_bfd, v, h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + else if (!info->executable + && !SYMBOL_REFERENCES_LOCAL (info, h) + && (h->type == STT_FUNC + || h->type == STT_OBJECT) + && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) + { + (*_bfd_error_handler) + (_("%B: relocation R_X86_64_GOTOFF64 against protected %s `%s' can not be used when making a shared object"), + input_bfd, + h->type == STT_FUNC ? "function" : "data", + h->root.root.string); + bfd_set_error (bfd_error_bad_value); return FALSE; + } } /* Note that sgot is not involved in this @@ -3637,9 +4166,20 @@ elf_x86_64_relocate_section (bfd *output_bfd, && h->plt.offset != (bfd_vma) -1 && htab->elf.splt != NULL) { - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset); + if (htab->plt_bnd != NULL) + { + resolved_plt = htab->plt_bnd; + plt_offset = eh->plt_bnd.offset; + } + else + { + resolved_plt = htab->elf.splt; + plt_offset = h->plt.offset; + } + + relocation = (resolved_plt->output_section->vma + + resolved_plt->output_offset + + plt_offset); unresolved_reloc = FALSE; } @@ -3648,6 +4188,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, break; case R_X86_64_PLT32: + case R_X86_64_PLT32_BND: /* Relocation is to the entry for this symbol in the procedure linkage table. */ @@ -3656,7 +4197,8 @@ elf_x86_64_relocate_section (bfd *output_bfd, if (h == NULL) break; - if (h->plt.offset == (bfd_vma) -1 + if ((h->plt.offset == (bfd_vma) -1 + && eh->plt_got.offset == (bfd_vma) -1) || htab->elf.splt == NULL) { /* We didn't make a PLT entry for this symbol. This @@ -3665,9 +4207,29 @@ elf_x86_64_relocate_section (bfd *output_bfd, break; } - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset); + if (h->plt.offset != (bfd_vma) -1) + { + if (htab->plt_bnd != NULL) + { + resolved_plt = htab->plt_bnd; + plt_offset = eh->plt_bnd.offset; + } + else + { + resolved_plt = htab->elf.splt; + plt_offset = h->plt.offset; + } + } + else + { + /* Use the GOT PLT. */ + resolved_plt = htab->plt_got; + plt_offset = eh->plt_got.offset; + } + + relocation = (resolved_plt->output_section->vma + + resolved_plt->output_offset + + plt_offset); unresolved_reloc = FALSE; break; @@ -3680,14 +4242,20 @@ elf_x86_64_relocate_section (bfd *output_bfd, case R_X86_64_PC8: case R_X86_64_PC16: case R_X86_64_PC32: + case R_X86_64_PC32_BND: + /* Don't complain about -fPIC if the symbol is undefined when + building executable. */ if (info->shared && (input_section->flags & SEC_ALLOC) != 0 && (input_section->flags & SEC_READONLY) != 0 - && h != NULL) + && h != NULL + && !(info->executable + && h->root.type == bfd_link_hash_undefined)) { bfd_boolean fail = FALSE; bfd_boolean branch - = (r_type == R_X86_64_PC32 + = ((r_type == R_X86_64_PC32 + || r_type == R_X86_64_PC32_BND) && is_32bit_relative_branch (contents, rel->r_offset)); if (SYMBOL_REFERENCES_LOCAL (info, h)) @@ -3696,10 +4264,12 @@ elf_x86_64_relocate_section (bfd *output_bfd, defined locally or for a branch. */ fail = !h->def_regular && !branch; } - else + else if (!(info->executable + && (h->needs_copy || eh->needs_copy))) { - /* Symbol isn't referenced locally. We only allow - branch to symbol with non-default visibility. */ + /* Symbol doesn't need copy reloc and isn't referenced + locally. We only allow branch to symbol with + non-default visibility. */ fail = (!branch || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT); } @@ -3753,7 +4323,16 @@ direct: if ((input_section->flags & SEC_ALLOC) == 0) break; + /* Don't copy a pc-relative relocation into the output file + if the symbol needs copy reloc or the symbol is undefined + when building executable. */ if ((info->shared + && !(info->executable + && h != NULL + && (h->needs_copy + || eh->needs_copy + || h->root.type == bfd_link_hash_undefined) + && IS_X86_64_PCREL_TYPE (r_type)) && (h == NULL || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT || h->root.type != bfd_link_hash_undefweak) @@ -3945,8 +4524,26 @@ direct: .word 0x6666; rex64; call __tls_get_addr into: movl %fs:0, %eax - leaq foo@tpoff(%rax), %rax */ - if (ABI_64_P (output_bfd)) + leaq foo@tpoff(%rax), %rax + For largepic, change: + leaq foo@tlsgd(%rip), %rdi + movabsq $__tls_get_addr@pltoff, %rax + addq %rbx, %rax + call *%rax + into: + movq %fs:0, %rax + leaq foo@tpoff(%rax), %rax + nopw 0x0(%rax,%rax,1) */ + int largepic = 0; + if (ABI_64_P (output_bfd) + && contents[roff + 5] == (bfd_byte) '\xb8') + { + memcpy (contents + roff - 3, + "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80" + "\0\0\0\0\x66\x0f\x1f\x44\0", 22); + largepic = 1; + } + else if (ABI_64_P (output_bfd)) memcpy (contents + roff - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0", 16); @@ -3956,8 +4553,8 @@ direct: 15); bfd_put_32 (output_bfd, elf_x86_64_tpoff (info, relocation), - contents + roff + 8); - /* Skip R_X86_64_PC32/R_X86_64_PLT32. */ + contents + roff + 8 + largepic); + /* Skip R_X86_64_PC32/R_X86_64_PLT32/R_X86_64_PLTOFF64. */ rel++; continue; } @@ -3998,17 +4595,27 @@ direct: else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_GOTTPOFF) { /* IE->LE transition: - Originally it can be one of: + For 64bit, originally it can be one of: movq foo@gottpoff(%rip), %reg addq foo@gottpoff(%rip), %reg We change it into: movq $foo, %reg leaq foo(%reg), %reg - addq $foo, %reg. */ + addq $foo, %reg. + For 32bit, originally it can be one of: + movq foo@gottpoff(%rip), %reg + addl foo@gottpoff(%rip), %reg + We change it into: + movq $foo, %reg + leal foo(%reg), %reg + addl $foo, %reg. */ unsigned int val, type, reg; - val = bfd_get_8 (input_bfd, contents + roff - 3); + if (roff >= 3) + val = bfd_get_8 (input_bfd, contents + roff - 3); + else + val = 0; type = bfd_get_8 (input_bfd, contents + roff - 2); reg = bfd_get_8 (input_bfd, contents + roff - 1); reg >>= 3; @@ -4028,8 +4635,8 @@ direct: } else if (reg == 4) { - /* addq -> addq - addressing with %rsp/%r12 is - special */ + /* addq/addl -> addq/addl - addressing with %rsp/%r12 + is special */ if (val == 0x4c) bfd_put_8 (output_bfd, 0x49, contents + roff - 3); @@ -4043,7 +4650,7 @@ direct: } else { - /* addq -> leaq */ + /* addq/addl -> leaq/leal */ if (val == 0x4c) bfd_put_8 (output_bfd, 0x4d, contents + roff - 3); @@ -4192,8 +4799,26 @@ direct: .word 0x6666; rex64; call __tls_get_addr@plt into: movl %fs:0, %eax - addq foo@gottpoff(%rip), %rax */ - if (ABI_64_P (output_bfd)) + addq foo@gottpoff(%rip), %rax + For largepic, change: + leaq foo@tlsgd(%rip), %rdi + movabsq $__tls_get_addr@pltoff, %rax + addq %rbx, %rax + call *%rax + into: + movq %fs:0, %rax + addq foo@gottpoff(%rax), %rax + nopw 0x0(%rax,%rax,1) */ + int largepic = 0; + if (ABI_64_P (output_bfd) + && contents[roff + 5] == (bfd_byte) '\xb8') + { + memcpy (contents + roff - 3, + "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05" + "\0\0\0\0\x66\x0f\x1f\x44\0", 22); + largepic = 1; + } + else if (ABI_64_P (output_bfd)) memcpy (contents + roff - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0", 16); @@ -4205,12 +4830,13 @@ direct: relocation = (htab->elf.sgot->output_section->vma + htab->elf.sgot->output_offset + off - roff + - largepic - input_section->output_section->vma - input_section->output_offset - 12); bfd_put_32 (output_bfd, relocation, - contents + roff + 8); - /* Skip R_X86_64_PLT32. */ + contents + roff + 8 + largepic); + /* Skip R_X86_64_PLT32/R_X86_64_PLTOFF64. */ rel++; continue; } @@ -4272,16 +4898,29 @@ direct: For 64bit, we change it into: .word 0x6666; .byte 0x66; movq %fs:0, %rax. For 32bit, we change it into: - nopl 0x0(%rax); movl %fs:0, %eax. */ + nopl 0x0(%rax); movl %fs:0, %eax. + For largepic, change: + leaq foo@tlsgd(%rip), %rdi + movabsq $__tls_get_addr@pltoff, %rax + addq %rbx, %rax + call *%rax + into: + data32 data32 data32 nopw %cs:0x0(%rax,%rax,1) + movq %fs:0, %eax */ BFD_ASSERT (r_type == R_X86_64_TPOFF32); - if (ABI_64_P (output_bfd)) + if (ABI_64_P (output_bfd) + && contents[rel->r_offset + 5] == (bfd_byte) '\xb8') + memcpy (contents + rel->r_offset - 3, + "\x66\x66\x66\x66\x2e\x0f\x1f\x84\0\0\0\0\0" + "\x64\x48\x8b\x04\x25\0\0\0", 22); + else if (ABI_64_P (output_bfd)) memcpy (contents + rel->r_offset - 3, "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12); else memcpy (contents + rel->r_offset - 3, "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", 12); - /* Skip R_X86_64_PC32/R_X86_64_PLT32. */ + /* Skip R_X86_64_PC32/R_X86_64_PLT32/R_X86_64_PLTOFF64. */ rel++; continue; } @@ -4330,6 +4969,11 @@ direct: relocation = elf_x86_64_tpoff (info, relocation); break; + case R_X86_64_DTPOFF64: + BFD_ASSERT ((input_section->flags & SEC_CODE) == 0); + relocation -= elf_x86_64_dtpoff_base (info); + break; + default: break; } @@ -4408,21 +5052,33 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, Elf_Internal_Sym *sym ATTRIBUTE_UNUSED) { struct elf_x86_64_link_hash_table *htab; - const struct elf_x86_64_backend_data *const abed - = get_elf_x86_64_backend_data (output_bfd); + const struct elf_x86_64_backend_data *abed; + bfd_boolean use_plt_bnd; + struct elf_x86_64_link_hash_entry *eh; htab = elf_x86_64_hash_table (info); if (htab == NULL) return FALSE; + /* Use MPX backend data in case of BND relocation. Use .plt_bnd + section only if there is .plt section. */ + use_plt_bnd = htab->elf.splt != NULL && htab->plt_bnd != NULL; + abed = (use_plt_bnd + ? &elf_x86_64_bnd_arch_bed + : get_elf_x86_64_backend_data (output_bfd)); + + eh = (struct elf_x86_64_link_hash_entry *) h; + if (h->plt.offset != (bfd_vma) -1) { bfd_vma plt_index; - bfd_vma got_offset; + bfd_vma got_offset, plt_offset, plt_plt_offset, plt_got_offset; + bfd_vma plt_plt_insn_end, plt_got_insn_size; Elf_Internal_Rela rela; bfd_byte *loc; - asection *plt, *gotplt, *relplt; + asection *plt, *gotplt, *relplt, *resolved_plt; const struct elf_backend_data *bed; + bfd_vma plt_got_pcrel_offset; /* When building a static executable, use .iplt, .igot.plt and .rela.iplt sections for STT_GNU_IFUNC symbols. */ @@ -4472,23 +5128,74 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, got_offset = got_offset * GOT_ENTRY_SIZE; } - /* Fill in the entry in the procedure linkage table. */ - memcpy (plt->contents + h->plt.offset, abed->plt_entry, - abed->plt_entry_size); + plt_plt_insn_end = abed->plt_plt_insn_end; + plt_plt_offset = abed->plt_plt_offset; + plt_got_insn_size = abed->plt_got_insn_size; + plt_got_offset = abed->plt_got_offset; + if (use_plt_bnd) + { + /* Use the second PLT with BND relocations. */ + const bfd_byte *plt_entry, *plt2_entry; + + if (eh->has_bnd_reloc) + { + plt_entry = elf_x86_64_bnd_plt_entry; + plt2_entry = elf_x86_64_bnd_plt2_entry; + } + else + { + plt_entry = elf_x86_64_legacy_plt_entry; + plt2_entry = elf_x86_64_legacy_plt2_entry; + + /* Subtract 1 since there is no BND prefix. */ + plt_plt_insn_end -= 1; + plt_plt_offset -= 1; + plt_got_insn_size -= 1; + plt_got_offset -= 1; + } + + BFD_ASSERT (sizeof (elf_x86_64_bnd_plt_entry) + == sizeof (elf_x86_64_legacy_plt_entry)); + + /* Fill in the entry in the procedure linkage table. */ + memcpy (plt->contents + h->plt.offset, + plt_entry, sizeof (elf_x86_64_legacy_plt_entry)); + /* Fill in the entry in the second PLT. */ + memcpy (htab->plt_bnd->contents + eh->plt_bnd.offset, + plt2_entry, sizeof (elf_x86_64_legacy_plt2_entry)); + + resolved_plt = htab->plt_bnd; + plt_offset = eh->plt_bnd.offset; + } + else + { + /* Fill in the entry in the procedure linkage table. */ + memcpy (plt->contents + h->plt.offset, abed->plt_entry, + abed->plt_entry_size); + + resolved_plt = plt; + plt_offset = h->plt.offset; + } /* Insert the relocation positions of the plt section. */ /* Put offset the PC-relative instruction referring to the GOT entry, subtracting the size of that instruction. */ - bfd_put_32 (output_bfd, - (gotplt->output_section->vma - + gotplt->output_offset - + got_offset - - plt->output_section->vma - - plt->output_offset - - h->plt.offset - - abed->plt_got_insn_size), - plt->contents + h->plt.offset + abed->plt_got_offset); + plt_got_pcrel_offset = (gotplt->output_section->vma + + gotplt->output_offset + + got_offset + - resolved_plt->output_section->vma + - resolved_plt->output_offset + - plt_offset + - plt_got_insn_size); + + /* Check PC-relative offset overflow in PLT entry. */ + if ((plt_got_pcrel_offset + 0x80000000) > 0xffffffff) + info->callbacks->einfo (_("%F%B: PC-relative offset overflow in PLT entry for `%s'\n"), + output_bfd, h->root.root.string); + + bfd_put_32 (output_bfd, plt_got_pcrel_offset, + resolved_plt->contents + plt_offset + plt_got_offset); /* Fill in the entry in the global offset table, initially this points to the second part of the PLT entry. */ @@ -4526,32 +5233,101 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, /* Don't fill PLT entry for static executables. */ if (plt == htab->elf.splt) { + bfd_vma plt0_offset = h->plt.offset + plt_plt_insn_end; + /* Put relocation index. */ bfd_put_32 (output_bfd, plt_index, plt->contents + h->plt.offset + abed->plt_reloc_offset); - /* Put offset for jmp .PLT0. */ - bfd_put_32 (output_bfd, - (h->plt.offset + abed->plt_plt_insn_end), - plt->contents + h->plt.offset + abed->plt_plt_offset); + + /* Put offset for jmp .PLT0 and check for overflow. We don't + check relocation index for overflow since branch displacement + will overflow first. */ + if (plt0_offset > 0x80000000) + info->callbacks->einfo (_("%F%B: branch displacement overflow in PLT entry for `%s'\n"), + output_bfd, h->root.root.string); + bfd_put_32 (output_bfd, - plt0_offset, + plt->contents + h->plt.offset + plt_plt_offset); } bed = get_elf_backend_data (output_bfd); loc = relplt->contents + plt_index * bed->s->sizeof_rela; bed->s->swap_reloca_out (output_bfd, &rela, loc); + } + else if (eh->plt_got.offset != (bfd_vma) -1) + { + bfd_vma got_offset, plt_offset, plt_got_offset, plt_got_insn_size; + asection *plt, *got; + bfd_boolean got_after_plt; + int32_t got_pcrel_offset; + const bfd_byte *got_plt_entry; + + /* Set the entry in the GOT procedure linkage table. */ + plt = htab->plt_got; + got = htab->elf.sgot; + got_offset = h->got.offset; + + if (got_offset == (bfd_vma) -1 + || h->type == STT_GNU_IFUNC + || plt == NULL + || got == NULL) + abort (); - if (!h->def_regular) + /* Use the second PLT entry template for the GOT PLT since they + are the identical. */ + plt_got_insn_size = elf_x86_64_bnd_arch_bed.plt_got_insn_size; + plt_got_offset = elf_x86_64_bnd_arch_bed.plt_got_offset; + if (eh->has_bnd_reloc) + got_plt_entry = elf_x86_64_bnd_plt2_entry; + else { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value if there were any - relocations where pointer equality matters (this is a clue - for the dynamic linker, to make function pointer - comparisons work between an application and shared - library), otherwise set it to zero. If a function is only - called from a binary, there is no need to slow down - shared libraries because of that. */ - sym->st_shndx = SHN_UNDEF; - if (!h->pointer_equality_needed) - sym->st_value = 0; + got_plt_entry = elf_x86_64_legacy_plt2_entry; + + /* Subtract 1 since there is no BND prefix. */ + plt_got_insn_size -= 1; + plt_got_offset -= 1; } + + /* Fill in the entry in the GOT procedure linkage table. */ + plt_offset = eh->plt_got.offset; + memcpy (plt->contents + plt_offset, + got_plt_entry, sizeof (elf_x86_64_legacy_plt2_entry)); + + /* Put offset the PC-relative instruction referring to the GOT + entry, subtracting the size of that instruction. */ + got_pcrel_offset = (got->output_section->vma + + got->output_offset + + got_offset + - plt->output_section->vma + - plt->output_offset + - plt_offset + - plt_got_insn_size); + + /* Check PC-relative offset overflow in GOT PLT entry. */ + got_after_plt = got->output_section->vma > plt->output_section->vma; + if ((got_after_plt && got_pcrel_offset < 0) + || (!got_after_plt && got_pcrel_offset > 0)) + info->callbacks->einfo (_("%F%B: PC-relative offset overflow in GOT PLT entry for `%s'\n"), + output_bfd, h->root.root.string); + + bfd_put_32 (output_bfd, got_pcrel_offset, + plt->contents + plt_offset + plt_got_offset); + } + + if (!h->def_regular + && (h->plt.offset != (bfd_vma) -1 + || eh->plt_got.offset != (bfd_vma) -1)) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value if there were any + relocations where pointer equality matters (this is a clue + for the dynamic linker, to make function pointer + comparisons work between an application and shared + library), otherwise set it to zero. If a function is only + called from a binary, there is no need to slow down + shared libraries because of that. */ + sym->st_shndx = SHN_UNDEF; + if (!h->pointer_equality_needed) + sym->st_value = 0; } if (h->got.offset != (bfd_vma) -1 @@ -4666,7 +5442,9 @@ elf_x86_64_finish_local_dynamic_symbol (void **slot, void *inf) dynamic linker, before writing them out. */ static enum elf_reloc_type_class -elf_x86_64_reloc_type_class (const Elf_Internal_Rela *rela) +elf_x86_64_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, + const asection *rel_sec ATTRIBUTE_UNUSED, + const Elf_Internal_Rela *rela) { switch ((int) ELF32_R_TYPE (rela->r_info)) { @@ -4691,13 +5469,18 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, struct elf_x86_64_link_hash_table *htab; bfd *dynobj; asection *sdyn; - const struct elf_x86_64_backend_data *const abed - = get_elf_x86_64_backend_data (output_bfd); + const struct elf_x86_64_backend_data *abed; htab = elf_x86_64_hash_table (info); if (htab == NULL) return FALSE; + /* Use MPX backend data in case of BND relocation. Use .plt_bnd + section only if there is .plt section. */ + abed = (htab->elf.splt != NULL && htab->plt_bnd != NULL + ? &elf_x86_64_bnd_arch_bed + : get_elf_x86_64_backend_data (output_bfd)); + dynobj = htab->elf.dynobj; sdyn = bfd_get_linker_section (dynobj, ".dynamic"); @@ -4838,6 +5621,10 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, } } + if (htab->plt_bnd != NULL) + elf_section_data (htab->plt_bnd->output_section) + ->this_hdr.sh_entsize = sizeof (elf_x86_64_bnd_plt2_entry); + if (htab->elf.sgotplt) { if (bfd_is_abs_section (htab->elf.sgotplt->output_section)) @@ -4906,24 +5693,133 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, return TRUE; } -/* Return address for Ith PLT stub in section PLT, for relocation REL - or (bfd_vma) -1 if it should not be included. */ +/* Return an array of PLT entry symbol values. */ -static bfd_vma -elf_x86_64_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) +static bfd_vma * +elf_x86_64_get_plt_sym_val (bfd *abfd, asymbol **dynsyms, asection *plt, + asection *relplt) { - return plt->vma + (i + 1) * GET_PLT_ENTRY_SIZE (plt->owner); + bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); + arelent *p; + long count, i; + bfd_vma *plt_sym_val; + bfd_vma plt_offset; + bfd_byte *plt_contents; + const struct elf_x86_64_backend_data *bed; + Elf_Internal_Shdr *hdr; + asection *plt_bnd; + + /* Get the .plt section contents. PLT passed down may point to the + .plt.bnd section. Make sure that PLT always points to the .plt + section. */ + plt_bnd = bfd_get_section_by_name (abfd, ".plt.bnd"); + if (plt_bnd) + { + if (plt != plt_bnd) + abort (); + plt = bfd_get_section_by_name (abfd, ".plt"); + if (plt == NULL) + abort (); + bed = &elf_x86_64_bnd_arch_bed; + } + else + bed = get_elf_x86_64_backend_data (abfd); + + plt_contents = (bfd_byte *) bfd_malloc (plt->size); + if (plt_contents == NULL) + return NULL; + if (!bfd_get_section_contents (abfd, (asection *) plt, + plt_contents, 0, plt->size)) + { +bad_return: + free (plt_contents); + return NULL; + } + + slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; + if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) + goto bad_return; + + hdr = &elf_section_data (relplt)->this_hdr; + count = relplt->size / hdr->sh_entsize; + + plt_sym_val = (bfd_vma *) bfd_malloc (sizeof (bfd_vma) * count); + if (plt_sym_val == NULL) + goto bad_return; + + for (i = 0; i < count; i++) + plt_sym_val[i] = -1; + + plt_offset = bed->plt_entry_size; + p = relplt->relocation; + for (i = 0; i < count; i++, p++) + { + long reloc_index; + + /* Skip unknown relocation. */ + if (p->howto == NULL) + continue; + + if (p->howto->type != R_X86_64_JUMP_SLOT + && p->howto->type != R_X86_64_IRELATIVE) + continue; + + reloc_index = H_GET_32 (abfd, (plt_contents + plt_offset + + bed->plt_reloc_offset)); + if (reloc_index >= count) + abort (); + if (plt_bnd) + { + /* This is the index in .plt section. */ + long plt_index = plt_offset / bed->plt_entry_size; + /* Store VMA + the offset in .plt.bnd section. */ + plt_sym_val[reloc_index] = + (plt_bnd->vma + + (plt_index - 1) * sizeof (elf_x86_64_legacy_plt2_entry)); + } + else + plt_sym_val[reloc_index] = plt->vma + plt_offset; + plt_offset += bed->plt_entry_size; + + /* PR binutils/18437: Skip extra relocations in the .rela.plt + section. */ + if (plt_offset >= plt->size) + break; + } + + free (plt_contents); + + return plt_sym_val; +} + +/* Similar to _bfd_elf_get_synthetic_symtab, with .plt.bnd section + support. */ + +static long +elf_x86_64_get_synthetic_symtab (bfd *abfd, + long symcount, + asymbol **syms, + long dynsymcount, + asymbol **dynsyms, + asymbol **ret) +{ + /* Pass the .plt.bnd section to _bfd_elf_ifunc_get_synthetic_symtab + as PLT if it exists. */ + asection *plt = bfd_get_section_by_name (abfd, ".plt.bnd"); + if (plt == NULL) + plt = bfd_get_section_by_name (abfd, ".plt"); + return _bfd_elf_ifunc_get_synthetic_symtab (abfd, symcount, syms, + dynsymcount, dynsyms, ret, + plt, + elf_x86_64_get_plt_sym_val); } /* Handle an x86-64 specific section when reading an object file. This is called when elfcode.h finds a section with an unknown type. */ static bfd_boolean -elf_x86_64_section_from_shdr (bfd *abfd, - Elf_Internal_Shdr *hdr, - const char *name, - int shindex) +elf_x86_64_section_from_shdr (bfd *abfd, Elf_Internal_Shdr *hdr, + const char *name, int shindex) { if (hdr->sh_type != SHT_X86_64_UNWIND) return FALSE; @@ -4969,9 +5865,10 @@ elf_x86_64_add_symbol_hook (bfd *abfd, return TRUE; } - if ((abfd->flags & DYNAMIC) == 0 - && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)) + if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC + || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE) + && (abfd->flags & DYNAMIC) == 0 + && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; return TRUE; @@ -5038,49 +5935,33 @@ elf_x86_64_common_section (asection *sec) } static bfd_boolean -elf_x86_64_merge_symbol (struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf_link_hash_entry **sym_hash ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym, +elf_x86_64_merge_symbol (struct elf_link_hash_entry *h, + const Elf_Internal_Sym *sym, asection **psec, - bfd_vma *pvalue ATTRIBUTE_UNUSED, - unsigned int *pold_alignment ATTRIBUTE_UNUSED, - bfd_boolean *skip ATTRIBUTE_UNUSED, - bfd_boolean *override ATTRIBUTE_UNUSED, - bfd_boolean *type_change_ok ATTRIBUTE_UNUSED, - bfd_boolean *size_change_ok ATTRIBUTE_UNUSED, - bfd_boolean *newdyn ATTRIBUTE_UNUSED, - bfd_boolean *newdef, - bfd_boolean *newdyncommon ATTRIBUTE_UNUSED, - bfd_boolean *newweak ATTRIBUTE_UNUSED, - bfd *abfd ATTRIBUTE_UNUSED, - asection **sec, - bfd_boolean *olddyn ATTRIBUTE_UNUSED, - bfd_boolean *olddef, - bfd_boolean *olddyncommon ATTRIBUTE_UNUSED, - bfd_boolean *oldweak ATTRIBUTE_UNUSED, + bfd_boolean newdef, + bfd_boolean olddef, bfd *oldbfd, - asection **oldsec) + const asection *oldsec) { /* A normal common symbol and a large common symbol result in a normal common symbol. We turn the large common symbol into a normal one. */ - if (!*olddef + if (!olddef && h->root.type == bfd_link_hash_common - && !*newdef - && bfd_is_com_section (*sec) - && *oldsec != *sec) + && !newdef + && bfd_is_com_section (*psec) + && oldsec != *psec) { if (sym->st_shndx == SHN_COMMON - && (elf_section_flags (*oldsec) & SHF_X86_64_LARGE) != 0) + && (elf_section_flags (oldsec) & SHF_X86_64_LARGE) != 0) { h->root.u.c.p->section = bfd_make_section_old_way (oldbfd, "COMMON"); h->root.u.c.p->section->flags = SEC_ALLOC; } else if (sym->st_shndx == SHN_X86_64_LCOMMON - && (elf_section_flags (*oldsec) & SHF_X86_64_LARGE) == 0) - *psec = *sec = bfd_com_section_ptr; + && (elf_section_flags (oldsec) & SHF_X86_64_LARGE) == 0) + *psec = bfd_com_section_ptr; } return TRUE; @@ -5144,7 +6025,7 @@ static const struct bfd_elf_special_section { NULL, 0, 0, 0, 0 } }; -#define TARGET_LITTLE_SYM bfd_elf64_x86_64_vec +#define TARGET_LITTLE_SYM x86_64_elf64_vec #define TARGET_LITTLE_NAME "elf64-x86-64" #define ELF_ARCH bfd_arch_i386 #define ELF_TARGET_ID X86_64_ELF_DATA @@ -5161,13 +6042,12 @@ static const struct bfd_elf_special_section #define elf_backend_got_header_size (GOT_ENTRY_SIZE*3) #define elf_backend_rela_normal 1 #define elf_backend_plt_alignment 4 +#define elf_backend_extern_protected_data 1 #define elf_info_to_howto elf_x86_64_info_to_howto #define bfd_elf64_bfd_link_hash_table_create \ elf_x86_64_link_hash_table_create -#define bfd_elf64_bfd_link_hash_table_free \ - elf_x86_64_link_hash_table_free #define bfd_elf64_bfd_reloc_type_lookup elf_x86_64_reloc_type_lookup #define bfd_elf64_bfd_reloc_name_lookup \ elf_x86_64_reloc_name_lookup @@ -5191,9 +6071,9 @@ static const struct bfd_elf_special_section #define elf_backend_size_dynamic_sections elf_x86_64_size_dynamic_sections #define elf_backend_always_size_sections elf_x86_64_always_size_sections #define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_plt_sym_val elf_x86_64_plt_sym_val #define elf_backend_object_p elf64_x86_64_elf_object_p #define bfd_elf64_mkobject elf_x86_64_mkobject +#define bfd_elf64_get_synthetic_symtab elf_x86_64_get_synthetic_symtab #define elf_backend_section_from_shdr \ elf_x86_64_section_from_shdr @@ -5219,14 +6099,27 @@ static const struct bfd_elf_special_section #define elf_backend_hash_symbol \ elf_x86_64_hash_symbol -#define elf_backend_post_process_headers _bfd_elf_set_osabi +#include "elf64-target.h" + +/* CloudABI support. */ + +#undef TARGET_LITTLE_SYM +#define TARGET_LITTLE_SYM x86_64_elf64_cloudabi_vec +#undef TARGET_LITTLE_NAME +#define TARGET_LITTLE_NAME "elf64-x86-64-cloudabi" + +#undef ELF_OSABI +#define ELF_OSABI ELFOSABI_CLOUDABI + +#undef elf64_bed +#define elf64_bed elf64_x86_64_cloudabi_bed #include "elf64-target.h" /* FreeBSD support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_x86_64_freebsd_vec +#define TARGET_LITTLE_SYM x86_64_elf64_fbsd_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-x86-64-freebsd" @@ -5241,7 +6134,7 @@ static const struct bfd_elf_special_section /* Solaris 2 support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_x86_64_sol2_vec +#define TARGET_LITTLE_SYM x86_64_elf64_sol2_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-x86-64-sol2" @@ -5268,8 +6161,16 @@ static const struct bfd_elf_special_section /* Native Client support. */ +static bfd_boolean +elf64_x86_64_nacl_elf_object_p (bfd *abfd) +{ + /* Set the right machine number for a NaCl x86-64 ELF64 file. */ + bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x86_64_nacl); + return TRUE; +} + #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_x86_64_nacl_vec +#define TARGET_LITTLE_SYM x86_64_elf64_nacl_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-x86-64-nacl" #undef elf64_bed @@ -5304,7 +6205,7 @@ static const bfd_byte elf_x86_64_nacl_plt0_entry[NACL_PLT_ENTRY_SIZE] = 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) */ + 0x66, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, /* nopw 0x0(%rax,%rax,1) */ /* 32 bytes of nop to pad out to the standard size. */ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, /* excess data32 prefixes */ @@ -5400,17 +6301,29 @@ static const struct elf_x86_64_backend_data elf_x86_64_nacl_arch_bed = #undef elf_backend_arch_data #define elf_backend_arch_data &elf_x86_64_nacl_arch_bed +#undef elf_backend_object_p +#define elf_backend_object_p elf64_x86_64_nacl_elf_object_p #undef elf_backend_modify_segment_map #define elf_backend_modify_segment_map nacl_modify_segment_map #undef elf_backend_modify_program_headers #define elf_backend_modify_program_headers nacl_modify_program_headers +#undef elf_backend_final_write_processing +#define elf_backend_final_write_processing nacl_final_write_processing #include "elf64-target.h" /* Native Client x32 support. */ +static bfd_boolean +elf32_x86_64_nacl_elf_object_p (bfd *abfd) +{ + /* Set the right machine number for a NaCl x86-64 ELF32 file. */ + bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x64_32_nacl); + return TRUE; +} + #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf32_x86_64_nacl_vec +#define TARGET_LITTLE_SYM x86_64_elf32_nacl_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-x86-64-nacl" #undef elf32_bed @@ -5418,18 +6331,18 @@ static const struct elf_x86_64_backend_data elf_x86_64_nacl_arch_bed = #define bfd_elf32_bfd_link_hash_table_create \ elf_x86_64_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_free \ - elf_x86_64_link_hash_table_free #define bfd_elf32_bfd_reloc_type_lookup \ elf_x86_64_reloc_type_lookup #define bfd_elf32_bfd_reloc_name_lookup \ elf_x86_64_reloc_name_lookup #define bfd_elf32_mkobject \ elf_x86_64_mkobject +#define bfd_elf32_get_synthetic_symtab \ + elf_x86_64_get_synthetic_symtab #undef elf_backend_object_p #define elf_backend_object_p \ - elf32_x86_64_elf_object_p + elf32_x86_64_nacl_elf_object_p #undef elf_backend_bfd_from_remote_memory #define elf_backend_bfd_from_remote_memory \ @@ -5448,6 +6361,7 @@ static const struct elf_x86_64_backend_data elf_x86_64_nacl_arch_bed = #undef elf_backend_size_info #undef elf_backend_modify_segment_map #undef elf_backend_modify_program_headers +#undef elf_backend_final_write_processing /* Intel L1OM support. */ @@ -5460,7 +6374,7 @@ elf64_l1om_elf_object_p (bfd *abfd) } #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_l1om_vec +#define TARGET_LITTLE_SYM l1om_elf64_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-l1om" #undef ELF_ARCH @@ -5494,7 +6408,7 @@ elf64_l1om_elf_object_p (bfd *abfd) /* FreeBSD L1OM support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_l1om_freebsd_vec +#define TARGET_LITTLE_SYM l1om_elf64_fbsd_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-l1om-freebsd" @@ -5517,7 +6431,7 @@ elf64_k1om_elf_object_p (bfd *abfd) } #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_k1om_vec +#define TARGET_LITTLE_SYM k1om_elf64_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-k1om" #undef ELF_ARCH @@ -5544,7 +6458,7 @@ elf64_k1om_elf_object_p (bfd *abfd) /* FreeBSD K1OM support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_k1om_freebsd_vec +#define TARGET_LITTLE_SYM k1om_elf64_fbsd_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-k1om-freebsd" @@ -5559,7 +6473,7 @@ elf64_k1om_elf_object_p (bfd *abfd) /* 32bit x86-64 support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf32_x86_64_vec +#define TARGET_LITTLE_SYM x86_64_elf32_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-x86-64" #undef elf32_bed diff --git a/contrib/gdb-7/bfd/elf64.c b/contrib/gdb-7/bfd/elf64.c index 04fd3f0b41..74726648fd 100644 --- a/contrib/gdb-7/bfd/elf64.c +++ b/contrib/gdb-7/bfd/elf64.c @@ -1,5 +1,5 @@ /* ELF 64-bit executable support for BFD. - Copyright 1993, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 1993-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. diff --git a/contrib/gdb-7/bfd/elfcode.h b/contrib/gdb-7/bfd/elfcode.h index e296c5ce78..7e309cf998 100644 --- a/contrib/gdb-7/bfd/elfcode.h +++ b/contrib/gdb-7/bfd/elfcode.h @@ -1,7 +1,5 @@ /* ELF executable support for BFD. - Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 - Free Software Foundation, Inc. + Copyright (C) 1991-2015 Free Software Foundation, Inc. Written by Fred Fish @ Cygnus Support, from information published in "UNIX System V Release 4, Programmers Guide: ANSI C and @@ -73,6 +71,7 @@ #include "bfdlink.h" #include "libbfd.h" #include "elf-bfd.h" +#include "libiberty.h" /* Renaming structures, typedefs, macros and functions to be size-specific. */ #define Elf_External_Ehdr NAME(Elf,External_Ehdr) @@ -713,7 +712,7 @@ elf_object_p (bfd *abfd) switch (ebd->elf_machine_code) { case EM_386: - case EM_486: + case EM_IAMCU: case EM_X86_64: case EM_OLD_SPARCV9: case EM_SPARC32PLUS: @@ -1215,10 +1214,9 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic) for (isym = isymbuf + 1, sym = symbase; isym < isymend; isym++, sym++) { memcpy (&sym->internal_elf_sym, isym, sizeof (Elf_Internal_Sym)); - sym->symbol.the_bfd = abfd; + sym->symbol.the_bfd = abfd; sym->symbol.name = bfd_elf_sym_name (abfd, hdr, isym, NULL); - sym->symbol.value = isym->st_value; if (isym->st_shndx == SHN_UNDEF) @@ -1502,7 +1500,9 @@ elf_slurp_reloc_table (bfd *abfd, rel_hdr2 = d->rela.hdr; reloc_count2 = rel_hdr2 ? NUM_SHDR_ENTRIES (rel_hdr2) : 0; - BFD_ASSERT (asect->reloc_count == reloc_count + reloc_count2); + /* PR 17512: file: 0b4f81b7. */ + if (asect->reloc_count != reloc_count + reloc_count2) + return FALSE; BFD_ASSERT ((rel_hdr && asect->rel_filepos == rel_hdr->sh_offset) || (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset)); @@ -1588,37 +1588,40 @@ elf_debug_file (Elf_Internal_Ehdr *ehdrp) #endif /* Create a new BFD as if by bfd_openr. Rather than opening a file, - reconstruct an ELF file by reading the segments out of remote memory - based on the ELF file header at EHDR_VMA and the ELF program headers it - points to. If not null, *LOADBASEP is filled in with the difference - between the VMAs from which the segments were read, and the VMAs the - file headers (and hence BFD's idea of each section's VMA) put them at. - - The function TARGET_READ_MEMORY is called to copy LEN bytes from the - remote memory at target address VMA into the local buffer at MYADDR; it - should return zero on success or an `errno' code on failure. TEMPL must - be a BFD for a target with the word size and byte order found in the - remote memory. */ + reconstruct an ELF file by reading the segments out of remote + memory based on the ELF file header at EHDR_VMA and the ELF program + headers it points to. If non-zero, SIZE is the known extent of the + object. If not null, *LOADBASEP is filled in with the difference + between the VMAs from which the segments were read, and the VMAs + the file headers (and hence BFD's idea of each section's VMA) put + them at. + + The function TARGET_READ_MEMORY is called to copy LEN bytes from + the remote memory at target address VMA into the local buffer at + MYADDR; it should return zero on success or an `errno' code on + failure. TEMPL must be a BFD for a target with the word size and + byte order found in the remote memory. */ bfd * NAME(_bfd_elf,bfd_from_remote_memory) (bfd *templ, bfd_vma ehdr_vma, + bfd_size_type size, bfd_vma *loadbasep, int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type)) { Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ Elf_Internal_Ehdr i_ehdr; /* Elf file header, internal form */ Elf_External_Phdr *x_phdrs; - Elf_Internal_Phdr *i_phdrs, *last_phdr; + Elf_Internal_Phdr *i_phdrs, *last_phdr, *first_phdr; bfd *nbfd; struct bfd_in_memory *bim; - int contents_size; bfd_byte *contents; int err; unsigned int i; + bfd_vma high_offset; + bfd_vma shdr_end; bfd_vma loadbase; - bfd_boolean loadbase_set; /* Read in the ELF header in external format. */ err = target_read_memory (ehdr_vma, (bfd_byte *) &x_ehdr, sizeof x_ehdr); @@ -1678,10 +1681,7 @@ NAME(_bfd_elf,bfd_from_remote_memory) x_phdrs = (Elf_External_Phdr *) bfd_malloc (i_ehdr.e_phnum * (sizeof *x_phdrs + sizeof *i_phdrs)); if (x_phdrs == NULL) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } + return NULL; err = target_read_memory (ehdr_vma + i_ehdr.e_phoff, (bfd_byte *) x_phdrs, i_ehdr.e_phnum * sizeof x_phdrs[0]); if (err) @@ -1693,34 +1693,44 @@ NAME(_bfd_elf,bfd_from_remote_memory) } i_phdrs = (Elf_Internal_Phdr *) &x_phdrs[i_ehdr.e_phnum]; - contents_size = 0; + high_offset = 0; + loadbase = 0; + first_phdr = NULL; last_phdr = NULL; - loadbase = ehdr_vma; - loadbase_set = FALSE; for (i = 0; i < i_ehdr.e_phnum; ++i) { elf_swap_phdr_in (templ, &x_phdrs[i], &i_phdrs[i]); if (i_phdrs[i].p_type == PT_LOAD) { - bfd_vma segment_end; - segment_end = (i_phdrs[i].p_offset + i_phdrs[i].p_filesz - + i_phdrs[i].p_align - 1) & -i_phdrs[i].p_align; - if (segment_end > (bfd_vma) contents_size) - contents_size = segment_end; - - /* LOADADDR is the `Base address' from the gELF specification: - `lowest p_vaddr value for a PT_LOAD segment' is P_VADDR from the - first PT_LOAD as PT_LOADs are ordered by P_VADDR. */ - if (!loadbase_set && (i_phdrs[i].p_offset & -i_phdrs[i].p_align) == 0) + bfd_vma segment_end = i_phdrs[i].p_offset + i_phdrs[i].p_filesz; + + if (segment_end > high_offset) { - loadbase = ehdr_vma - (i_phdrs[i].p_vaddr & -i_phdrs[i].p_align); - loadbase_set = TRUE; + high_offset = segment_end; + last_phdr = &i_phdrs[i]; } - last_phdr = &i_phdrs[i]; + /* If this program header covers offset zero, where the file + header sits, then we can figure out the loadbase. */ + if (first_phdr == NULL) + { + bfd_vma p_offset = i_phdrs[i].p_offset; + bfd_vma p_vaddr = i_phdrs[i].p_vaddr; + + if (i_phdrs[i].p_align > 1) + { + p_offset &= -i_phdrs[i].p_align; + p_vaddr &= -i_phdrs[i].p_align; + } + if (p_offset == 0) + { + loadbase = ehdr_vma - p_vaddr; + first_phdr = &i_phdrs[i]; + } + } } } - if (last_phdr == NULL) + if (high_offset == 0) { /* There were no PT_LOAD segments, so we don't have anything to read. */ free (x_phdrs); @@ -1728,40 +1738,64 @@ NAME(_bfd_elf,bfd_from_remote_memory) return NULL; } - /* Trim the last segment so we don't bother with zeros in the last page - that are off the end of the file. However, if the extra bit in that - page includes the section headers, keep them. */ - if ((bfd_vma) contents_size > last_phdr->p_offset + last_phdr->p_filesz - && (bfd_vma) contents_size >= (i_ehdr.e_shoff - + i_ehdr.e_shnum * i_ehdr.e_shentsize)) + shdr_end = 0; + if (i_ehdr.e_shoff != 0 && i_ehdr.e_shnum != 0 && i_ehdr.e_shentsize != 0) { - contents_size = last_phdr->p_offset + last_phdr->p_filesz; - if ((bfd_vma) contents_size < (i_ehdr.e_shoff - + i_ehdr.e_shnum * i_ehdr.e_shentsize)) - contents_size = i_ehdr.e_shoff + i_ehdr.e_shnum * i_ehdr.e_shentsize; + shdr_end = i_ehdr.e_shoff + i_ehdr.e_shnum * i_ehdr.e_shentsize; + + if (last_phdr->p_filesz != last_phdr->p_memsz) + { + /* If the last PT_LOAD header has a bss area then ld.so will + have cleared anything past p_filesz, zapping the section + headers. */ + } + else if (size >= shdr_end) + high_offset = size; + else + { + bfd_vma page_size = get_elf_backend_data (templ)->minpagesize; + bfd_vma segment_end = last_phdr->p_offset + last_phdr->p_filesz; + + /* Assume we loaded full pages, allowing us to sometimes see + section headers. */ + if (page_size > 1 && shdr_end > segment_end) + { + bfd_vma page_end = (segment_end + page_size - 1) & -page_size; + + if (page_end >= shdr_end) + /* Whee, section headers covered. */ + high_offset = shdr_end; + } + } } - else - contents_size = last_phdr->p_offset + last_phdr->p_filesz; /* Now we know the size of the whole image we want read in. */ - contents = (bfd_byte *) bfd_zmalloc (contents_size); + contents = (bfd_byte *) bfd_zmalloc (high_offset); if (contents == NULL) { free (x_phdrs); - bfd_set_error (bfd_error_no_memory); return NULL; } for (i = 0; i < i_ehdr.e_phnum; ++i) if (i_phdrs[i].p_type == PT_LOAD) { - bfd_vma start = i_phdrs[i].p_offset & -i_phdrs[i].p_align; - bfd_vma end = (i_phdrs[i].p_offset + i_phdrs[i].p_filesz - + i_phdrs[i].p_align - 1) & -i_phdrs[i].p_align; - if (end > (bfd_vma) contents_size) - end = contents_size; - err = target_read_memory ((loadbase + i_phdrs[i].p_vaddr) - & -i_phdrs[i].p_align, + bfd_vma start = i_phdrs[i].p_offset; + bfd_vma end = start + i_phdrs[i].p_filesz; + bfd_vma vaddr = i_phdrs[i].p_vaddr; + + /* Extend the beginning of the first pt_load to cover file + header and program headers, if we proved earlier that its + aligned offset is 0. */ + if (first_phdr == &i_phdrs[i]) + { + vaddr -= start; + start = 0; + } + /* Extend the end of the last pt_load to cover section headers. */ + if (last_phdr == &i_phdrs[i]) + end = high_offset; + err = target_read_memory (loadbase + vaddr, contents + start, end - start); if (err) { @@ -1776,8 +1810,7 @@ NAME(_bfd_elf,bfd_from_remote_memory) /* If the segments visible in memory didn't include the section headers, then clear them from the file header. */ - if ((bfd_vma) contents_size < (i_ehdr.e_shoff - + i_ehdr.e_shnum * i_ehdr.e_shentsize)) + if (high_offset < shdr_end) { memset (&x_ehdr.e_shoff, 0, sizeof x_ehdr.e_shoff); memset (&x_ehdr.e_shnum, 0, sizeof x_ehdr.e_shnum); @@ -1793,7 +1826,6 @@ NAME(_bfd_elf,bfd_from_remote_memory) if (bim == NULL) { free (contents); - bfd_set_error (bfd_error_no_memory); return NULL; } nbfd = _bfd_new_bfd (); @@ -1801,12 +1833,11 @@ NAME(_bfd_elf,bfd_from_remote_memory) { free (bim); free (contents); - bfd_set_error (bfd_error_no_memory); return NULL; } - nbfd->filename = ""; + nbfd->filename = xstrdup (""); nbfd->xvec = templ->xvec; - bim->size = contents_size; + bim->size = high_offset; bim->buffer = contents; nbfd->iostream = bim; nbfd->flags = BFD_IN_MEMORY; diff --git a/contrib/gdb-7/bfd/elfcore.h b/contrib/gdb-7/bfd/elfcore.h index 429c09c758..c4e5b43c6b 100644 --- a/contrib/gdb-7/bfd/elfcore.h +++ b/contrib/gdb-7/bfd/elfcore.h @@ -1,6 +1,5 @@ /* ELF core file support for BFD. - Copyright 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2005, 2007, - 2008, 2010 Free Software Foundation, Inc. + Copyright (C) 1995-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. diff --git a/contrib/gdb-7/bfd/elflink.c b/contrib/gdb-7/bfd/elflink.c index ba65f21aaa..1c0861ba3a 100644 --- a/contrib/gdb-7/bfd/elflink.c +++ b/contrib/gdb-7/bfd/elflink.c @@ -1,7 +1,5 @@ /* ELF linking support for BFD. - Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 - Free Software Foundation, Inc. + Copyright (C) 1995-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -22,6 +20,7 @@ #include "sysdep.h" #include "bfd.h" +#include "bfd_stdint.h" #include "bfdlink.h" #include "libbfd.h" #define ARCH_SIZE 0 @@ -55,6 +54,47 @@ struct elf_find_verdep_info static bfd_boolean _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *, struct elf_info_failed *); +asection * +_bfd_elf_section_for_symbol (struct elf_reloc_cookie *cookie, + unsigned long r_symndx, + bfd_boolean discard) +{ + if (r_symndx >= cookie->locsymcount + || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL) + { + struct elf_link_hash_entry *h; + + h = cookie->sym_hashes[r_symndx - cookie->extsymoff]; + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && discarded_section (h->root.u.def.section)) + return h->root.u.def.section; + else + return NULL; + } + else + { + /* It's not a relocation against a global symbol, + but it could be a relocation against a local + symbol for a discarded section. */ + asection *isec; + Elf_Internal_Sym *isym; + + /* Need to: get the symbol; get the section. */ + isym = &cookie->locsyms[r_symndx]; + isec = bfd_section_from_elf_index (cookie->abfd, isym->st_shndx); + if (isec != NULL + && discard ? discarded_section (isec) : 1) + return isec; + } + return NULL; +} + /* Define a symbol in a dynamic linkage section. */ struct elf_link_hash_entry * @@ -78,18 +118,19 @@ _bfd_elf_define_linkage_sym (bfd *abfd, } bh = &h->root; + bed = get_elf_backend_data (abfd); if (!_bfd_generic_link_add_one_symbol (info, abfd, name, BSF_GLOBAL, - sec, 0, NULL, FALSE, - get_elf_backend_data (abfd)->collect, + sec, 0, NULL, FALSE, bed->collect, &bh)) return NULL; h = (struct elf_link_hash_entry *) bh; h->def_regular = 1; h->non_elf = 0; + h->root.linker_def = 1; h->type = STT_OBJECT; - h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; + if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL) + h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; - bed = get_elf_backend_data (abfd); (*bed->elf_backend_hide_symbol) (info, h, TRUE); return h; } @@ -575,7 +616,8 @@ bfd_elf_record_link_assignment (bfd *output_bfd, if (hidden) { bed = get_elf_backend_data (output_bfd); - h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; + if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL) + h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; (*bed->elf_backend_hide_symbol) (info, h, TRUE); } @@ -760,6 +802,7 @@ _bfd_elf_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, asection *p) { struct elf_link_hash_table *htab; + asection *ip; switch (elf_section_data (p)->this_hdr.sh_type) { @@ -775,18 +818,9 @@ _bfd_elf_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, if (htab->text_index_section != NULL) return p != htab->text_index_section && p != htab->data_index_section; - if (strcmp (p->name, ".got") == 0 - || strcmp (p->name, ".got.plt") == 0 - || strcmp (p->name, ".plt") == 0) - { - asection *ip; - - if (htab->dynobj != NULL + return (htab->dynobj != NULL && (ip = bfd_get_linker_section (htab->dynobj, p->name)) != NULL - && ip->output_section == p) - return TRUE; - } - return FALSE; + && ip->output_section == p); /* There shouldn't be section relative relocations against any other section. */ @@ -851,72 +885,57 @@ _bfd_elf_link_renumber_dynsyms (bfd *output_bfd, static void elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h, - Elf_Internal_Sym *isym, bfd_boolean definition, - bfd_boolean dynamic) + const Elf_Internal_Sym *isym, asection *sec, + bfd_boolean definition, bfd_boolean dynamic) { const struct elf_backend_data *bed = get_elf_backend_data (abfd); /* If st_other has a processor-specific meaning, specific - code might be needed here. We never merge the visibility - attribute with the one from a dynamic object. */ + code might be needed here. */ if (bed->elf_backend_merge_symbol_attribute) (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition, dynamic); - /* If this symbol has default visibility and the user has requested - we not re-export it, then mark it as hidden. */ - if (definition - && !dynamic - && (abfd->no_export - || (abfd->my_archive && abfd->my_archive->no_export)) - && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL) - isym->st_other = (STV_HIDDEN - | (isym->st_other & ~ELF_ST_VISIBILITY (-1))); - - if (!dynamic && ELF_ST_VISIBILITY (isym->st_other) != 0) - { - unsigned char hvis, symvis, other, nvis; - - /* Only merge the visibility. Leave the remainder of the - st_other field to elf_backend_merge_symbol_attribute. */ - other = h->other & ~ELF_ST_VISIBILITY (-1); - - /* Combine visibilities, using the most constraining one. */ - hvis = ELF_ST_VISIBILITY (h->other); - symvis = ELF_ST_VISIBILITY (isym->st_other); - if (! hvis) - nvis = symvis; - else if (! symvis) - nvis = hvis; - else - nvis = hvis < symvis ? hvis : symvis; + if (!dynamic) + { + unsigned symvis = ELF_ST_VISIBILITY (isym->st_other); + unsigned hvis = ELF_ST_VISIBILITY (h->other); - h->other = other | nvis; + /* Keep the most constraining visibility. Leave the remainder + of the st_other field to elf_backend_merge_symbol_attribute. */ + if (symvis - 1 < hvis - 1) + h->other = symvis | (h->other & ~ELF_ST_VISIBILITY (-1)); } + else if (definition + && ELF_ST_VISIBILITY (isym->st_other) != STV_DEFAULT + && (sec->flags & SEC_READONLY) == 0) + h->protected_def = 1; } -/* This function is called when we want to define a new symbol. It - handles the various cases which arise when we find a definition in - a dynamic object, or when there is already a definition in a - dynamic object. The new symbol is described by NAME, SYM, PSEC, - and PVALUE. We set SYM_HASH to the hash table entry. We set - OVERRIDE if the old symbol is overriding a new definition. We set - TYPE_CHANGE_OK if it is OK for the type to change. We set - SIZE_CHANGE_OK if it is OK for the size to change. By OK to - change, we mean that we shouldn't warn if the type or size does - change. We set POLD_ALIGNMENT if an old common symbol in a dynamic - object is overridden by a regular object. */ +/* This function is called when we want to merge a new symbol with an + existing symbol. It handles the various cases which arise when we + find a definition in a dynamic object, or when there is already a + definition in a dynamic object. The new symbol is described by + NAME, SYM, PSEC, and PVALUE. We set SYM_HASH to the hash table + entry. We set POLDBFD to the old symbol's BFD. We set POLD_WEAK + if the old symbol was weak. We set POLD_ALIGNMENT to the alignment + of an old common symbol. We set OVERRIDE if the old symbol is + overriding a new definition. We set TYPE_CHANGE_OK if it is OK for + the type to change. We set SIZE_CHANGE_OK if it is OK for the size + to change. By OK to change, we mean that we shouldn't warn if the + type or size does change. */ -bfd_boolean +static bfd_boolean _bfd_elf_merge_symbol (bfd *abfd, struct bfd_link_info *info, const char *name, Elf_Internal_Sym *sym, asection **psec, bfd_vma *pvalue, + struct elf_link_hash_entry **sym_hash, + bfd **poldbfd, bfd_boolean *pold_weak, unsigned int *pold_alignment, - struct elf_link_hash_entry **sym_hash, bfd_boolean *skip, bfd_boolean *override, bfd_boolean *type_change_ok, @@ -938,15 +957,6 @@ _bfd_elf_merge_symbol (bfd *abfd, sec = *psec; bind = ELF_ST_BIND (sym->st_info); - /* Silently discard TLS symbols from --just-syms. There's no way to - combine a static TLS block with a new TLS block for this executable. */ - if (ELF_ST_TYPE (sym->st_info) == STT_TLS - && sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) - { - *skip = TRUE; - return TRUE; - } - if (! bfd_is_und_section (sec)) h = elf_link_hash_lookup (elf_hash_table (info), name, TRUE, FALSE, FALSE); else @@ -958,11 +968,6 @@ _bfd_elf_merge_symbol (bfd *abfd, bed = get_elf_backend_data (abfd); - /* This code is for coping with dynamic objects, and is only useful - if we are doing an ELF link. */ - if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec)) - return TRUE; - /* For merging, we only care about real symbols. But we need to make sure that indirect symbol dynamic flags are updated. */ hi = h; @@ -970,6 +975,49 @@ _bfd_elf_merge_symbol (bfd *abfd, || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; + /* OLDBFD and OLDSEC are a BFD and an ASECTION associated with the + existing symbol. */ + + oldbfd = NULL; + oldsec = NULL; + switch (h->root.type) + { + default: + break; + + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + oldbfd = h->root.u.undef.abfd; + break; + + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + oldbfd = h->root.u.def.section->owner; + oldsec = h->root.u.def.section; + break; + + case bfd_link_hash_common: + oldbfd = h->root.u.c.p->section->owner; + oldsec = h->root.u.c.p->section; + if (pold_alignment) + *pold_alignment = h->root.u.c.p->alignment_power; + break; + } + if (poldbfd && *poldbfd == NULL) + *poldbfd = oldbfd; + + /* Differentiate strong and weak symbols. */ + newweak = bind == STB_WEAK; + oldweak = (h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_undefweak); + if (pold_weak) + *pold_weak = oldweak; + + /* This code is for coping with dynamic objects, and is only useful + if we are doing an ELF link. */ + if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec)) + return TRUE; + /* We have to check it for every instance since the first few may be references and not all compilers emit symbol type for undefined symbols. */ @@ -1014,41 +1062,6 @@ _bfd_elf_merge_symbol (bfd *abfd, return TRUE; } - /* OLDBFD and OLDSEC are a BFD and an ASECTION associated with the - existing symbol. */ - - switch (h->root.type) - { - default: - oldbfd = NULL; - oldsec = NULL; - break; - - case bfd_link_hash_undefined: - case bfd_link_hash_undefweak: - oldbfd = h->root.u.undef.abfd; - oldsec = NULL; - break; - - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - oldbfd = h->root.u.def.section->owner; - oldsec = h->root.u.def.section; - break; - - case bfd_link_hash_common: - oldbfd = h->root.u.c.p->section->owner; - oldsec = h->root.u.c.p->section; - break; - } - - /* Differentiate strong and weak symbols. */ - newweak = bind == STB_WEAK; - oldweak = (h->root.type == bfd_link_hash_defweak - || h->root.type == bfd_link_hash_undefweak); - if (pold_weak) - *pold_weak = oldweak; - /* In cases involving weak versioned symbols, we may wind up trying to merge a symbol with itself. Catch that here, to avoid the confusion that results if we try to override a symbol with @@ -1091,34 +1104,32 @@ _bfd_elf_merge_symbol (bfd *abfd, /* When we try to create a default indirect symbol from the dynamic definition with the default version, we skip it if its type and - the type of existing regular definition mismatch. We only do it - if the existing regular definition won't be dynamic. */ + the type of existing regular definition mismatch. */ if (pold_alignment == NULL - && !info->shared - && !info->export_dynamic - && !h->ref_dynamic && newdyn && newdef && !olddyn - && (olddef || h->root.type == bfd_link_hash_common) - && ELF_ST_TYPE (sym->st_info) != h->type - && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE - && h->type != STT_NOTYPE - && !(newfunc && oldfunc)) + && (((olddef || h->root.type == bfd_link_hash_common) + && ELF_ST_TYPE (sym->st_info) != h->type + && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE + && h->type != STT_NOTYPE + && !(newfunc && oldfunc)) + || (olddef + && ((h->type == STT_GNU_IFUNC) + != (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))))) { *skip = TRUE; return TRUE; } - /* Plugin symbol type isn't currently set. Stop bogus errors. */ - if (oldbfd != NULL && (oldbfd->flags & BFD_PLUGIN) != 0) - *type_change_ok = TRUE; - - /* Check TLS symbol. We don't check undefined symbol introduced by - "ld -u". */ - else if (oldbfd != NULL - && ELF_ST_TYPE (sym->st_info) != h->type - && (ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS)) + /* Check TLS symbols. We don't check undefined symbols introduced + by "ld -u" which have no type (and oldbfd NULL), and we don't + check symbols from plugins because they also have no type. */ + if (oldbfd != NULL + && (oldbfd->flags & BFD_PLUGIN) == 0 + && (abfd->flags & BFD_PLUGIN) == 0 + && ELF_ST_TYPE (sym->st_info) != h->type + && (ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS)) { bfd *ntbfd, *tbfd; bfd_boolean ntdef, tdef; @@ -1145,19 +1156,23 @@ _bfd_elf_merge_symbol (bfd *abfd, if (tdef && ntdef) (*_bfd_error_handler) - (_("%s: TLS definition in %B section %A mismatches non-TLS definition in %B section %A"), + (_("%s: TLS definition in %B section %A " + "mismatches non-TLS definition in %B section %A"), tbfd, tsec, ntbfd, ntsec, h->root.root.string); else if (!tdef && !ntdef) (*_bfd_error_handler) - (_("%s: TLS reference in %B mismatches non-TLS reference in %B"), + (_("%s: TLS reference in %B " + "mismatches non-TLS reference in %B"), tbfd, ntbfd, h->root.root.string); else if (tdef) (*_bfd_error_handler) - (_("%s: TLS definition in %B section %A mismatches non-TLS reference in %B"), + (_("%s: TLS definition in %B section %A " + "mismatches non-TLS reference in %B"), tbfd, tsec, ntbfd, h->root.root.string); else (*_bfd_error_handler) - (_("%s: TLS reference in %B mismatches non-TLS definition in %B section %A"), + (_("%s: TLS reference in %B " + "mismatches non-TLS definition in %B section %A"), tbfd, ntbfd, ntsec, h->root.root.string); bfd_set_error (bfd_error_bad_value); @@ -1190,7 +1205,7 @@ _bfd_elf_merge_symbol (bfd *abfd, /* If the new symbol with non-default visibility comes from a relocatable file and the old definition comes from a dynamic object, we remove the old definition. */ - if ((*sym_hash)->root.type == bfd_link_hash_indirect) + if (hi->root.type == bfd_link_hash_indirect) { /* Handle the case where the old dynamic definition is default versioned. We need to copy the symbol info from @@ -1198,13 +1213,11 @@ _bfd_elf_merge_symbol (bfd *abfd, was referenced before. */ if (h->ref_regular) { - struct elf_link_hash_entry *vh = *sym_hash; - - vh->root.type = h->root.type; + hi->root.type = h->root.type; h->root.type = bfd_link_hash_indirect; - (*bed->elf_backend_copy_indirect_symbol) (info, vh, h); + (*bed->elf_backend_copy_indirect_symbol) (info, hi, h); - h->root.u.i.link = (struct bfd_link_hash_entry *) vh; + h->root.u.i.link = (struct bfd_link_hash_entry *) hi; if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED) { /* If the new symbol is hidden or internal, completely undo @@ -1221,10 +1234,10 @@ _bfd_elf_merge_symbol (bfd *abfd, h->size = 0; h->type = 0; - h = vh; + h = hi; } else - h = *sym_hash; + h = hi; } /* If the old symbol was undefined before, then it will still be @@ -1347,15 +1360,12 @@ _bfd_elf_merge_symbol (bfd *abfd, /* We now know everything about the old and new symbols. We ask the backend to check if we can merge them. */ - if (bed->merge_symbol - && !bed->merge_symbol (info, sym_hash, h, sym, psec, pvalue, - pold_alignment, skip, override, - type_change_ok, size_change_ok, - &newdyn, &newdef, &newdyncommon, &newweak, - abfd, &sec, - &olddyn, &olddef, &olddyncommon, &oldweak, - oldbfd, &oldsec)) - return FALSE; + if (bed->merge_symbol != NULL) + { + if (!bed->merge_symbol (h, sym, psec, newdef, olddef, oldbfd, oldsec)) + return FALSE; + sec = *psec; + } /* If both the old and the new symbols look like common symbols in a dynamic object, set the size of the symbol to the larger of the @@ -1442,12 +1452,15 @@ _bfd_elf_merge_symbol (bfd *abfd, if (!(oldbfd != NULL && (oldbfd->flags & BFD_PLUGIN) != 0 && (abfd->flags & BFD_PLUGIN) == 0)) - *skip = TRUE; + { + newdef = FALSE; + *skip = TRUE; + } /* Merge st_other. If the symbol already has a dynamic index, but visibility says it should not be visible, turn it into a local symbol. */ - elf_merge_st_other (abfd, h, sym, newdef, newdyn); + elf_merge_st_other (abfd, h, sym, sec, newdef, newdyn); if (h->dynindx != -1) switch (ELF_ST_VISIBILITY (h->other)) { @@ -1504,8 +1517,8 @@ _bfd_elf_merge_symbol (bfd *abfd, *type_change_ok = TRUE; } - if ((*sym_hash)->root.type == bfd_link_hash_indirect) - flip = *sym_hash; + if (hi->root.type == bfd_link_hash_indirect) + flip = hi; else /* This union may have been set to be non-NULL when this symbol was seen in a dynamic object. We must force the union to be @@ -1550,8 +1563,8 @@ _bfd_elf_merge_symbol (bfd *abfd, *size_change_ok = TRUE; *type_change_ok = TRUE; - if ((*sym_hash)->root.type == bfd_link_hash_indirect) - flip = *sym_hash; + if (hi->root.type == bfd_link_hash_indirect) + flip = hi; else h->verinfo.vertree = NULL; } @@ -1578,7 +1591,7 @@ _bfd_elf_merge_symbol (bfd *abfd, /* This function is called to create an indirect symbol from the default for the symbol with the default version if needed. The - symbol is described by H, NAME, SYM, PSEC, VALUE, and OVERRIDE. We + symbol is described by H, NAME, SYM, SEC, and VALUE. We set DYNSYM if the new indirect symbol is dynamic. */ static bfd_boolean @@ -1587,10 +1600,10 @@ _bfd_elf_add_default_symbol (bfd *abfd, struct elf_link_hash_entry *h, const char *name, Elf_Internal_Sym *sym, - asection **psec, - bfd_vma *value, - bfd_boolean *dynsym, - bfd_boolean override) + asection *sec, + bfd_vma value, + bfd **poldbfd, + bfd_boolean *dynsym) { bfd_boolean type_change_ok; bfd_boolean size_change_ok; @@ -1601,9 +1614,10 @@ _bfd_elf_add_default_symbol (bfd *abfd, const struct elf_backend_data *bed; bfd_boolean collect; bfd_boolean dynamic; + bfd_boolean override; char *p; size_t len, shortlen; - asection *sec; + asection *tmp_sec; /* If this symbol has a version, and it is the default version, we create an indirect symbol from the default name to the fully @@ -1613,24 +1627,6 @@ _bfd_elf_add_default_symbol (bfd *abfd, if (p == NULL || p[1] != ELF_VER_CHR) return TRUE; - if (override) - { - /* We are overridden by an old definition. We need to check if we - need to create the indirect symbol from the default name. */ - hi = elf_link_hash_lookup (elf_hash_table (info), name, TRUE, - FALSE, FALSE); - BFD_ASSERT (hi != NULL); - if (hi == h) - return TRUE; - while (hi->root.type == bfd_link_hash_indirect - || hi->root.type == bfd_link_hash_warning) - { - hi = (struct elf_link_hash_entry *) hi->root.u.i.link; - if (hi == h) - return TRUE; - } - } - bed = get_elf_backend_data (abfd); collect = bed->collect; dynamic = (abfd->flags & DYNAMIC) != 0; @@ -1648,9 +1644,9 @@ _bfd_elf_add_default_symbol (bfd *abfd, actually going to define an indirect symbol. */ type_change_ok = FALSE; size_change_ok = FALSE; - sec = *psec; - if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value, - NULL, NULL, &hi, &skip, &override, + tmp_sec = sec; + if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value, + &hi, poldbfd, NULL, NULL, &skip, &override, &type_change_ok, &size_change_ok)) return FALSE; @@ -1724,6 +1720,12 @@ _bfd_elf_add_default_symbol (bfd *abfd, ht = (struct elf_link_hash_entry *) hi->root.u.i.link; (*bed->elf_backend_copy_indirect_symbol) (info, ht, hi); + /* A reference to the SHORTNAME symbol from a dynamic library + will be satisfied by the versioned symbol at runtime. In + effect, we have a reference to the versioned symbol. */ + ht->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak; + hi->dynamic_def |= ht->dynamic_def; + /* See if the new flags lead us to realize that the symbol must be dynamic. */ if (! *dynsym) @@ -1757,9 +1759,9 @@ nondefault: /* Once again, merge with any existing symbol. */ type_change_ok = FALSE; size_change_ok = FALSE; - sec = *psec; - if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value, - NULL, NULL, &hi, &skip, &override, + tmp_sec = sec; + if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value, + &hi, poldbfd, NULL, NULL, &skip, &override, &type_change_ok, &size_change_ok)) return FALSE; @@ -1793,6 +1795,8 @@ nondefault: if (hi->root.type == bfd_link_hash_indirect) { (*bed->elf_backend_copy_indirect_symbol) (info, h, hi); + h->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak; + hi->dynamic_def |= h->dynamic_def; /* See if the new flags lead us to realize that the symbol must be dynamic. */ @@ -1866,7 +1870,9 @@ _bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h, if (!h->def_dynamic || h->def_regular || h->dynindx == -1 - || h->verinfo.verdef == NULL) + || h->verinfo.verdef == NULL + || (elf_dyn_lib_class (h->verinfo.verdef->vd_bfd) + & (DYN_AS_NEEDED | DYN_DT_NEEDED | DYN_NO_NEEDED))) return TRUE; /* See if we already know about this version. */ @@ -2317,8 +2323,8 @@ _bfd_elf_link_size_reloc_section (bfd *abfd, { struct elf_link_hash_entry **p; - p = (struct elf_link_hash_entry **) - bfd_zmalloc (reldata->count * sizeof (struct elf_link_hash_entry *)); + p = ((struct elf_link_hash_entry **) + bfd_zmalloc (reldata->count * sizeof (*p))); if (p == NULL) return FALSE; @@ -2491,7 +2497,7 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h, && !h->def_regular && h->ref_regular && !h->def_dynamic - && (h->root.u.def.section->owner->flags & DYNAMIC) == 0) + && (h->root.u.def.section->owner->flags & (DYNAMIC | BFD_PLUGIN)) == 0) h->def_regular = 1; /* If -Bsymbolic was used (which means to bind references to global @@ -2668,7 +2674,8 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data) DYNBSS. */ bfd_boolean -_bfd_elf_adjust_dynamic_copy (struct elf_link_hash_entry *h, +_bfd_elf_adjust_dynamic_copy (struct bfd_link_info *info, + struct elf_link_hash_entry *h, asection *dynbss) { unsigned int power_of_two; @@ -2707,6 +2714,15 @@ _bfd_elf_adjust_dynamic_copy (struct elf_link_hash_entry *h, /* Increment the size of DYNBSS to make room for the symbol. */ dynbss->size += h->size; + /* No error if extern_protected_data is true. */ + if (h->protected_def + && (!info->extern_protected_data + || (info->extern_protected_data < 0 + && !get_elf_backend_data (dynbss->owner)->extern_protected_data))) + info->callbacks->einfo + (_("%P: copy reloc against protected `%T' is dangerous\n"), + h->root.root.string); + return TRUE; } @@ -2862,8 +2878,12 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h, bed = get_elf_backend_data (hash_table->dynobj); - /* STV_PROTECTED non-function symbols are local. */ - if (!bed->is_function_type (h->type)) + /* If extern_protected_data is false, STV_PROTECTED non-function + symbols are local. */ + if ((!info->extern_protected_data + || (info->extern_protected_data < 0 + && !bed->extern_protected_data)) + && !bed->is_function_type (h->type)) return TRUE; /* Function pointer equality tests may require that STV_PROTECTED @@ -2962,14 +2982,11 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef) if (abfd == NULL) return FALSE; - if (! bfd_check_format (abfd, bfd_object)) + /* Return FALSE if the object has been claimed by plugin. */ + if (abfd->plugin_format == bfd_plugin_yes) return FALSE; - /* If we have already included the element containing this symbol in the - link then we do not need to include it again. Just claim that any symbol - it contains is not a definition, so that our caller will not decide to - (re)include this element. */ - if (abfd->archive_pass) + if (! bfd_check_format (abfd, bfd_object)) return FALSE; /* Select the appropriate symbol table. */ @@ -3127,7 +3144,8 @@ static bfd_boolean on_needed_list (const char *soname, struct bfd_link_needed_list *needed) { for (; needed != NULL; needed = needed->next) - if (strcmp (soname, needed->name) == 0) + if ((elf_dyn_lib_class (needed->by) & DYN_AS_NEEDED) == 0 + && strcmp (soname, needed->name) == 0) return TRUE; return FALSE; @@ -3331,6 +3349,18 @@ _bfd_elf_relocs_compatible (const bfd_target *input, return ibed->relocs_compatible == obed->relocs_compatible; } +/* Make a special call to the linker "notice" function to tell it that + we are about to handle an as-needed lib, or have finished + processing the lib. */ + +bfd_boolean +_bfd_elf_notice_as_needed (bfd *ibfd, + struct bfd_link_info *info, + enum notice_asneeded_action act) +{ + return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0); +} + /* Add symbols from an ELF object file to the linker hash table. */ static bfd_boolean @@ -3360,14 +3390,14 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) unsigned int old_size = 0; unsigned int old_count = 0; void *old_tab = NULL; - void *old_hash; void *old_ent; struct bfd_link_hash_entry *old_undefs = NULL; struct bfd_link_hash_entry *old_undefs_tail = NULL; long old_dynsymcount = 0; bfd_size_type old_dynstr_size = 0; size_t tabsize = 0; - size_t hashsize = 0; + asection *s; + bfd_boolean just_syms; htab = elf_hash_table (info); bed = get_elf_backend_data (abfd); @@ -3409,88 +3439,82 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) symbol. This differs from .gnu.warning sections, which generate warnings when they are included in an output file. */ /* PR 12761: Also generate this warning when building shared libraries. */ - if (info->executable || info->shared) + for (s = abfd->sections; s != NULL; s = s->next) { - asection *s; + const char *name; - for (s = abfd->sections; s != NULL; s = s->next) + name = bfd_get_section_name (abfd, s); + if (CONST_STRNEQ (name, ".gnu.warning.")) { - const char *name; + char *msg; + bfd_size_type sz; + + name += sizeof ".gnu.warning." - 1; - name = bfd_get_section_name (abfd, s); - if (CONST_STRNEQ (name, ".gnu.warning.")) + /* If this is a shared object, then look up the symbol + in the hash table. If it is there, and it is already + been defined, then we will not be using the entry + from this shared object, so we don't need to warn. + FIXME: If we see the definition in a regular object + later on, we will warn, but we shouldn't. The only + fix is to keep track of what warnings we are supposed + to emit, and then handle them all at the end of the + link. */ + if (dynamic) { - char *msg; - bfd_size_type sz; - - name += sizeof ".gnu.warning." - 1; - - /* If this is a shared object, then look up the symbol - in the hash table. If it is there, and it is already - been defined, then we will not be using the entry - from this shared object, so we don't need to warn. - FIXME: If we see the definition in a regular object - later on, we will warn, but we shouldn't. The only - fix is to keep track of what warnings we are supposed - to emit, and then handle them all at the end of the - link. */ - if (dynamic) - { - struct elf_link_hash_entry *h; + struct elf_link_hash_entry *h; - h = elf_link_hash_lookup (htab, name, FALSE, FALSE, TRUE); + h = elf_link_hash_lookup (htab, name, FALSE, FALSE, TRUE); - /* FIXME: What about bfd_link_hash_common? */ - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)) - { - /* We don't want to issue this warning. Clobber - the section size so that the warning does not - get copied into the output file. */ - s->size = 0; - continue; - } - } + /* FIXME: What about bfd_link_hash_common? */ + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + continue; + } - sz = s->size; - msg = (char *) bfd_alloc (abfd, sz + 1); - if (msg == NULL) - goto error_return; + sz = s->size; + msg = (char *) bfd_alloc (abfd, sz + 1); + if (msg == NULL) + goto error_return; - if (! bfd_get_section_contents (abfd, s, msg, 0, sz)) - goto error_return; + if (! bfd_get_section_contents (abfd, s, msg, 0, sz)) + goto error_return; - msg[sz] = '\0'; + msg[sz] = '\0'; - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, name, BSF_WARNING, s, 0, msg, - FALSE, bed->collect, NULL))) - goto error_return; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, BSF_WARNING, s, 0, msg, + FALSE, bed->collect, NULL))) + goto error_return; - if (! info->relocatable) - { - /* Clobber the section size so that the warning does - not get copied into the output file. */ - s->size = 0; + if (!info->relocatable && info->executable) + { + /* Clobber the section size so that the warning does + not get copied into the output file. */ + s->size = 0; - /* Also set SEC_EXCLUDE, so that symbols defined in - the warning section don't get copied to the output. */ - s->flags |= SEC_EXCLUDE; - } + /* Also set SEC_EXCLUDE, so that symbols defined in + the warning section don't get copied to the output. */ + s->flags |= SEC_EXCLUDE; } } } + just_syms = ((s = abfd->sections) != NULL + && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS); + add_needed = TRUE; if (! dynamic) { /* If we are creating a shared library, create all the dynamic sections immediately. We need to attach them to something, so we attach them to this BFD, provided it is the right - format. FIXME: If there are no input BFD's of the same - format as the output, we can't make a shared library. */ - if (info->shared + format and is not from ld --just-symbols. FIXME: If there + are no input BFD's of the same format as the output, we can't + make a shared library. */ + if (!just_syms + && info->shared && is_elf_hash_table (htab) && info->output_bfd->xvec == abfd->xvec && !htab->dynamic_sections_created) @@ -3503,7 +3527,6 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) goto error_return; else { - asection *s; const char *soname = NULL; char *audit = NULL; struct bfd_link_needed_list *rpath = NULL, *runpath = NULL; @@ -3511,8 +3534,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) /* ld --just-symbols and dynamic objects don't mix very well. ld shouldn't allow it. */ - if ((s = abfd->sections) != NULL - && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) + if (just_syms) abort (); /* If this dynamic lib was specified on the command line with @@ -3722,7 +3744,7 @@ error_free_dyn: extsymoff = hdr->sh_info; } - sym_hash = NULL; + sym_hash = elf_sym_hashes (abfd); if (extsymcount != 0) { isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff, @@ -3730,13 +3752,16 @@ error_free_dyn: if (isymbuf == NULL) goto error_return; - /* We store a pointer to the hash table entry for each external - symbol. */ - amt = extsymcount * sizeof (struct elf_link_hash_entry *); - sym_hash = (struct elf_link_hash_entry **) bfd_alloc (abfd, amt); if (sym_hash == NULL) - goto error_free_sym; - elf_sym_hashes (abfd) = sym_hash; + { + /* We store a pointer to the hash table entry for each + external symbol. */ + amt = extsymcount * sizeof (struct elf_link_hash_entry *); + sym_hash = (struct elf_link_hash_entry **) bfd_zalloc (abfd, amt); + if (sym_hash == NULL) + goto error_free_sym; + elf_sym_hashes (abfd) = sym_hash; + } } if (dynamic) @@ -3786,8 +3811,7 @@ error_free_dyn: } tabsize = htab->root.table.size * sizeof (struct bfd_hash_entry *); - hashsize = extsymcount * sizeof (struct elf_link_hash_entry *); - old_tab = bfd_malloc (tabsize + entsize + hashsize); + old_tab = bfd_malloc (tabsize + entsize); if (old_tab == NULL) goto error_free_vers; @@ -3799,16 +3823,13 @@ error_free_dyn: /* Make a special call to the linker "notice" function to tell it that we are about to handle an as-needed lib. */ - if (!(*info->callbacks->notice) (info, NULL, abfd, NULL, - notice_as_needed, 0, NULL)) + if (!(*bed->notice_as_needed) (abfd, info, notice_as_needed)) goto error_free_vers; - /* Clone the symbol table and sym hashes. Remember some - pointers into the symbol table, and dynamic symbol count. */ - old_hash = (char *) old_tab + tabsize; - old_ent = (char *) old_hash + hashsize; + /* Clone the symbol table. Remember some pointers into the + symbol table, and dynamic symbol count. */ + old_ent = (char *) old_tab + tabsize; memcpy (old_tab, htab->root.table.table, tabsize); - memcpy (old_hash, sym_hash, hashsize); old_undefs = htab->root.undefs; old_undefs_tail = htab->root.undefs_tail; old_table = htab->root.table.table; @@ -3859,14 +3880,12 @@ error_free_dyn: bfd_boolean common; unsigned int old_alignment; bfd *old_bfd; - bfd * undef_bfd = NULL; override = FALSE; flags = BSF_NO_FLAGS; sec = NULL; value = isym->st_value; - *sym_hash = NULL; common = bed->common_definition (isym); bind = ELF_ST_BIND (isym->st_info); @@ -3979,6 +3998,13 @@ error_free_dyn: goto error_free_vers; } + /* Silently discard TLS symbols from --just-syms. There's + no way to combine a static TLS block with a new TLS block + for this executable. */ + if (ELF_ST_TYPE (isym->st_info) == STT_TLS + && sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) + continue; + if (bfd_is_und_section (sec) || bfd_is_com_section (sec)) definition = FALSE; @@ -3998,22 +4024,6 @@ error_free_dyn: unsigned int vernum = 0; bfd_boolean skip; - /* If this is a definition of a symbol which was previously - referenced, then make a note of the bfd that contained the - reference. This is used if we need to refer to the source - of the reference later on. */ - if (! bfd_is_und_section (sec)) - { - h = elf_link_hash_lookup (elf_hash_table (info), name, - FALSE, FALSE, FALSE); - - if (h != NULL - && (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak) - && h->root.u.undef.abfd) - undef_bfd = h->root.u.undef.abfd; - } - if (ever == NULL) { if (info->default_imported_symver) @@ -4121,23 +4131,18 @@ error_free_dyn: name = newname; } - /* If necessary, make a second attempt to locate the bfd - containing an unresolved reference to the current symbol. */ - if (! bfd_is_und_section (sec) && undef_bfd == NULL) - { - h = elf_link_hash_lookup (elf_hash_table (info), name, - FALSE, FALSE, FALSE); - - if (h != NULL - && (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak) - && h->root.u.undef.abfd) - undef_bfd = h->root.u.undef.abfd; - } - - if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, - &value, &old_weak, &old_alignment, - sym_hash, &skip, &override, + /* If this symbol has default visibility and the user has + requested we not re-export it, then mark it as hidden. */ + if (definition + && !dynamic + && abfd->no_export + && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL) + isym->st_other = (STV_HIDDEN + | (isym->st_other & ~ELF_ST_VISIBILITY (-1))); + + if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value, + sym_hash, &old_bfd, &old_weak, + &old_alignment, &skip, &override, &type_change_ok, &size_change_ok)) goto error_free_vers; @@ -4152,28 +4157,6 @@ error_free_dyn: || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; - /* Remember the old alignment if this is a common symbol, so - that we don't reduce the alignment later on. We can't - check later, because _bfd_generic_link_add_one_symbol - will set a default for the alignment which we want to - override. We also remember the old bfd where the existing - definition comes from. */ - switch (h->root.type) - { - default: - break; - - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - old_bfd = h->root.u.def.section->owner; - break; - - case bfd_link_hash_common: - old_bfd = h->root.u.c.p->section->owner; - old_alignment = h->root.u.c.p->alignment_power; - break; - } - if (elf_tdata (abfd)->verdef != NULL && vernum > 1 && definition) @@ -4243,7 +4226,73 @@ error_free_dyn: if (is_elf_hash_table (htab)) { - bfd_boolean dynsym; + /* Set a flag in the hash table entry indicating the type of + reference or definition we just found. A dynamic symbol + is one which is referenced or defined by both a regular + object and a shared object. */ + bfd_boolean dynsym = FALSE; + + /* Plugin symbols aren't normal. Don't set def_regular or + ref_regular for them, or make them dynamic. */ + if ((abfd->flags & BFD_PLUGIN) != 0) + ; + else if (! dynamic) + { + if (! definition) + { + h->ref_regular = 1; + if (bind != STB_WEAK) + h->ref_regular_nonweak = 1; + } + else + { + h->def_regular = 1; + if (h->def_dynamic) + { + h->def_dynamic = 0; + h->ref_dynamic = 1; + } + } + + /* If the indirect symbol has been forced local, don't + make the real symbol dynamic. */ + if ((h == hi || !hi->forced_local) + && (! info->executable + || h->def_dynamic + || h->ref_dynamic)) + dynsym = TRUE; + } + else + { + if (! definition) + { + h->ref_dynamic = 1; + hi->ref_dynamic = 1; + } + else + { + h->def_dynamic = 1; + hi->def_dynamic = 1; + } + + /* If the indirect symbol has been forced local, don't + make the real symbol dynamic. */ + if ((h == hi || !hi->forced_local) + && (h->def_regular + || h->ref_regular + || (h->u.weakdef != NULL + && ! new_weakdef + && h->u.weakdef->dynindx != -1))) + dynsym = TRUE; + } + + /* Check to see if we need to add an indirect symbol for + the default name. */ + if (definition + || (!override && h->root.type == bfd_link_hash_common)) + if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym, + sec, value, &old_bfd, &dynsym)) + goto error_free_vers; /* Check the alignment when a common symbol is involved. This can change when a common symbol is overridden by a normal @@ -4259,6 +4308,9 @@ error_free_dyn: bfd *normal_bfd; bfd *common_bfd; + BFD_ASSERT (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak); + symbol_align = ffs (h->root.u.def.value) - 1; if (h->root.u.def.section->owner != NULL && (h->root.u.def.section->owner->flags & DYNAMIC) == 0) @@ -4288,8 +4340,8 @@ error_free_dyn: /* PR binutils/2735 */ if (normal_bfd == NULL) (*_bfd_error_handler) - (_("Warning: alignment %u of common symbol `%s' in %B" - " is greater than the alignment (%u) of its section %A"), + (_("Warning: alignment %u of common symbol `%s' in %B is" + " greater than the alignment (%u) of its section %A"), common_bfd, h->root.u.def.section, 1 << common_align, name, 1 << normal_align); else @@ -4302,7 +4354,8 @@ error_free_dyn: } /* Remember the symbol size if it isn't undefined. */ - if ((isym->st_size != 0 && isym->st_shndx != SHN_UNDEF) + if (isym->st_size != 0 + && isym->st_shndx != SHN_UNDEF && (definition || h->size == 0)) { if (h->size != 0 @@ -4322,7 +4375,7 @@ error_free_dyn: to be the size of the common symbol. The code just above won't fix the size if a common symbol becomes larger. We don't warn about a size change here, because that is - covered by --warn-common. Allow changed between different + covered by --warn-common. Allow changes between different function types. */ if (h->root.type == bfd_link_hash_common) h->size = h->root.u.c.size; @@ -4353,63 +4406,7 @@ error_free_dyn: } /* Merge st_other field. */ - elf_merge_st_other (abfd, h, isym, definition, dynamic); - - /* Set a flag in the hash table entry indicating the type of - reference or definition we just found. Keep a count of - the number of dynamic symbols we find. A dynamic symbol - is one which is referenced or defined by both a regular - object and a shared object. */ - dynsym = FALSE; - if (! dynamic) - { - if (! definition) - { - h->ref_regular = 1; - if (bind != STB_WEAK) - h->ref_regular_nonweak = 1; - } - else - { - h->def_regular = 1; - if (h->def_dynamic) - { - h->def_dynamic = 0; - h->ref_dynamic = 1; - } - } - - /* If the indirect symbol has been forced local, don't - make the real symbol dynamic. */ - if ((h == hi || !hi->forced_local) - && (! info->executable - || h->def_dynamic - || h->ref_dynamic)) - dynsym = TRUE; - } - else - { - if (! definition) - { - h->ref_dynamic = 1; - hi->ref_dynamic = 1; - } - else - { - h->def_dynamic = 1; - hi->def_dynamic = 1; - } - - /* If the indirect symbol has been forced local, don't - make the real symbol dynamic. */ - if ((h == hi || !hi->forced_local) - && (h->def_regular - || h->ref_regular - || (h->u.weakdef != NULL - && ! new_weakdef - && h->u.weakdef->dynindx != -1))) - dynsym = TRUE; - } + elf_merge_st_other (abfd, h, isym, sec, definition, dynamic); /* We don't want to make debug symbol dynamic. */ if (definition && (sec->flags & SEC_DEBUGGING) && !info->relocatable) @@ -4425,14 +4422,6 @@ error_free_dyn: h->unique_global = (flags & BSF_GNU_UNIQUE) != 0; } - /* Check to see if we need to add an indirect symbol for - the default name. */ - if (definition || h->root.type == bfd_link_hash_common) - if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym, - &sec, &value, &dynsym, - override)) - goto error_free_vers; - if (definition && !dynamic) { char *p = strchr (name, ELF_VER_CHR); @@ -4444,8 +4433,8 @@ error_free_dyn: { amt = ((isymend - isym + 1) * sizeof (struct elf_link_hash_entry *)); - nondeflt_vers = - (struct elf_link_hash_entry **) bfd_malloc (amt); + nondeflt_vers + = (struct elf_link_hash_entry **) bfd_malloc (amt); if (!nondeflt_vers) goto error_free_vers; } @@ -4482,36 +4471,36 @@ error_free_dyn: if (!add_needed && definition && ((dynsym - && h->ref_regular - && (undef_bfd == NULL - || (undef_bfd->flags & BFD_PLUGIN) == 0)) - || (h->ref_dynamic + && h->ref_regular_nonweak + && (old_bfd == NULL + || (old_bfd->flags & BFD_PLUGIN) == 0)) + || (h->ref_dynamic_nonweak && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0 && !on_needed_list (elf_dt_name (abfd), htab->needed)))) { int ret; const char *soname = elf_dt_name (abfd); + info->callbacks->minfo ("%!", soname, old_bfd, + h->root.root.string); + /* A symbol from a library loaded via DT_NEEDED of some other library is referenced by a regular object. Add a DT_NEEDED entry for it. Issue an error if --no-add-needed is used and the reference was not a weak one. */ - if (undef_bfd != NULL + if (old_bfd != NULL && (elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0) { (*_bfd_error_handler) (_("%B: undefined reference to symbol '%s'"), - undef_bfd, name); - (*_bfd_error_handler) - (_("note: '%s' is defined in DSO %B so try adding it to the linker command line"), - abfd, name); - bfd_set_error (bfd_error_invalid_operation); + old_bfd, name); + bfd_set_error (bfd_error_missing_dso); goto error_free_vers; } elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class) - (elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED); + (elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED); add_needed = TRUE; ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed); @@ -4540,16 +4529,13 @@ error_free_dyn: unsigned int i; /* Restore the symbol table. */ - if (bed->as_needed_cleanup) - (*bed->as_needed_cleanup) (abfd, info); - old_hash = (char *) old_tab + tabsize; - old_ent = (char *) old_hash + hashsize; - sym_hash = elf_sym_hashes (abfd); + old_ent = (char *) old_tab + tabsize; + memset (elf_sym_hashes (abfd), 0, + extsymcount * sizeof (struct elf_link_hash_entry *)); htab->root.table.table = old_table; htab->root.table.size = old_size; htab->root.table.count = old_count; memcpy (htab->root.table.table, old_tab, tabsize); - memcpy (sym_hash, old_hash, hashsize); htab->root.undefs = old_undefs; htab->root.undefs_tail = old_undefs_tail; _bfd_elf_strtab_restore_size (htab->dynstr, old_dynstr_size); @@ -4604,8 +4590,7 @@ error_free_dyn: /* Make a special call to the linker "notice" function to tell it that symbols added for crefs may need to be removed. */ - if (!(*info->callbacks->notice) (info, NULL, abfd, NULL, - notice_not_needed, 0, NULL)) + if (!(*bed->notice_as_needed) (abfd, info, notice_not_needed)) goto error_free_vers; free (old_tab); @@ -4618,8 +4603,7 @@ error_free_dyn: if (old_tab != NULL) { - if (!(*info->callbacks->notice) (info, NULL, abfd, NULL, - notice_needed, 0, NULL)) + if (!(*bed->notice_as_needed) (abfd, info, notice_needed)) goto error_free_vers; free (old_tab); old_tab = NULL; @@ -4730,7 +4714,7 @@ error_free_dyn: struct elf_link_hash_entry *hlook; asection *slook; bfd_vma vlook; - size_t i, j, idx; + size_t i, j, idx = 0; hlook = weaks; weaks = hlook->u.weakdef; @@ -4925,8 +4909,7 @@ error_free_dyn: /* Add this bfd to the loaded list. */ struct elf_link_loaded_list *n; - n = (struct elf_link_loaded_list *) - bfd_alloc (abfd, sizeof (struct elf_link_loaded_list)); + n = (struct elf_link_loaded_list *) bfd_alloc (abfd, sizeof (*n)); if (n == NULL) goto error_return; n->abfd = abfd; @@ -5000,20 +4983,8 @@ _bfd_elf_archive_symbol_lookup (bfd *abfd, } /* Add symbols from an ELF archive file to the linker hash table. We - don't use _bfd_generic_link_add_archive_symbols because of a - problem which arises on UnixWare. The UnixWare libc.so is an - archive which includes an entry libc.so.1 which defines a bunch of - symbols. The libc.so archive also includes a number of other - object files, which also define symbols, some of which are the same - as those defined in libc.so.1. Correct linking requires that we - consider each object file in turn, and include it if it defines any - symbols we need. _bfd_generic_link_add_archive_symbols does not do - this; it looks through the list of undefined symbols, and includes - any object file which defines them. When this algorithm is used on - UnixWare, it winds up pulling in libc.so.1 early and defining a - bunch of symbols. This means that some of the other objects in the - archive are not included in the link, which is incorrect since they - precede libc.so.1 in the archive. + don't use _bfd_generic_link_add_archive_symbols because we need to + handle versioned symbols. Fortunately, ELF archive handling is simpler than that done by _bfd_generic_link_add_archive_symbols, which has to allow for a.out @@ -5028,8 +4999,7 @@ static bfd_boolean elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) { symindex c; - bfd_boolean *defined = NULL; - bfd_boolean *included = NULL; + unsigned char *included = NULL; carsym *symdefs; bfd_boolean loop; bfd_size_type amt; @@ -5053,11 +5023,10 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) if (c == 0) return TRUE; amt = c; - amt *= sizeof (bfd_boolean); - defined = (bfd_boolean *) bfd_zmalloc (amt); - included = (bfd_boolean *) bfd_zmalloc (amt); - if (defined == NULL || included == NULL) - goto error_return; + amt *= sizeof (*included); + included = (unsigned char *) bfd_zmalloc (amt); + if (included == NULL) + return FALSE; symdefs = bfd_ardata (abfd)->symdefs; bed = get_elf_backend_data (abfd); @@ -5082,7 +5051,7 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) struct bfd_link_hash_entry *undefs_tail; symindex mark; - if (defined[i] || included[i]) + if (included[i]) continue; if (symdef->file_offset == last) { @@ -5117,7 +5086,8 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) else if (h->root.type != bfd_link_hash_undefined) { if (h->root.type != bfd_link_hash_undefweak) - defined[i] = TRUE; + /* Symbol must be defined. Don't check it again. */ + included[i] = TRUE; continue; } @@ -5129,16 +5099,6 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) if (! bfd_check_format (element, bfd_object)) goto error_return; - /* Doublecheck that we have not included this object - already--it should be impossible, but there may be - something wrong with the archive. */ - if (element->archive_pass != 0) - { - bfd_set_error (bfd_error_bad_value); - goto error_return; - } - element->archive_pass = 1; - undefs_tail = info->hash->undefs_tail; if (!(*info->callbacks @@ -5176,14 +5136,11 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) } while (loop); - free (defined); free (included); return TRUE; error_return: - if (defined != NULL) - free (defined); if (included != NULL) free (included); return FALSE; @@ -5513,7 +5470,7 @@ compute_bucket_count (struct bfd_link_info *info ATTRIBUTE_UNUSED, { best_chlen = max; best_size = i; - no_improvement_count = 0; + no_improvement_count = 0; } /* PR 11843: Avoid futile long searches for the best bucket size when there are a large number of symbols. */ @@ -5549,7 +5506,7 @@ _bfd_elf_size_group_sections (struct bfd_link_info *info) { bfd *ibfd; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour && !_bfd_elf_fixup_group_sections (ibfd, bfd_abs_section_ptr)) return FALSE; @@ -5676,7 +5633,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, for (inputobj = info->input_bfds; inputobj; - inputobj = inputobj->link_next) + inputobj = inputobj->link.next) { asection *s; @@ -5942,7 +5899,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, asection *o; for (sub = info->input_bfds; sub != NULL; - sub = sub->link_next) + sub = sub->link.next) if (bfd_get_flavour (sub) == bfd_target_elf_flavour) for (o = sub->sections; o != NULL; o = o->next) if (elf_section_data (o)->this_hdr.sh_type @@ -6772,7 +6729,7 @@ _bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info) if (!is_elf_hash_table (info->hash)) return FALSE; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) if ((ibfd->flags & DYNAMIC) == 0) for (sec = ibfd->sections; sec != NULL; sec = sec->next) if ((sec->flags & SEC_MERGE) != 0 @@ -6807,7 +6764,7 @@ _bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry, if (entry == NULL) { entry = (struct bfd_hash_entry *) - bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry)); + bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry)); if (entry == NULL) return entry; } @@ -6962,6 +6919,7 @@ _bfd_elf_link_hash_table_create (bfd *abfd) free (ret); return NULL; } + ret->root.hash_table_free = _bfd_elf_link_hash_table_free; return &ret->root; } @@ -6969,13 +6927,15 @@ _bfd_elf_link_hash_table_create (bfd *abfd) /* Destroy an ELF linker hash table. */ void -_bfd_elf_link_hash_table_free (struct bfd_link_hash_table *hash) +_bfd_elf_link_hash_table_free (bfd *obfd) { - struct elf_link_hash_table *htab = (struct elf_link_hash_table *) hash; + struct elf_link_hash_table *htab; + + htab = (struct elf_link_hash_table *) obfd->link.hash; if (htab->dynstr != NULL) _bfd_elf_strtab_free (htab->dynstr); _bfd_merge_sections_free (htab->merge_info); - _bfd_generic_link_hash_table_free (hash); + _bfd_generic_link_hash_table_free (obfd); } /* This is a hook for the ELF emulation code in the generic linker to @@ -7355,10 +7315,10 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2, if (count1 == 0 || count2 == 0 || count1 != count2) goto done; - symtable1 = (struct elf_symbol *) - bfd_malloc (count1 * sizeof (struct elf_symbol)); - symtable2 = (struct elf_symbol *) - bfd_malloc (count2 * sizeof (struct elf_symbol)); + symtable1 + = (struct elf_symbol *) bfd_malloc (count1 * sizeof (*symtable1)); + symtable2 + = (struct elf_symbol *) bfd_malloc (count2 * sizeof (*symtable2)); if (symtable1 == NULL || symtable2 == NULL) goto done; @@ -7484,7 +7444,7 @@ struct elf_final_link_info /* Output BFD. */ bfd *output_bfd; /* Symbol string table. */ - struct bfd_strtab_hash *symstrtab; + struct elf_strtab_hash *symstrtab; /* .dynsym section. */ asection *dynsym_sec; /* .hash section. */ @@ -7511,16 +7471,8 @@ struct elf_final_link_info /* Array large enough to hold a section pointer for each local symbol of any input BFD. */ asection **sections; - /* Buffer to hold swapped out symbols. */ - bfd_byte *symbuf; - /* And one for symbol section indices. */ + /* Buffer for SHT_SYMTAB_SHNDX section. */ Elf_External_Sym_Shndx *symshndxbuf; - /* Number of swapped out symbols in buffer. */ - size_t symbuf_count; - /* Number of symbols which fit in symbuf. */ - size_t symbuf_size; - /* And same for symshndxbuf. */ - size_t shndxbuf_size; /* Number of STT_FILE syms seen. */ size_t filesym_count; }; @@ -7531,8 +7483,7 @@ struct elf_outext_info { bfd_boolean failed; bfd_boolean localsyms; - bfd_boolean need_second_pass; - bfd_boolean second_pass; + bfd_boolean file_sym_done; struct elf_final_link_info *flinfo; }; @@ -7882,28 +7833,34 @@ put_value (bfd_vma size, { location += (size - chunksz); - for (; size; size -= chunksz, location -= chunksz, x >>= (chunksz * 8)) + for (; size; size -= chunksz, location -= chunksz) { switch (chunksz) { - default: - case 0: - abort (); case 1: bfd_put_8 (input_bfd, x, location); + x >>= 8; break; case 2: bfd_put_16 (input_bfd, x, location); + x >>= 16; break; case 4: bfd_put_32 (input_bfd, x, location); + /* Computed this way because x >>= 32 is undefined if x is a 32-bit value. */ + x >>= 16; + x >>= 16; break; - case 8: #ifdef BFD64 + case 8: bfd_put_64 (input_bfd, x, location); -#else - abort (); + /* Computed this way because x >>= 64 is undefined if x is a 64-bit value. */ + x >>= 32; + x >>= 32; + break; #endif + default: + abort (); break; } } @@ -8050,6 +8007,138 @@ bfd_elf_perform_complex_relocation (bfd *input_bfd, return r; } +/* qsort comparison functions sorting external relocs by r_offset. */ + +static int +cmp_ext32l_r_offset (const void *p, const void *q) +{ + union aligned32 + { + uint32_t v; + unsigned char c[4]; + }; + const union aligned32 *a + = (const union aligned32 *) ((const Elf32_External_Rel *) p)->r_offset; + const union aligned32 *b + = (const union aligned32 *) ((const Elf32_External_Rel *) q)->r_offset; + + uint32_t aval = ( (uint32_t) a->c[0] + | (uint32_t) a->c[1] << 8 + | (uint32_t) a->c[2] << 16 + | (uint32_t) a->c[3] << 24); + uint32_t bval = ( (uint32_t) b->c[0] + | (uint32_t) b->c[1] << 8 + | (uint32_t) b->c[2] << 16 + | (uint32_t) b->c[3] << 24); + if (aval < bval) + return -1; + else if (aval > bval) + return 1; + return 0; +} + +static int +cmp_ext32b_r_offset (const void *p, const void *q) +{ + union aligned32 + { + uint32_t v; + unsigned char c[4]; + }; + const union aligned32 *a + = (const union aligned32 *) ((const Elf32_External_Rel *) p)->r_offset; + const union aligned32 *b + = (const union aligned32 *) ((const Elf32_External_Rel *) q)->r_offset; + + uint32_t aval = ( (uint32_t) a->c[0] << 24 + | (uint32_t) a->c[1] << 16 + | (uint32_t) a->c[2] << 8 + | (uint32_t) a->c[3]); + uint32_t bval = ( (uint32_t) b->c[0] << 24 + | (uint32_t) b->c[1] << 16 + | (uint32_t) b->c[2] << 8 + | (uint32_t) b->c[3]); + if (aval < bval) + return -1; + else if (aval > bval) + return 1; + return 0; +} + +#ifdef BFD_HOST_64_BIT +static int +cmp_ext64l_r_offset (const void *p, const void *q) +{ + union aligned64 + { + uint64_t v; + unsigned char c[8]; + }; + const union aligned64 *a + = (const union aligned64 *) ((const Elf64_External_Rel *) p)->r_offset; + const union aligned64 *b + = (const union aligned64 *) ((const Elf64_External_Rel *) q)->r_offset; + + uint64_t aval = ( (uint64_t) a->c[0] + | (uint64_t) a->c[1] << 8 + | (uint64_t) a->c[2] << 16 + | (uint64_t) a->c[3] << 24 + | (uint64_t) a->c[4] << 32 + | (uint64_t) a->c[5] << 40 + | (uint64_t) a->c[6] << 48 + | (uint64_t) a->c[7] << 56); + uint64_t bval = ( (uint64_t) b->c[0] + | (uint64_t) b->c[1] << 8 + | (uint64_t) b->c[2] << 16 + | (uint64_t) b->c[3] << 24 + | (uint64_t) b->c[4] << 32 + | (uint64_t) b->c[5] << 40 + | (uint64_t) b->c[6] << 48 + | (uint64_t) b->c[7] << 56); + if (aval < bval) + return -1; + else if (aval > bval) + return 1; + return 0; +} + +static int +cmp_ext64b_r_offset (const void *p, const void *q) +{ + union aligned64 + { + uint64_t v; + unsigned char c[8]; + }; + const union aligned64 *a + = (const union aligned64 *) ((const Elf64_External_Rel *) p)->r_offset; + const union aligned64 *b + = (const union aligned64 *) ((const Elf64_External_Rel *) q)->r_offset; + + uint64_t aval = ( (uint64_t) a->c[0] << 56 + | (uint64_t) a->c[1] << 48 + | (uint64_t) a->c[2] << 40 + | (uint64_t) a->c[3] << 32 + | (uint64_t) a->c[4] << 24 + | (uint64_t) a->c[5] << 16 + | (uint64_t) a->c[6] << 8 + | (uint64_t) a->c[7]); + uint64_t bval = ( (uint64_t) b->c[0] << 56 + | (uint64_t) b->c[1] << 48 + | (uint64_t) b->c[2] << 40 + | (uint64_t) b->c[3] << 32 + | (uint64_t) b->c[4] << 24 + | (uint64_t) b->c[5] << 16 + | (uint64_t) b->c[6] << 8 + | (uint64_t) b->c[7]); + if (aval < bval) + return -1; + else if (aval > bval) + return 1; + return 0; +} +#endif + /* When performing a relocatable link, the input relocations are preserved. But, if they reference global symbols, the indices referenced must be updated. Update all the relocations found in @@ -8057,7 +8146,8 @@ bfd_elf_perform_complex_relocation (bfd *input_bfd, static void elf_link_adjust_relocs (bfd *abfd, - struct bfd_elf_section_reloc_data *reldata) + struct bfd_elf_section_reloc_data *reldata, + bfd_boolean sort) { unsigned int i; const struct elf_backend_data *bed = get_elf_backend_data (abfd); @@ -8113,6 +8203,35 @@ elf_link_adjust_relocs (bfd *abfd, | (irela[j].r_info & r_type_mask)); (*swap_out) (abfd, irela, erela); } + + if (sort) + { + int (*compare) (const void *, const void *); + + if (bed->s->arch_size == 32) + { + if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE) + compare = cmp_ext32l_r_offset; + else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG) + compare = cmp_ext32b_r_offset; + else + abort (); + } + else + { +#ifdef BFD_HOST_64_BIT + if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE) + compare = cmp_ext64l_r_offset; + else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG) + compare = cmp_ext64b_r_offset; + else +#endif + abort (); + } + qsort (reldata->hdr->contents, count, reldata->hdr->sh_entsize, compare); + free (reldata->hashes); + reldata->hashes = NULL; + } } struct elf_link_sort_rela @@ -8156,17 +8275,14 @@ elf_link_sort_cmp2 (const void *A, const void *B) { const struct elf_link_sort_rela *a = (const struct elf_link_sort_rela *) A; const struct elf_link_sort_rela *b = (const struct elf_link_sort_rela *) B; - int copya, copyb; - if (a->u.offset < b->u.offset) + if (a->type < b->type) return -1; - if (a->u.offset > b->u.offset) + if (a->type > b->type) return 1; - copya = (a->type == reloc_class_copy) * 2 + (a->type == reloc_class_plt); - copyb = (b->type == reloc_class_copy) * 2 + (b->type == reloc_class_plt); - if (copya < copyb) + if (a->u.offset < b->u.offset) return -1; - if (copya > copyb) + if (a->u.offset > b->u.offset) return 1; if (a->rela->r_offset < b->rela->r_offset) return -1; @@ -8393,7 +8509,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec) struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p; (*swap_in) (abfd, erel, s->rela); - s->type = (*bed->elf_backend_reloc_type_class) (s->rela); + s->type = (*bed->elf_backend_reloc_type_class) (info, o, s->rela); s->u.sym_mask = r_sym_mask; p += sort_elt; erel += ext_size; @@ -8446,47 +8562,23 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec) return ret; } -/* Flush the output symbols to the file. */ - -static bfd_boolean -elf_link_flush_output_syms (struct elf_final_link_info *flinfo, - const struct elf_backend_data *bed) -{ - if (flinfo->symbuf_count > 0) - { - Elf_Internal_Shdr *hdr; - file_ptr pos; - bfd_size_type amt; - - hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr; - pos = hdr->sh_offset + hdr->sh_size; - amt = flinfo->symbuf_count * bed->s->sizeof_sym; - if (bfd_seek (flinfo->output_bfd, pos, SEEK_SET) != 0 - || bfd_bwrite (flinfo->symbuf, amt, flinfo->output_bfd) != amt) - return FALSE; - - hdr->sh_size += amt; - flinfo->symbuf_count = 0; - } - - return TRUE; -} - -/* Add a symbol to the output symbol table. */ +/* Add a symbol to the output symbol string table. */ static int -elf_link_output_sym (struct elf_final_link_info *flinfo, - const char *name, - Elf_Internal_Sym *elfsym, - asection *input_sec, - struct elf_link_hash_entry *h) -{ - bfd_byte *dest; - Elf_External_Sym_Shndx *destshndx; +elf_link_output_symstrtab (struct elf_final_link_info *flinfo, + const char *name, + Elf_Internal_Sym *elfsym, + asection *input_sec, + struct elf_link_hash_entry *h) +{ int (*output_symbol_hook) (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *, struct elf_link_hash_entry *); + struct elf_link_hash_table *hash_table; const struct elf_backend_data *bed; + bfd_size_type strtabsize; + + BFD_ASSERT (elf_onesymtab (flinfo->output_bfd)); bed = get_elf_backend_data (flinfo->output_bfd); output_symbol_hook = bed->elf_backend_link_output_symbol_hook; @@ -8497,49 +8589,119 @@ elf_link_output_sym (struct elf_final_link_info *flinfo, return ret; } - if (name == NULL || *name == '\0') - elfsym->st_name = 0; - else if (input_sec->flags & SEC_EXCLUDE) - elfsym->st_name = 0; + if (name == NULL + || *name == '\0' + || (input_sec->flags & SEC_EXCLUDE)) + elfsym->st_name = (unsigned long) -1; else { - elfsym->st_name = (unsigned long) _bfd_stringtab_add (flinfo->symstrtab, - name, TRUE, FALSE); + /* Call _bfd_elf_strtab_offset after _bfd_elf_strtab_finalize + to get the final offset for st_name. */ + elfsym->st_name + = (unsigned long) _bfd_elf_strtab_add (flinfo->symstrtab, + name, FALSE); if (elfsym->st_name == (unsigned long) -1) return 0; } - if (flinfo->symbuf_count >= flinfo->symbuf_size) + hash_table = elf_hash_table (flinfo->info); + strtabsize = hash_table->strtabsize; + if (strtabsize <= hash_table->strtabcount) { - if (! elf_link_flush_output_syms (flinfo, bed)) + strtabsize += strtabsize; + hash_table->strtabsize = strtabsize; + strtabsize *= sizeof (*hash_table->strtab); + hash_table->strtab + = (struct elf_sym_strtab *) bfd_realloc (hash_table->strtab, + strtabsize); + if (hash_table->strtab == NULL) return 0; } + hash_table->strtab[hash_table->strtabcount].sym = *elfsym; + hash_table->strtab[hash_table->strtabcount].dest_index + = hash_table->strtabcount; + hash_table->strtab[hash_table->strtabcount].destshndx_index + = flinfo->symshndxbuf ? bfd_get_symcount (flinfo->output_bfd) : 0; + + bfd_get_symcount (flinfo->output_bfd) += 1; + hash_table->strtabcount += 1; + + return 1; +} + +/* Swap symbols out to the symbol table and flush the output symbols to + the file. */ + +static bfd_boolean +elf_link_swap_symbols_out (struct elf_final_link_info *flinfo) +{ + struct elf_link_hash_table *hash_table = elf_hash_table (flinfo->info); + bfd_size_type amt, i; + const struct elf_backend_data *bed; + bfd_byte *symbuf; + Elf_Internal_Shdr *hdr; + file_ptr pos; + bfd_boolean ret; + + if (!hash_table->strtabcount) + return TRUE; + + BFD_ASSERT (elf_onesymtab (flinfo->output_bfd)); - dest = flinfo->symbuf + flinfo->symbuf_count * bed->s->sizeof_sym; - destshndx = flinfo->symshndxbuf; - if (destshndx != NULL) + bed = get_elf_backend_data (flinfo->output_bfd); + + amt = bed->s->sizeof_sym * hash_table->strtabcount; + symbuf = (bfd_byte *) bfd_malloc (amt); + if (symbuf == NULL) + return FALSE; + + if (flinfo->symshndxbuf) { - if (bfd_get_symcount (flinfo->output_bfd) >= flinfo->shndxbuf_size) + amt = (sizeof (Elf_External_Sym_Shndx) + * (bfd_get_symcount (flinfo->output_bfd))); + flinfo->symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt); + if (flinfo->symshndxbuf == NULL) { - bfd_size_type amt; - - amt = flinfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx); - destshndx = (Elf_External_Sym_Shndx *) bfd_realloc (destshndx, - amt * 2); - if (destshndx == NULL) - return 0; - flinfo->symshndxbuf = destshndx; - memset ((char *) destshndx + amt, 0, amt); - flinfo->shndxbuf_size *= 2; + free (symbuf); + return FALSE; } - destshndx += bfd_get_symcount (flinfo->output_bfd); } - bed->s->swap_symbol_out (flinfo->output_bfd, elfsym, dest, destshndx); - flinfo->symbuf_count += 1; - bfd_get_symcount (flinfo->output_bfd) += 1; + for (i = 0; i < hash_table->strtabcount; i++) + { + struct elf_sym_strtab *elfsym = &hash_table->strtab[i]; + if (elfsym->sym.st_name == (unsigned long) -1) + elfsym->sym.st_name = 0; + else + elfsym->sym.st_name + = (unsigned long) _bfd_elf_strtab_offset (flinfo->symstrtab, + elfsym->sym.st_name); + bed->s->swap_symbol_out (flinfo->output_bfd, &elfsym->sym, + ((bfd_byte *) symbuf + + (elfsym->dest_index + * bed->s->sizeof_sym)), + (flinfo->symshndxbuf + + elfsym->destshndx_index)); + } + + hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr; + pos = hdr->sh_offset + hdr->sh_size; + amt = hash_table->strtabcount * bed->s->sizeof_sym; + if (bfd_seek (flinfo->output_bfd, pos, SEEK_SET) == 0 + && bfd_bwrite (symbuf, amt, flinfo->output_bfd) == amt) + { + hdr->sh_size += amt; + ret = TRUE; + } + else + ret = FALSE; - return 1; + free (symbuf); + + free (hash_table->strtab); + hash_table->strtab = NULL; + + return ret; } /* Return TRUE if the dynamic symbol SYM in ABFD is supported. */ @@ -8749,11 +8911,6 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) { if (!h->forced_local) return TRUE; - if (eoinfo->second_pass - && !((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section->output_section != NULL)) - return TRUE; } else { @@ -8837,8 +8994,9 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) a regular file, or that we have been told to strip. However, if h->indx is set to -2, the symbol is used by a reloc and we must output it. */ + strip = FALSE; if (h->indx == -2) - strip = FALSE; + ; else if ((h->def_dynamic || h->ref_dynamic || h->root.type == bfd_link_hash_new) @@ -8855,7 +9013,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) || h->root.type == bfd_link_hash_defweak) && ((flinfo->info->strip_discarded && discarded_section (h->root.u.def.section)) - || (h->root.u.def.section->owner != NULL + || ((h->root.u.def.section->flags & SEC_LINKER_CREATED) == 0 + && h->root.u.def.section->owner != NULL && (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0))) strip = TRUE; else if ((h->root.type == bfd_link_hash_undefined @@ -8863,12 +9022,11 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) && h->root.u.undef.abfd != NULL && (h->root.u.undef.abfd->flags & BFD_PLUGIN) != 0) strip = TRUE; - else - strip = FALSE; /* If we're stripping it, and it's not a dynamic symbol, there's - nothing else to do unless it is a forced local symbol or a - STT_GNU_IFUNC symbol. */ + nothing else to do. However, if it is a forced local symbol or + an ifunc symbol we need to give the backend finish_dynamic_symbol + function a chance to make it dynamic. */ if (strip && h->dynindx == -1 && h->type != STT_GNU_IFUNC @@ -8914,19 +9072,6 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) input_sec = h->root.u.def.section; if (input_sec->output_section != NULL) { - if (eoinfo->localsyms && flinfo->filesym_count == 1) - { - bfd_boolean second_pass_sym - = (input_sec->owner == flinfo->output_bfd - || input_sec->owner == NULL - || (input_sec->flags & SEC_LINKER_CREATED) != 0 - || (input_sec->owner->flags & BFD_LINKER_CREATED) != 0); - - eoinfo->need_second_pass |= second_pass_sym; - if (eoinfo->second_pass != second_pass_sym) - return TRUE; - } - sym.st_shndx = _bfd_elf_section_from_bfd_section (flinfo->output_bfd, input_sec->output_section); @@ -8952,12 +9097,6 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) asection *tls_sec = elf_hash_table (flinfo->info)->tls_sec; if (tls_sec != NULL) sym.st_value -= tls_sec->vma; - else - { - /* The TLS section may have been garbage collected. */ - BFD_ASSERT (flinfo->info->gc_sections - && !input_sec->gc_mark); - } } } } @@ -9132,7 +9271,9 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) if (!h->def_regular) { - if (h->verinfo.verdef == NULL) + if (h->verinfo.verdef == NULL + || (elf_dyn_lib_class (h->verinfo.verdef->vd_bfd) + & (DYN_AS_NEEDED | DYN_DT_NEEDED | DYN_NO_NEEDED))) iversym.vs_vers = 0; else iversym.vs_vers = h->verinfo.verdef->vd_exp_refno + 1; @@ -9156,13 +9297,46 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) } } - /* If we're stripping it, then it was just a dynamic symbol, and - there's nothing else to do. */ - if (strip || (input_sec->flags & SEC_EXCLUDE) != 0) + /* If the symbol is undefined, and we didn't output it to .dynsym, + strip it from .symtab too. Obviously we can't do this for + relocatable output or when needed for --emit-relocs. */ + else if (input_sec == bfd_und_section_ptr + && h->indx != -2 + && !flinfo->info->relocatable) + return TRUE; + /* Also strip others that we couldn't earlier due to dynamic symbol + processing. */ + if (strip) return TRUE; + if ((input_sec->flags & SEC_EXCLUDE) != 0) + return TRUE; + + /* Output a FILE symbol so that following locals are not associated + with the wrong input file. We need one for forced local symbols + if we've seen more than one FILE symbol or when we have exactly + one FILE symbol but global symbols are present in a file other + than the one with the FILE symbol. We also need one if linker + defined symbols are present. In practice these conditions are + always met, so just emit the FILE symbol unconditionally. */ + if (eoinfo->localsyms + && !eoinfo->file_sym_done + && eoinfo->flinfo->filesym_count != 0) + { + Elf_Internal_Sym fsym; + + memset (&fsym, 0, sizeof (fsym)); + fsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); + fsym.st_shndx = SHN_ABS; + if (!elf_link_output_symstrtab (eoinfo->flinfo, NULL, &fsym, + bfd_und_section_ptr, NULL)) + return FALSE; + + eoinfo->file_sym_done = TRUE; + } indx = bfd_get_symcount (flinfo->output_bfd); - ret = elf_link_output_sym (flinfo, h->root.root.string, &sym, input_sec, h); + ret = elf_link_output_symstrtab (flinfo, h->root.root.string, &sym, + input_sec, h); if (ret == 0) { eoinfo->failed = TRUE; @@ -9188,6 +9362,7 @@ elf_section_ignore_discarded_relocs (asection *sec) { case SEC_INFO_TYPE_STABS: case SEC_INFO_TYPE_EH_FRAME: + case SEC_INFO_TYPE_EH_FRAME_ENTRY: return TRUE; default: break; @@ -9383,8 +9558,9 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) *ppsection = isec; - /* Don't output the first, undefined, symbol. */ - if (ppsection == flinfo->sections) + /* Don't output the first, undefined, symbol. In fact, don't + output any undefined local symbol. */ + if (isec == bfd_und_section_ptr) continue; if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) @@ -9434,6 +9610,10 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) if (ELF_ST_TYPE (isym->st_info) == STT_FILE) { + if (input_bfd->lto_output) + /* -flto puts a temp file name here. This means builds + are not reproducible. Discard the symbol. */ + continue; have_file_sym = TRUE; flinfo->filesym_count += 1; } @@ -9450,8 +9630,11 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) memset (&osym, 0, sizeof (osym)); osym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); osym.st_shndx = SHN_ABS; - if (!elf_link_output_sym (flinfo, input_bfd->filename, &osym, - bfd_abs_section_ptr, NULL)) + if (!elf_link_output_symstrtab (flinfo, + (input_bfd->lto_output ? NULL + : input_bfd->filename), + &osym, bfd_abs_section_ptr, + NULL)) return FALSE; } @@ -9483,7 +9666,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) } indx = bfd_get_symcount (output_bfd); - ret = elf_link_output_sym (flinfo, name, &osym, isec, NULL); + ret = elf_link_output_symstrtab (flinfo, name, &osym, isec, NULL); if (ret == 0) return FALSE; else if (ret == 1) @@ -9566,7 +9749,8 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) sym.st_value += o->output_offset; indx = bfd_get_symcount (output_bfd); - ret = elf_link_output_sym (flinfo, name, &sym, o, NULL); + ret = elf_link_output_symstrtab (flinfo, name, &sym, o, + NULL); if (ret == 0) return FALSE; else if (ret == 1) @@ -9595,7 +9779,16 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) file, so the contents field will not have been set by any of the routines which work on output files. */ if (elf_section_data (o)->this_hdr.contents != NULL) - contents = elf_section_data (o)->this_hdr.contents; + { + contents = elf_section_data (o)->this_hdr.contents; + if (bed->caches_rawsize + && o->rawsize != 0 + && o->rawsize < o->size) + { + memcpy (flinfo->contents, contents, o->rawsize); + contents = flinfo->contents; + } + } else { contents = flinfo->contents; @@ -9692,6 +9885,24 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) s_type = h->type; + /* If a plugin symbol is referenced from a non-IR file, + mark the symbol as undefined. Note that the + linker may attach linker created dynamic sections + to the plugin bfd. Symbols defined in linker + created sections are not plugin symbols. */ + if (h->root.non_ir_ref + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && (h->root.u.def.section->flags + & SEC_LINKER_CREATED) == 0 + && h->root.u.def.section->owner != NULL + && (h->root.u.def.section->owner->flags + & BFD_PLUGIN) != 0) + { + h->root.type = bfd_link_hash_undefined; + h->root.u.undef.abfd = h->root.u.def.section->owner; + } + ps = NULL; if (h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) @@ -10014,8 +10225,9 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) } indx = bfd_get_symcount (output_bfd); - ret = elf_link_output_sym (flinfo, name, &sym, sec, - NULL); + ret = elf_link_output_symstrtab (flinfo, name, + &sym, sec, + NULL); if (ret == 0) return FALSE; else if (ret == 1) @@ -10085,6 +10297,14 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) return FALSE; } break; + case SEC_INFO_TYPE_EH_FRAME_ENTRY: + { + if (! _bfd_elf_write_section_eh_frame_entry (output_bfd, + flinfo->info, + o, contents)) + return FALSE; + } + break; default: { /* FIXME: octets_per_byte. */ @@ -10228,7 +10448,7 @@ elf_reloc_link_order (bfd *output_bfd, size = (bfd_size_type) bfd_get_reloc_size (howto); buf = (bfd_byte *) bfd_zmalloc (size); - if (buf == NULL) + if (buf == NULL && size != 0) return FALSE; rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf); switch (rstat) @@ -10454,7 +10674,7 @@ elf_final_link_free (bfd *obfd, struct elf_final_link_info *flinfo) asection *o; if (flinfo->symstrtab != NULL) - _bfd_stringtab_free (flinfo->symstrtab); + _bfd_elf_strtab_free (flinfo->symstrtab); if (flinfo->contents != NULL) free (flinfo->contents); if (flinfo->external_relocs != NULL) @@ -10471,8 +10691,6 @@ elf_final_link_free (bfd *obfd, struct elf_final_link_info *flinfo) free (flinfo->indices); if (flinfo->sections != NULL) free (flinfo->sections); - if (flinfo->symbuf != NULL) - free (flinfo->symbuf); if (flinfo->symshndxbuf != NULL) free (flinfo->symshndxbuf); for (o = obfd->sections; o != NULL; o = o->next) @@ -10502,12 +10720,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) bfd_size_type max_internal_reloc_count; bfd_size_type max_sym_count; bfd_size_type max_sym_shndx_count; - file_ptr off; Elf_Internal_Sym elfsym; unsigned int i; Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Shdr *symtab_shndx_hdr; - Elf_Internal_Shdr *symstrtab_hdr; const struct elf_backend_data *bed = get_elf_backend_data (abfd); struct elf_outext_info eoinfo; bfd_boolean merged; @@ -10532,7 +10748,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) flinfo.info = info; flinfo.output_bfd = abfd; - flinfo.symstrtab = _bfd_elf_stringtab_init (); + flinfo.symstrtab = _bfd_elf_strtab_init (); if (flinfo.symstrtab == NULL) return FALSE; @@ -10559,10 +10775,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) flinfo.internal_syms = NULL; flinfo.indices = NULL; flinfo.sections = NULL; - flinfo.symbuf = NULL; flinfo.symshndxbuf = NULL; - flinfo.symbuf_count = 0; - flinfo.shndxbuf_size = 0; flinfo.filesym_count = 0; /* The object attributes have been merged. Remove the input @@ -10738,7 +10951,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* Figure out the file positions for everything but the symbol table and the relocs. We set symcount to force assign_section_numbers to create a symbol table. */ - bfd_get_symcount (abfd) = info->strip == strip_all ? 0 : 1; + bfd_get_symcount (abfd) = info->strip != strip_all || emit_relocs; BFD_ASSERT (! abfd->output_has_begun); if (! _bfd_elf_compute_section_file_positions (abfd, info)) goto error_return; @@ -10762,14 +10975,27 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) to count upwards while actually outputting the relocations. */ esdo->rel.count = 0; esdo->rela.count = 0; - } - _bfd_elf_assign_file_positions_for_relocs (abfd); + if (esdo->this_hdr.sh_offset == (file_ptr) -1) + { + /* Cache the section contents so that they can be compressed + later. Use bfd_malloc since it will be freed by + bfd_compress_section_contents. */ + unsigned char *contents = esdo->this_hdr.contents; + if ((o->flags & SEC_ELF_COMPRESS) == 0 || contents != NULL) + abort (); + contents + = (unsigned char *) bfd_malloc (esdo->this_hdr.sh_size); + if (contents == NULL) + goto error_return; + esdo->this_hdr.contents = contents; + } + } /* We have now assigned file positions for all the sections except - .symtab and .strtab. We start the .symtab section at the current - file position, and write directly to it. We build the .strtab - section in memory. */ + .symtab, .strtab, and non-loaded reloc sections. We start the + .symtab section at the current file position, and write directly + to it. We build the .strtab section in memory. */ bfd_get_symcount (abfd) = 0; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; /* sh_name is set in prep_headers. */ @@ -10781,59 +11007,47 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* sh_offset is set just below. */ symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align; - off = elf_next_file_pos (abfd); - off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE); - - /* Note that at this point elf_next_file_pos (abfd) is - incorrect. We do not yet know the size of the .symtab section. - We correct next_file_pos below, after we do know the size. */ - - /* Allocate a buffer to hold swapped out symbols. This is to avoid - continuously seeking to the right position in the file. */ - if (! info->keep_memory || max_sym_count < 20) - flinfo.symbuf_size = 20; - else - flinfo.symbuf_size = max_sym_count; - amt = flinfo.symbuf_size; - amt *= bed->s->sizeof_sym; - flinfo.symbuf = (bfd_byte *) bfd_malloc (amt); - if (flinfo.symbuf == NULL) + if (max_sym_count < 20) + max_sym_count = 20; + elf_hash_table (info)->strtabsize = max_sym_count; + amt = max_sym_count * sizeof (struct elf_sym_strtab); + elf_hash_table (info)->strtab + = (struct elf_sym_strtab *) bfd_malloc (amt); + if (elf_hash_table (info)->strtab == NULL) goto error_return; - if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF)) - { - /* Wild guess at number of output symbols. realloc'd as needed. */ - amt = 2 * max_sym_count + elf_numsections (abfd) + 1000; - flinfo.shndxbuf_size = amt; - amt *= sizeof (Elf_External_Sym_Shndx); - flinfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt); - if (flinfo.symshndxbuf == NULL) - goto error_return; - } + /* The real buffer will be allocated in elf_link_swap_symbols_out. */ + flinfo.symshndxbuf + = (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF) + ? (Elf_External_Sym_Shndx *) -1 : NULL); - /* Start writing out the symbol table. The first symbol is always a - dummy symbol. */ - if (info->strip != strip_all - || emit_relocs) + if (info->strip != strip_all || emit_relocs) { + file_ptr off = elf_next_file_pos (abfd); + + _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE); + + /* Note that at this point elf_next_file_pos (abfd) is + incorrect. We do not yet know the size of the .symtab section. + We correct next_file_pos below, after we do know the size. */ + + /* Start writing out the symbol table. The first symbol is always a + dummy symbol. */ elfsym.st_value = 0; elfsym.st_size = 0; elfsym.st_info = 0; elfsym.st_other = 0; elfsym.st_shndx = SHN_UNDEF; elfsym.st_target_internal = 0; - if (elf_link_output_sym (&flinfo, NULL, &elfsym, bfd_und_section_ptr, - NULL) != 1) + if (elf_link_output_symstrtab (&flinfo, NULL, &elfsym, + bfd_und_section_ptr, NULL) != 1) goto error_return; - } - /* Output a symbol for each section. We output these even if we are - discarding local symbols, since they are used for relocs. These - symbols have no names. We store the index of each one in the - index field of the section, so that we can find it again when - outputting relocs. */ - if (info->strip != strip_all - || emit_relocs) - { + /* Output a symbol for each section. We output these even if we are + discarding local symbols, since they are used for relocs. These + symbols have no names. We store the index of each one in the + index field of the section, so that we can find it again when + outputting relocs. */ + elfsym.st_size = 0; elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); elfsym.st_other = 0; @@ -10848,7 +11062,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) elfsym.st_shndx = i; if (!info->relocatable) elfsym.st_value = o->vma; - if (elf_link_output_sym (&flinfo, NULL, &elfsym, o, NULL) != 1) + if (elf_link_output_symstrtab (&flinfo, NULL, &elfsym, o, + NULL) != 1) goto error_return; } } @@ -10947,6 +11162,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) return FALSE; } + if (!_bfd_elf_fixup_eh_frame_hdr (info)) + return FALSE; + /* Since ELF permits relocations to be against local symbols, we must have the local symbols available when we do the relocations. Since we would rather only read the local symbols once, and we @@ -10967,7 +11185,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) we could write the relocs out and then read them again; I don't know how bad the memory loss will be. */ - for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) sub->output_has_begun = FALSE; for (o = abfd->sections; o != NULL; o = o->next) { @@ -11029,7 +11247,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* Free symbol buffer if needed. */ if (!info->reduce_memory_overheads) { - for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) if (bfd_get_flavour (sub) == bfd_target_elf_flavour && elf_tdata (sub)->symbuf) { @@ -11038,17 +11256,6 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) } } - /* Output a FILE symbol so that following locals are not associated - with the wrong input file. */ - memset (&elfsym, 0, sizeof (elfsym)); - elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); - elfsym.st_shndx = SHN_ABS; - - if (flinfo.filesym_count > 1 - && !elf_link_output_sym (&flinfo, NULL, &elfsym, - bfd_und_section_ptr, NULL)) - return FALSE; - /* Output any global symbols that got converted to local in a version script or due to symbol visibility. We do this in a separate step since ELF requires all local symbols to appear @@ -11058,35 +11265,23 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) eoinfo.failed = FALSE; eoinfo.flinfo = &flinfo; eoinfo.localsyms = TRUE; - eoinfo.need_second_pass = FALSE; - eoinfo.second_pass = FALSE; + eoinfo.file_sym_done = FALSE; bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo); if (eoinfo.failed) return FALSE; - if (flinfo.filesym_count == 1 - && !elf_link_output_sym (&flinfo, NULL, &elfsym, - bfd_und_section_ptr, NULL)) - return FALSE; - - if (eoinfo.need_second_pass) - { - eoinfo.second_pass = TRUE; - bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo); - if (eoinfo.failed) - return FALSE; - } - /* If backend needs to output some local symbols not present in the hash table, do it now. */ - if (bed->elf_backend_output_arch_local_syms) + if (bed->elf_backend_output_arch_local_syms + && (info->strip != strip_all || emit_relocs)) { typedef int (*out_sym_func) (void *, const char *, Elf_Internal_Sym *, asection *, struct elf_link_hash_entry *); if (! ((*bed->elf_backend_output_arch_local_syms) - (abfd, info, &flinfo, (out_sym_func) elf_link_output_sym))) + (abfd, info, &flinfo, + (out_sym_func) elf_link_output_symstrtab))) return FALSE; } @@ -11189,63 +11384,69 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* If backend needs to output some symbols not present in the hash table, do it now. */ - if (bed->elf_backend_output_arch_syms) + if (bed->elf_backend_output_arch_syms + && (info->strip != strip_all || emit_relocs)) { typedef int (*out_sym_func) (void *, const char *, Elf_Internal_Sym *, asection *, struct elf_link_hash_entry *); if (! ((*bed->elf_backend_output_arch_syms) - (abfd, info, &flinfo, (out_sym_func) elf_link_output_sym))) + (abfd, info, &flinfo, + (out_sym_func) elf_link_output_symstrtab))) return FALSE; } - /* Flush all symbols to the file. */ - if (! elf_link_flush_output_syms (&flinfo, bed)) + /* Finalize the .strtab section. */ + _bfd_elf_strtab_finalize (flinfo.symstrtab); + + /* Swap out the .strtab section. */ + if (!elf_link_swap_symbols_out (&flinfo)) return FALSE; /* Now we know the size of the symtab section. */ - off += symtab_hdr->sh_size; - - symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; - if (symtab_shndx_hdr->sh_name != 0) + if (bfd_get_symcount (abfd) > 0) { - symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX; - symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx); - symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx); - amt = bfd_get_symcount (abfd) * sizeof (Elf_External_Sym_Shndx); - symtab_shndx_hdr->sh_size = amt; + /* Finish up and write out the symbol string table (.strtab) + section. */ + Elf_Internal_Shdr *symstrtab_hdr; + file_ptr off = symtab_hdr->sh_offset + symtab_hdr->sh_size; - off = _bfd_elf_assign_file_position_for_section (symtab_shndx_hdr, - off, TRUE); + symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; + if (symtab_shndx_hdr->sh_name != 0) + { + symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX; + symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx); + symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx); + amt = bfd_get_symcount (abfd) * sizeof (Elf_External_Sym_Shndx); + symtab_shndx_hdr->sh_size = amt; - if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0 - || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt)) - return FALSE; - } + off = _bfd_elf_assign_file_position_for_section (symtab_shndx_hdr, + off, TRUE); + if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0 + || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt)) + return FALSE; + } - /* Finish up and write out the symbol string table (.strtab) - section. */ - symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; - /* sh_name was set in prep_headers. */ - symstrtab_hdr->sh_type = SHT_STRTAB; - symstrtab_hdr->sh_flags = 0; - symstrtab_hdr->sh_addr = 0; - symstrtab_hdr->sh_size = _bfd_stringtab_size (flinfo.symstrtab); - symstrtab_hdr->sh_entsize = 0; - symstrtab_hdr->sh_link = 0; - symstrtab_hdr->sh_info = 0; - /* sh_offset is set just below. */ - symstrtab_hdr->sh_addralign = 1; + symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; + /* sh_name was set in prep_headers. */ + symstrtab_hdr->sh_type = SHT_STRTAB; + symstrtab_hdr->sh_flags = 0; + symstrtab_hdr->sh_addr = 0; + symstrtab_hdr->sh_size = _bfd_elf_strtab_size (flinfo.symstrtab); + symstrtab_hdr->sh_entsize = 0; + symstrtab_hdr->sh_link = 0; + symstrtab_hdr->sh_info = 0; + /* sh_offset is set just below. */ + symstrtab_hdr->sh_addralign = 1; - off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, off, TRUE); - elf_next_file_pos (abfd) = off; + off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, + off, TRUE); + elf_next_file_pos (abfd) = off; - if (bfd_get_symcount (abfd) > 0) - { if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0 - || ! _bfd_stringtab_emit (abfd, flinfo.symstrtab)) + || ! _bfd_elf_strtab_emit (abfd, flinfo.symstrtab)) return FALSE; } @@ -11253,13 +11454,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) for (o = abfd->sections; o != NULL; o = o->next) { struct bfd_elf_section_data *esdo = elf_section_data (o); + bfd_boolean sort; if ((o->flags & SEC_RELOC) == 0) continue; + sort = bed->sort_relocs_p == NULL || (*bed->sort_relocs_p) (o); if (esdo->rel.hdr != NULL) - elf_link_adjust_relocs (abfd, &esdo->rel); + elf_link_adjust_relocs (abfd, &esdo->rel, sort); if (esdo->rela.hdr != NULL) - elf_link_adjust_relocs (abfd, &esdo->rela); + elf_link_adjust_relocs (abfd, &esdo->rela, sort); /* Set the reloc_count field to 0 to prevent write_relocs from trying to swap the relocs out itself. */ @@ -11506,6 +11709,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) { /* The contents of the .dynstr section are actually in a stringtab. */ + file_ptr off; + off = elf_section_data (o->output_section)->this_hdr.sh_offset; if (bfd_seek (abfd, off, SEEK_SET) != 0 || ! _bfd_elf_strtab_emit (abfd, @@ -11730,7 +11935,7 @@ _bfd_elf_gc_mark_hook (asection *sec, { bfd *i; - for (i = info->input_bfds; i; i = i->link_next) + for (i = info->input_bfds; i; i = i->link.next) { sec = bfd_get_section_by_name (i, sec_name); if (sec) @@ -11769,6 +11974,12 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec, || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL) { h = cookie->sym_hashes[r_symndx - cookie->extsymoff]; + if (h == NULL) + { + info->callbacks->einfo (_("%F%P: corrupt input: %B\n"), + sec->owner); + return NULL; + } while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; @@ -11868,9 +12079,55 @@ _bfd_elf_gc_mark (struct bfd_link_info *info, } } + eh_frame = elf_section_eh_frame_entry (sec); + if (ret && eh_frame && !eh_frame->gc_mark) + if (!_bfd_elf_gc_mark (info, eh_frame, gc_mark_hook)) + ret = FALSE; + return ret; } +/* Scan and mark sections in a special or debug section group. */ + +static void +_bfd_elf_gc_mark_debug_special_section_group (asection *grp) +{ + /* Point to first section of section group. */ + asection *ssec; + /* Used to iterate the section group. */ + asection *msec; + + bfd_boolean is_special_grp = TRUE; + bfd_boolean is_debug_grp = TRUE; + + /* First scan to see if group contains any section other than debug + and special section. */ + ssec = msec = elf_next_in_group (grp); + do + { + if ((msec->flags & SEC_DEBUGGING) == 0) + is_debug_grp = FALSE; + + if ((msec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) != 0) + is_special_grp = FALSE; + + msec = elf_next_in_group (msec); + } + while (msec != ssec); + + /* If this is a pure debug section group or pure special section group, + keep all sections in this group. */ + if (is_debug_grp || is_special_grp) + { + do + { + msec->gc_mark = 1; + msec = elf_next_in_group (msec); + } + while (msec != ssec); + } +} + /* Keep debug and special sections. */ bfd_boolean @@ -11879,38 +12136,87 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info, { bfd *ibfd; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { asection *isec; bfd_boolean some_kept; + bfd_boolean debug_frag_seen; if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) continue; - /* Ensure all linker created sections are kept, and see whether - any other section is already marked. */ - some_kept = FALSE; + /* Ensure all linker created sections are kept, + see if any other section is already marked, + and note if we have any fragmented debug sections. */ + debug_frag_seen = some_kept = FALSE; for (isec = ibfd->sections; isec != NULL; isec = isec->next) { if ((isec->flags & SEC_LINKER_CREATED) != 0) isec->gc_mark = 1; else if (isec->gc_mark) some_kept = TRUE; + + if (debug_frag_seen == FALSE + && (isec->flags & SEC_DEBUGGING) + && CONST_STRNEQ (isec->name, ".debug_line.")) + debug_frag_seen = TRUE; } /* If no section in this file will be kept, then we can - toss out debug sections. */ + toss out the debug and special sections. */ if (!some_kept) continue; /* Keep debug and special sections like .comment when they are - not part of a group, or when we have single-member groups. */ + not part of a group. Also keep section groups that contain + just debug sections or special sections. */ + for (isec = ibfd->sections; isec != NULL; isec = isec->next) + { + if ((isec->flags & SEC_GROUP) != 0) + _bfd_elf_gc_mark_debug_special_section_group (isec); + else if (((isec->flags & SEC_DEBUGGING) != 0 + || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) + && elf_next_in_group (isec) == NULL) + isec->gc_mark = 1; + } + + if (! debug_frag_seen) + continue; + + /* Look for CODE sections which are going to be discarded, + and find and discard any fragmented debug sections which + are associated with that code section. */ for (isec = ibfd->sections; isec != NULL; isec = isec->next) - if ((elf_next_in_group (isec) == NULL - || elf_next_in_group (isec) == isec) - && ((isec->flags & SEC_DEBUGGING) != 0 - || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)) - isec->gc_mark = 1; + if ((isec->flags & SEC_CODE) != 0 + && isec->gc_mark == 0) + { + unsigned int ilen; + asection *dsec; + + ilen = strlen (isec->name); + + /* Association is determined by the name of the debug section + containing the name of the code section as a suffix. For + example .debug_line.text.foo is a debug section associated + with .text.foo. */ + for (dsec = ibfd->sections; dsec != NULL; dsec = dsec->next) + { + unsigned int dlen; + + if (dsec->gc_mark == 0 + || (dsec->flags & SEC_DEBUGGING) == 0) + continue; + + dlen = strlen (dsec->name); + + if (dlen > ilen + && strncmp (dsec->name + (dlen - ilen), + isec->name, ilen) == 0) + { + dsec->gc_mark = 0; + } + } + } } return TRUE; } @@ -11930,7 +12236,7 @@ elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *data) if (!h->mark && (((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) - && !(h->def_regular + && !((h->def_regular || ELF_COMMON_DEF_P (h)) && h->root.u.def.section->gc_mark)) || h->root.type == bfd_link_hash_undefined || h->root.type == bfd_link_hash_undefweak)) @@ -11961,11 +12267,12 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info) unsigned long section_sym_count; struct elf_gc_sweep_symbol_info sweep_info; - for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) { asection *o; - if (bfd_get_flavour (sub) != bfd_target_elf_flavour) + if (bfd_get_flavour (sub) != bfd_target_elf_flavour + || !(*bed->relocs_compatible) (sub->xvec, abfd->xvec)) continue; for (o = sub->sections; o != NULL; o = o->next) @@ -11998,7 +12305,9 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info) info we collected before. */ if (gc_sweep_hook && (o->flags & SEC_RELOC) != 0 - && o->reloc_count > 0 + && o->reloc_count != 0 + && !((info->strip == strip_all || info->strip == strip_debugger) + && (o->flags & SEC_DEBUGGING) != 0) && !bfd_is_abs_section (o->output_section)) { Elf_Internal_Rela *internal_relocs; @@ -12146,14 +12455,19 @@ bfd_boolean bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf) { struct bfd_link_info *info = (struct bfd_link_info *) inf; + struct bfd_elf_dynamic_list *d = info->dynamic_list; if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) && (h->ref_dynamic - || ((!info->executable || info->export_dynamic) - && h->def_regular + || ((h->def_regular || ELF_COMMON_DEF_P (h)) && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN + && (!info->executable + || info->export_dynamic + || (h->dynamic + && d != NULL + && (*d->match) (&d->head, NULL, h->root.root.string))) && (strchr (h->root.root.string, ELF_VER_CHR) != NULL || !bfd_hide_sym_by_version (info->version_info, h->root.root.string))))) @@ -12185,6 +12499,36 @@ _bfd_elf_gc_keep (struct bfd_link_info *info) } } +bfd_boolean +bfd_elf_parse_eh_frame_entries (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) +{ + bfd *ibfd = info->input_bfds; + + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + asection *sec; + struct elf_reloc_cookie cookie; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) + continue; + + if (!init_reloc_cookie (&cookie, info, ibfd)) + return FALSE; + + for (sec = ibfd->sections; sec; sec = sec->next) + { + if (CONST_STRNEQ (bfd_section_name (ibfd, sec), ".eh_frame_entry") + && init_reloc_cookie_rels (&cookie, info, ibfd, sec)) + { + _bfd_elf_parse_eh_frame_entry (info, sec, &cookie); + fini_reloc_cookie_rels (&cookie, sec); + } + } + } + return TRUE; +} + /* Do mark and sweep of unused sections. */ bfd_boolean @@ -12194,6 +12538,7 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) bfd *sub; elf_gc_mark_hook_fn gc_mark_hook; const struct elf_backend_data *bed = get_elf_backend_data (abfd); + struct elf_link_hash_table *htab; if (!bed->can_gc_sections || !is_elf_hash_table (info->hash)) @@ -12203,11 +12548,13 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) } bed->gc_keep (info); + htab = elf_hash_table (info); /* Try to parse each bfd's .eh_frame section. Point elf_eh_frame_section at the .eh_frame section if we can mark the FDEs individually. */ - _bfd_elf_begin_eh_frame_parsing (info); - for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + for (sub = info->input_bfds; + info->eh_frame_hdr_type != COMPACT_EH_HDR && sub != NULL; + sub = sub->link.next) { asection *sec; struct elf_reloc_cookie cookie; @@ -12223,35 +12570,29 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) sec = bfd_get_next_section_by_name (sec); } } - _bfd_elf_end_eh_frame_parsing (info); /* Apply transitive closure to the vtable entry usage info. */ - elf_link_hash_traverse (elf_hash_table (info), - elf_gc_propagate_vtable_entries_used, - &ok); + elf_link_hash_traverse (htab, elf_gc_propagate_vtable_entries_used, &ok); if (!ok) return FALSE; /* Kill the vtable relocations that were not used. */ - elf_link_hash_traverse (elf_hash_table (info), - elf_gc_smash_unused_vtentry_relocs, - &ok); + elf_link_hash_traverse (htab, elf_gc_smash_unused_vtentry_relocs, &ok); if (!ok) return FALSE; /* Mark dynamically referenced symbols. */ - if (elf_hash_table (info)->dynamic_sections_created) - elf_link_hash_traverse (elf_hash_table (info), - bed->gc_mark_dynamic_ref, - info); + if (htab->dynamic_sections_created) + elf_link_hash_traverse (htab, bed->gc_mark_dynamic_ref, info); /* Grovel through relocs to find out who stays ... */ gc_mark_hook = bed->gc_mark_hook; - for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) { asection *o; - if (bfd_get_flavour (sub) != bfd_target_elf_flavour) + if (bfd_get_flavour (sub) != bfd_target_elf_flavour + || !(*bed->relocs_compatible) (sub->xvec, abfd->xvec)) continue; /* Start at sections marked with SEC_KEEP (ref _bfd_elf_gc_keep). @@ -12319,8 +12660,8 @@ bfd_elf_gc_record_vtinherit (bfd *abfd, win: if (!child->vtable) { - child->vtable = (struct elf_link_virtual_table_entry *) - bfd_zalloc (abfd, sizeof (*child->vtable)); + child->vtable = ((struct elf_link_virtual_table_entry *) + bfd_zalloc (abfd, sizeof (*child->vtable))); if (!child->vtable) return FALSE; } @@ -12352,8 +12693,8 @@ bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED, if (!h->vtable) { - h->vtable = (struct elf_link_virtual_table_entry *) - bfd_zalloc (abfd, sizeof (*h->vtable)); + h->vtable = ((struct elf_link_virtual_table_entry *) + bfd_zalloc (abfd, sizeof (*h->vtable))); if (!h->vtable) return FALSE; } @@ -12556,7 +12897,7 @@ bfd_elf_gc_common_finalize_got_offsets (bfd *abfd, gotoff = bed->got_header_size; /* Do the local .got entries first. */ - for (i = info->input_bfds; i; i = i->link_next) + for (i = info->input_bfds; i; i = i->link.next) { bfd_signed_vma *local_got; bfd_size_type j, locsymcount; @@ -12645,10 +12986,10 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie) if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) - && discarded_section (h->root.u.def.section)) + && (h->root.u.def.section->owner != rcookie->abfd + || h->root.u.def.section->kept_section != NULL + || discarded_section (h->root.u.def.section))) return TRUE; - else - return FALSE; } else { @@ -12661,7 +13002,9 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie) /* Need to: get the symbol; get the section. */ isym = &rcookie->locsyms[r_symndx]; isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx); - if (isec != NULL && discarded_section (isec)) + if (isec != NULL + && (isec->kept_section != NULL + || discarded_section (isec))) return TRUE; } return FALSE; @@ -12670,94 +13013,110 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie) } /* Discard unneeded references to discarded sections. - Returns TRUE if any section's size was changed. */ -/* This function assumes that the relocations are in sorted order, - which is true for all known assemblers. */ + Returns -1 on error, 1 if any section's size was changed, 0 if + nothing changed. This function assumes that the relocations are in + sorted order, which is true for all known assemblers. */ -bfd_boolean +int bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info) { struct elf_reloc_cookie cookie; - asection *stab, *eh; - const struct elf_backend_data *bed; + asection *o; bfd *abfd; - bfd_boolean ret = FALSE; + int changed = 0; if (info->traditional_format || !is_elf_hash_table (info->hash)) - return FALSE; + return 0; - _bfd_elf_begin_eh_frame_parsing (info); - for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next) + o = bfd_get_section_by_name (output_bfd, ".stab"); + if (o != NULL) { - if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) - continue; - - bed = get_elf_backend_data (abfd); + asection *i; - eh = NULL; - if (!info->relocatable) + for (i = o->map_head.s; i != NULL; i = i->map_head.s) { - eh = bfd_get_section_by_name (abfd, ".eh_frame"); - while (eh != NULL - && (eh->size == 0 - || bfd_is_abs_section (eh->output_section))) - eh = bfd_get_next_section_by_name (eh); - } - - stab = bfd_get_section_by_name (abfd, ".stab"); - if (stab != NULL - && (stab->size == 0 - || bfd_is_abs_section (stab->output_section) - || stab->sec_info_type != SEC_INFO_TYPE_STABS)) - stab = NULL; + if (i->size == 0 + || i->reloc_count == 0 + || i->sec_info_type != SEC_INFO_TYPE_STABS) + continue; - if (stab == NULL - && eh == NULL - && bed->elf_backend_discard_info == NULL) - continue; + abfd = i->owner; + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) + continue; - if (!init_reloc_cookie (&cookie, info, abfd)) - return FALSE; + if (!init_reloc_cookie_for_section (&cookie, info, i)) + return -1; - if (stab != NULL - && stab->reloc_count > 0 - && init_reloc_cookie_rels (&cookie, info, abfd, stab)) - { - if (_bfd_discard_section_stabs (abfd, stab, - elf_section_data (stab)->sec_info, + if (_bfd_discard_section_stabs (abfd, i, + elf_section_data (i)->sec_info, bfd_elf_reloc_symbol_deleted_p, &cookie)) - ret = TRUE; - fini_reloc_cookie_rels (&cookie, stab); + changed = 1; + + fini_reloc_cookie_for_section (&cookie, i); } + } + + o = NULL; + if (info->eh_frame_hdr_type != COMPACT_EH_HDR) + o = bfd_get_section_by_name (output_bfd, ".eh_frame"); + if (o != NULL) + { + asection *i; - while (eh != NULL - && init_reloc_cookie_rels (&cookie, info, abfd, eh)) + for (i = o->map_head.s; i != NULL; i = i->map_head.s) { - _bfd_elf_parse_eh_frame (abfd, info, eh, &cookie); - if (_bfd_elf_discard_section_eh_frame (abfd, info, eh, + if (i->size == 0) + continue; + + abfd = i->owner; + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) + continue; + + if (!init_reloc_cookie_for_section (&cookie, info, i)) + return -1; + + _bfd_elf_parse_eh_frame (abfd, info, i, &cookie); + if (_bfd_elf_discard_section_eh_frame (abfd, info, i, bfd_elf_reloc_symbol_deleted_p, &cookie)) - ret = TRUE; - fini_reloc_cookie_rels (&cookie, eh); - eh = bfd_get_next_section_by_name (eh); + changed = 1; + + fini_reloc_cookie_for_section (&cookie, i); } + } + + for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) + { + const struct elf_backend_data *bed; + + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) + continue; - if (bed->elf_backend_discard_info != NULL - && (*bed->elf_backend_discard_info) (abfd, &cookie, info)) - ret = TRUE; + bed = get_elf_backend_data (abfd); + + if (bed->elf_backend_discard_info != NULL) + { + if (!init_reloc_cookie (&cookie, info, abfd)) + return -1; + + if ((*bed->elf_backend_discard_info) (abfd, &cookie, info)) + changed = 1; - fini_reloc_cookie (&cookie, abfd); + fini_reloc_cookie (&cookie, abfd); + } } - _bfd_elf_end_eh_frame_parsing (info); - if (info->eh_frame_hdr + if (info->eh_frame_hdr_type == COMPACT_EH_HDR) + _bfd_elf_end_eh_frame_parsing (info); + + if (info->eh_frame_hdr_type && !info->relocatable && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info)) - ret = TRUE; + changed = 1; - return ret; + return changed; } bfd_boolean @@ -12998,11 +13357,11 @@ _bfd_elf_get_dynamic_reloc_section (bfd * abfd, string table associated with ABFD. */ asection * -_bfd_elf_make_dynamic_reloc_section (asection * sec, - bfd * dynobj, - unsigned int alignment, - bfd * abfd, - bfd_boolean is_rela) +_bfd_elf_make_dynamic_reloc_section (asection *sec, + bfd *dynobj, + unsigned int alignment, + bfd *abfd, + bfd_boolean is_rela) { asection * reloc_sec = elf_section_data (sec)->sreloc; @@ -13025,6 +13384,11 @@ _bfd_elf_make_dynamic_reloc_section (asection * sec, reloc_sec = bfd_make_section_anyway_with_flags (dynobj, name, flags); if (reloc_sec != NULL) { + /* _bfd_elf_get_sec_type_attr chooses a section type by + name. Override as it may be wrong, eg. for a user + section named "auto" we'll get ".relauto" which is + seen to be a .rela section. */ + elf_section_type (reloc_sec) = is_rela ? SHT_RELA : SHT_REL; if (! bfd_set_section_alignment (dynobj, reloc_sec, alignment)) reloc_sec = NULL; } @@ -13036,17 +13400,24 @@ _bfd_elf_make_dynamic_reloc_section (asection * sec, return reloc_sec; } -/* Copy the ELF symbol type associated with a linker hash entry. */ +/* Copy the ELF symbol type and other attributes for a linker script + assignment from HSRC to HDEST. Generally this should be treated as + if we found a strong non-dynamic definition for HDEST (except that + ld ignores multiple definition errors). */ void -_bfd_elf_copy_link_hash_symbol_type (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_hash_entry * hdest, - struct bfd_link_hash_entry * hsrc) +_bfd_elf_copy_link_hash_symbol_type (bfd *abfd, + struct bfd_link_hash_entry *hdest, + struct bfd_link_hash_entry *hsrc) { - struct elf_link_hash_entry *ehdest = (struct elf_link_hash_entry *)hdest; - struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *)hsrc; + struct elf_link_hash_entry *ehdest = (struct elf_link_hash_entry *) hdest; + struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *) hsrc; + Elf_Internal_Sym isym; ehdest->type = ehsrc->type; ehdest->target_internal = ehsrc->target_internal; + + isym.st_other = ehsrc->other; + elf_merge_st_other (abfd, ehdest, &isym, NULL, TRUE, FALSE); } /* Append a RELA relocation REL to section S in BFD. */ diff --git a/contrib/gdb-7/bfd/elfnn-aarch64.c b/contrib/gdb-7/bfd/elfnn-aarch64.c new file mode 100644 index 0000000000..b13f5db610 --- /dev/null +++ b/contrib/gdb-7/bfd/elfnn-aarch64.c @@ -0,0 +1,8632 @@ +/* AArch64-specific support for NN-bit ELF. + Copyright (C) 2009-2015 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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 . */ + +/* Notes on implementation: + + Thread Local Store (TLS) + + Overview: + + The implementation currently supports both traditional TLS and TLS + descriptors, but only general dynamic (GD). + + For traditional TLS the assembler will present us with code + fragments of the form: + + adrp x0, :tlsgd:foo + R_AARCH64_TLSGD_ADR_PAGE21(foo) + add x0, :tlsgd_lo12:foo + R_AARCH64_TLSGD_ADD_LO12_NC(foo) + bl __tls_get_addr + nop + + For TLS descriptors the assembler will present us with code + fragments of the form: + + adrp x0, :tlsdesc:foo R_AARCH64_TLSDESC_ADR_PAGE21(foo) + ldr x1, [x0, #:tlsdesc_lo12:foo] R_AARCH64_TLSDESC_LD64_LO12(foo) + add x0, x0, #:tlsdesc_lo12:foo R_AARCH64_TLSDESC_ADD_LO12(foo) + .tlsdesccall foo + blr x1 R_AARCH64_TLSDESC_CALL(foo) + + The relocations R_AARCH64_TLSGD_{ADR_PREL21,ADD_LO12_NC} against foo + indicate that foo is thread local and should be accessed via the + traditional TLS mechanims. + + The relocations R_AARCH64_TLSDESC_{ADR_PAGE21,LD64_LO12_NC,ADD_LO12_NC} + against foo indicate that 'foo' is thread local and should be accessed + via a TLS descriptor mechanism. + + The precise instruction sequence is only relevant from the + perspective of linker relaxation which is currently not implemented. + + The static linker must detect that 'foo' is a TLS object and + allocate a double GOT entry. The GOT entry must be created for both + global and local TLS symbols. Note that this is different to none + TLS local objects which do not need a GOT entry. + + In the traditional TLS mechanism, the double GOT entry is used to + provide the tls_index structure, containing module and offset + entries. The static linker places the relocation R_AARCH64_TLS_DTPMOD + on the module entry. The loader will subsequently fixup this + relocation with the module identity. + + For global traditional TLS symbols the static linker places an + R_AARCH64_TLS_DTPREL relocation on the offset entry. The loader + will subsequently fixup the offset. For local TLS symbols the static + linker fixes up offset. + + In the TLS descriptor mechanism the double GOT entry is used to + provide the descriptor. The static linker places the relocation + R_AARCH64_TLSDESC on the first GOT slot. The loader will + subsequently fix this up. + + Implementation: + + The handling of TLS symbols is implemented across a number of + different backend functions. The following is a top level view of + what processing is performed where. + + The TLS implementation maintains state information for each TLS + symbol. The state information for local and global symbols is kept + in different places. Global symbols use generic BFD structures while + local symbols use backend specific structures that are allocated and + maintained entirely by the backend. + + The flow: + + elfNN_aarch64_check_relocs() + + This function is invoked for each relocation. + + The TLS relocations R_AARCH64_TLSGD_{ADR_PREL21,ADD_LO12_NC} and + R_AARCH64_TLSDESC_{ADR_PAGE21,LD64_LO12_NC,ADD_LO12_NC} are + spotted. One time creation of local symbol data structures are + created when the first local symbol is seen. + + The reference count for a symbol is incremented. The GOT type for + each symbol is marked as general dynamic. + + elfNN_aarch64_allocate_dynrelocs () + + For each global with positive reference count we allocate a double + GOT slot. For a traditional TLS symbol we allocate space for two + relocation entries on the GOT, for a TLS descriptor symbol we + allocate space for one relocation on the slot. Record the GOT offset + for this symbol. + + elfNN_aarch64_size_dynamic_sections () + + Iterate all input BFDS, look for in the local symbol data structure + constructed earlier for local TLS symbols and allocate them double + GOT slots along with space for a single GOT relocation. Update the + local symbol structure to record the GOT offset allocated. + + elfNN_aarch64_relocate_section () + + Calls elfNN_aarch64_final_link_relocate () + + Emit the relevant TLS relocations against the GOT for each TLS + symbol. For local TLS symbols emit the GOT offset directly. The GOT + relocations are emitted once the first time a TLS symbol is + encountered. The implementation uses the LSB of the GOT offset to + flag that the relevant GOT relocations for a symbol have been + emitted. All of the TLS code that uses the GOT offset needs to take + care to mask out this flag bit before using the offset. + + elfNN_aarch64_final_link_relocate () + + Fixup the R_AARCH64_TLSGD_{ADR_PREL21, ADD_LO12_NC} relocations. */ + +#include "sysdep.h" +#include "bfd.h" +#include "libiberty.h" +#include "libbfd.h" +#include "bfd_stdint.h" +#include "elf-bfd.h" +#include "bfdlink.h" +#include "objalloc.h" +#include "elf/aarch64.h" +#include "elfxx-aarch64.h" + +#define ARCH_SIZE NN + +#if ARCH_SIZE == 64 +#define AARCH64_R(NAME) R_AARCH64_ ## NAME +#define AARCH64_R_STR(NAME) "R_AARCH64_" #NAME +#define HOWTO64(...) HOWTO (__VA_ARGS__) +#define HOWTO32(...) EMPTY_HOWTO (0) +#define LOG_FILE_ALIGN 3 +#endif + +#if ARCH_SIZE == 32 +#define AARCH64_R(NAME) R_AARCH64_P32_ ## NAME +#define AARCH64_R_STR(NAME) "R_AARCH64_P32_" #NAME +#define HOWTO64(...) EMPTY_HOWTO (0) +#define HOWTO32(...) HOWTO (__VA_ARGS__) +#define LOG_FILE_ALIGN 2 +#endif + +#define IS_AARCH64_TLS_RELOC(R_TYPE) \ + ((R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PREL21 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLS_DTPMOD \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLS_DTPREL \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLS_TPREL \ + || IS_AARCH64_TLSDESC_RELOC ((R_TYPE))) + +#define IS_AARCH64_TLSDESC_RELOC(R_TYPE) \ + ((R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD_PREL19 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G1 \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDR \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_CALL \ + || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC) + +#define ELIMINATE_COPY_RELOCS 0 + +/* Return size of a relocation entry. HTAB is the bfd's + elf_aarch64_link_hash_entry. */ +#define RELOC_SIZE(HTAB) (sizeof (ElfNN_External_Rela)) + +/* GOT Entry size - 8 bytes in ELF64 and 4 bytes in ELF32. */ +#define GOT_ENTRY_SIZE (ARCH_SIZE / 8) +#define PLT_ENTRY_SIZE (32) +#define PLT_SMALL_ENTRY_SIZE (16) +#define PLT_TLSDESC_ENTRY_SIZE (32) + +/* Encoding of the nop instruction */ +#define INSN_NOP 0xd503201f + +#define aarch64_compute_jump_table_size(htab) \ + (((htab)->root.srelplt == NULL) ? 0 \ + : (htab)->root.srelplt->reloc_count * GOT_ENTRY_SIZE) + +/* The first entry in a procedure linkage table looks like this + if the distance between the PLTGOT and the PLT is < 4GB use + these PLT entries. Note that the dynamic linker gets &PLTGOT[2] + in x16 and needs to work out PLTGOT[1] by using an address of + [x16,#-GOT_ENTRY_SIZE]. */ +static const bfd_byte elfNN_aarch64_small_plt0_entry[PLT_ENTRY_SIZE] = +{ + 0xf0, 0x7b, 0xbf, 0xa9, /* stp x16, x30, [sp, #-16]! */ + 0x10, 0x00, 0x00, 0x90, /* adrp x16, (GOT+16) */ +#if ARCH_SIZE == 64 + 0x11, 0x0A, 0x40, 0xf9, /* ldr x17, [x16, #PLT_GOT+0x10] */ + 0x10, 0x42, 0x00, 0x91, /* add x16, x16,#PLT_GOT+0x10 */ +#else + 0x11, 0x0A, 0x40, 0xb9, /* ldr w17, [x16, #PLT_GOT+0x8] */ + 0x10, 0x22, 0x00, 0x11, /* add w16, w16,#PLT_GOT+0x8 */ +#endif + 0x20, 0x02, 0x1f, 0xd6, /* br x17 */ + 0x1f, 0x20, 0x03, 0xd5, /* nop */ + 0x1f, 0x20, 0x03, 0xd5, /* nop */ + 0x1f, 0x20, 0x03, 0xd5, /* nop */ +}; + +/* Per function entry in a procedure linkage table looks like this + if the distance between the PLTGOT and the PLT is < 4GB use + these PLT entries. */ +static const bfd_byte elfNN_aarch64_small_plt_entry[PLT_SMALL_ENTRY_SIZE] = +{ + 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */ +#if ARCH_SIZE == 64 + 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */ + 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */ +#else + 0x11, 0x02, 0x40, 0xb9, /* ldr w17, [x16, PLTGOT + n * 4] */ + 0x10, 0x02, 0x00, 0x11, /* add w16, w16, :lo12:PLTGOT + n * 4 */ +#endif + 0x20, 0x02, 0x1f, 0xd6, /* br x17. */ +}; + +static const bfd_byte +elfNN_aarch64_tlsdesc_small_plt_entry[PLT_TLSDESC_ENTRY_SIZE] = +{ + 0xe2, 0x0f, 0xbf, 0xa9, /* stp x2, x3, [sp, #-16]! */ + 0x02, 0x00, 0x00, 0x90, /* adrp x2, 0 */ + 0x03, 0x00, 0x00, 0x90, /* adrp x3, 0 */ +#if ARCH_SIZE == 64 + 0x42, 0x00, 0x40, 0xf9, /* ldr x2, [x2, #0] */ + 0x63, 0x00, 0x00, 0x91, /* add x3, x3, 0 */ +#else + 0x42, 0x00, 0x40, 0xb9, /* ldr w2, [x2, #0] */ + 0x63, 0x00, 0x00, 0x11, /* add w3, w3, 0 */ +#endif + 0x40, 0x00, 0x1f, 0xd6, /* br x2 */ + 0x1f, 0x20, 0x03, 0xd5, /* nop */ + 0x1f, 0x20, 0x03, 0xd5, /* nop */ +}; + +#define elf_info_to_howto elfNN_aarch64_info_to_howto +#define elf_info_to_howto_rel elfNN_aarch64_info_to_howto + +#define AARCH64_ELF_ABI_VERSION 0 + +/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */ +#define ALL_ONES (~ (bfd_vma) 0) + +/* Indexed by the bfd interal reloc enumerators. + Therefore, the table needs to be synced with BFD_RELOC_AARCH64_* + in reloc.c. */ + +static reloc_howto_type elfNN_aarch64_howto_table[] = +{ + EMPTY_HOWTO (0), + + /* Basic data relocations. */ + +#if ARCH_SIZE == 64 + HOWTO (R_AARCH64_NULL, /* type */ + 0, /* rightshift */ + 3, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_AARCH64_NULL", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ +#else + HOWTO (R_AARCH64_NONE, /* type */ + 0, /* rightshift */ + 3, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_AARCH64_NONE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ +#endif + + /* .xword: (S+A) */ + HOWTO64 (AARCH64_R (ABS64), /* type */ + 0, /* rightshift */ + 4, /* size (4 = long long) */ + 64, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (ABS64), /* name */ + FALSE, /* partial_inplace */ + ALL_ONES, /* src_mask */ + ALL_ONES, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* .word: (S+A) */ + HOWTO (AARCH64_R (ABS32), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (ABS32), /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* .half: (S+A) */ + HOWTO (AARCH64_R (ABS16), /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (ABS16), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* .xword: (S+A-P) */ + HOWTO64 (AARCH64_R (PREL64), /* type */ + 0, /* rightshift */ + 4, /* size (4 = long long) */ + 64, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (PREL64), /* name */ + FALSE, /* partial_inplace */ + ALL_ONES, /* src_mask */ + ALL_ONES, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* .word: (S+A-P) */ + HOWTO (AARCH64_R (PREL32), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (PREL32), /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* .half: (S+A-P) */ + HOWTO (AARCH64_R (PREL16), /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (PREL16), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* Group relocations to create a 16, 32, 48 or 64 bit + unsigned data or abs address inline. */ + + /* MOVZ: ((S+A) >> 0) & 0xffff */ + HOWTO (AARCH64_R (MOVW_UABS_G0), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (MOVW_UABS_G0), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* MOVK: ((S+A) >> 0) & 0xffff [no overflow check] */ + HOWTO (AARCH64_R (MOVW_UABS_G0_NC), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (MOVW_UABS_G0_NC), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* MOVZ: ((S+A) >> 16) & 0xffff */ + HOWTO (AARCH64_R (MOVW_UABS_G1), /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (MOVW_UABS_G1), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* MOVK: ((S+A) >> 16) & 0xffff [no overflow check] */ + HOWTO64 (AARCH64_R (MOVW_UABS_G1_NC), /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (MOVW_UABS_G1_NC), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* MOVZ: ((S+A) >> 32) & 0xffff */ + HOWTO64 (AARCH64_R (MOVW_UABS_G2), /* type */ + 32, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (MOVW_UABS_G2), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* MOVK: ((S+A) >> 32) & 0xffff [no overflow check] */ + HOWTO64 (AARCH64_R (MOVW_UABS_G2_NC), /* type */ + 32, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (MOVW_UABS_G2_NC), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* MOVZ: ((S+A) >> 48) & 0xffff */ + HOWTO64 (AARCH64_R (MOVW_UABS_G3), /* type */ + 48, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (MOVW_UABS_G3), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Group relocations to create high part of a 16, 32, 48 or 64 bit + signed data or abs address inline. Will change instruction + to MOVN or MOVZ depending on sign of calculated value. */ + + /* MOV[ZN]: ((S+A) >> 0) & 0xffff */ + HOWTO (AARCH64_R (MOVW_SABS_G0), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (MOVW_SABS_G0), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* MOV[ZN]: ((S+A) >> 16) & 0xffff */ + HOWTO64 (AARCH64_R (MOVW_SABS_G1), /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (MOVW_SABS_G1), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* MOV[ZN]: ((S+A) >> 32) & 0xffff */ + HOWTO64 (AARCH64_R (MOVW_SABS_G2), /* type */ + 32, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (MOVW_SABS_G2), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + +/* Relocations to generate 19, 21 and 33 bit PC-relative load/store + addresses: PG(x) is (x & ~0xfff). */ + + /* LD-lit: ((S+A-P) >> 2) & 0x7ffff */ + HOWTO (AARCH64_R (LD_PREL_LO19), /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 19, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (LD_PREL_LO19), /* name */ + FALSE, /* partial_inplace */ + 0x7ffff, /* src_mask */ + 0x7ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* ADR: (S+A-P) & 0x1fffff */ + HOWTO (AARCH64_R (ADR_PREL_LO21), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (ADR_PREL_LO21), /* name */ + FALSE, /* partial_inplace */ + 0x1fffff, /* src_mask */ + 0x1fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff */ + HOWTO (AARCH64_R (ADR_PREL_PG_HI21), /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (ADR_PREL_PG_HI21), /* name */ + FALSE, /* partial_inplace */ + 0x1fffff, /* src_mask */ + 0x1fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff [no overflow check] */ + HOWTO64 (AARCH64_R (ADR_PREL_PG_HI21_NC), /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (ADR_PREL_PG_HI21_NC), /* name */ + FALSE, /* partial_inplace */ + 0x1fffff, /* src_mask */ + 0x1fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* ADD: (S+A) & 0xfff [no overflow check] */ + HOWTO (AARCH64_R (ADD_ABS_LO12_NC), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 10, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (ADD_ABS_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0x3ffc00, /* src_mask */ + 0x3ffc00, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* LD/ST8: (S+A) & 0xfff */ + HOWTO (AARCH64_R (LDST8_ABS_LO12_NC), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (LDST8_ABS_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xfff, /* src_mask */ + 0xfff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relocations for control-flow instructions. */ + + /* TBZ/NZ: ((S+A-P) >> 2) & 0x3fff */ + HOWTO (AARCH64_R (TSTBR14), /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 14, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TSTBR14), /* name */ + FALSE, /* partial_inplace */ + 0x3fff, /* src_mask */ + 0x3fff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* B.cond: ((S+A-P) >> 2) & 0x7ffff */ + HOWTO (AARCH64_R (CONDBR19), /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 19, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (CONDBR19), /* name */ + FALSE, /* partial_inplace */ + 0x7ffff, /* src_mask */ + 0x7ffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* B: ((S+A-P) >> 2) & 0x3ffffff */ + HOWTO (AARCH64_R (JUMP26), /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (JUMP26), /* name */ + FALSE, /* partial_inplace */ + 0x3ffffff, /* src_mask */ + 0x3ffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* BL: ((S+A-P) >> 2) & 0x3ffffff */ + HOWTO (AARCH64_R (CALL26), /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (CALL26), /* name */ + FALSE, /* partial_inplace */ + 0x3ffffff, /* src_mask */ + 0x3ffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* LD/ST16: (S+A) & 0xffe */ + HOWTO (AARCH64_R (LDST16_ABS_LO12_NC), /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (LDST16_ABS_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xffe, /* src_mask */ + 0xffe, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* LD/ST32: (S+A) & 0xffc */ + HOWTO (AARCH64_R (LDST32_ABS_LO12_NC), /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (LDST32_ABS_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xffc, /* src_mask */ + 0xffc, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* LD/ST64: (S+A) & 0xff8 */ + HOWTO (AARCH64_R (LDST64_ABS_LO12_NC), /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (LDST64_ABS_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xff8, /* src_mask */ + 0xff8, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* LD/ST128: (S+A) & 0xff0 */ + HOWTO (AARCH64_R (LDST128_ABS_LO12_NC), /* type */ + 4, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (LDST128_ABS_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xff0, /* src_mask */ + 0xff0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Set a load-literal immediate field to bits + 0x1FFFFC of G(S)-P */ + HOWTO (AARCH64_R (GOT_LD_PREL19), /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte,1 = short,2 = long) */ + 19, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (GOT_LD_PREL19), /* name */ + FALSE, /* partial_inplace */ + 0xffffe0, /* src_mask */ + 0xffffe0, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* Get to the page for the GOT entry for the symbol + (G(S) - P) using an ADRP instruction. */ + HOWTO (AARCH64_R (ADR_GOT_PAGE), /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (ADR_GOT_PAGE), /* name */ + FALSE, /* partial_inplace */ + 0x1fffff, /* src_mask */ + 0x1fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* LD64: GOT offset G(S) & 0xff8 */ + HOWTO64 (AARCH64_R (LD64_GOT_LO12_NC), /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (LD64_GOT_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xff8, /* src_mask */ + 0xff8, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* LD32: GOT offset G(S) & 0xffc */ + HOWTO32 (AARCH64_R (LD32_GOT_LO12_NC), /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (LD32_GOT_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xffc, /* src_mask */ + 0xffc, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* LD64: GOT offset for the symbol. */ + HOWTO64 (AARCH64_R (LD64_GOTOFF_LO15), /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (LD64_GOTOFF_LO15), /* name */ + FALSE, /* partial_inplace */ + 0x7ff8, /* src_mask */ + 0x7ff8, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* LD32: GOT offset to the page address of GOT table. + (G(S) - PAGE (_GLOBAL_OFFSET_TABLE_)) & 0x5ffc. */ + HOWTO32 (AARCH64_R (LD32_GOTPAGE_LO14), /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (LD32_GOTPAGE_LO14), /* name */ + FALSE, /* partial_inplace */ + 0x5ffc, /* src_mask */ + 0x5ffc, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* LD64: GOT offset to the page address of GOT table. + (G(S) - PAGE (_GLOBAL_OFFSET_TABLE_)) & 0x7ff8. */ + HOWTO64 (AARCH64_R (LD64_GOTPAGE_LO15), /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (LD64_GOTPAGE_LO15), /* name */ + FALSE, /* partial_inplace */ + 0x7ff8, /* src_mask */ + 0x7ff8, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Get to the page for the GOT entry for the symbol + (G(S) - P) using an ADRP instruction. */ + HOWTO (AARCH64_R (TLSGD_ADR_PAGE21), /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSGD_ADR_PAGE21), /* name */ + FALSE, /* partial_inplace */ + 0x1fffff, /* src_mask */ + 0x1fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLSGD_ADR_PREL21), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSGD_ADR_PREL21), /* name */ + FALSE, /* partial_inplace */ + 0x1fffff, /* src_mask */ + 0x1fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* ADD: GOT offset G(S) & 0xff8 [no overflow check] */ + HOWTO (AARCH64_R (TLSGD_ADD_LO12_NC), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSGD_ADD_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xfff, /* src_mask */ + 0xfff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO64 (AARCH64_R (TLSIE_MOVW_GOTTPREL_G1), /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSIE_MOVW_GOTTPREL_G1), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO64 (AARCH64_R (TLSIE_MOVW_GOTTPREL_G0_NC), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSIE_MOVW_GOTTPREL_G0_NC), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLSIE_ADR_GOTTPREL_PAGE21), /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSIE_ADR_GOTTPREL_PAGE21), /* name */ + FALSE, /* partial_inplace */ + 0x1fffff, /* src_mask */ + 0x1fffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO64 (AARCH64_R (TLSIE_LD64_GOTTPREL_LO12_NC), /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSIE_LD64_GOTTPREL_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xff8, /* src_mask */ + 0xff8, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO32 (AARCH64_R (TLSIE_LD32_GOTTPREL_LO12_NC), /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSIE_LD32_GOTTPREL_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xffc, /* src_mask */ + 0xffc, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLSIE_LD_GOTTPREL_PREL19), /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 19, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSIE_LD_GOTTPREL_PREL19), /* name */ + FALSE, /* partial_inplace */ + 0x1ffffc, /* src_mask */ + 0x1ffffc, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO64 (AARCH64_R (TLSLE_MOVW_TPREL_G2), /* type */ + 32, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSLE_MOVW_TPREL_G2), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLSLE_MOVW_TPREL_G1), /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSLE_MOVW_TPREL_G1), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO64 (AARCH64_R (TLSLE_MOVW_TPREL_G1_NC), /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSLE_MOVW_TPREL_G1_NC), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLSLE_MOVW_TPREL_G0), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSLE_MOVW_TPREL_G0), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLSLE_MOVW_TPREL_G0_NC), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSLE_MOVW_TPREL_G0_NC), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLSLE_ADD_TPREL_HI12), /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSLE_ADD_TPREL_HI12), /* name */ + FALSE, /* partial_inplace */ + 0xfff, /* src_mask */ + 0xfff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLSLE_ADD_TPREL_LO12), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSLE_ADD_TPREL_LO12), /* name */ + FALSE, /* partial_inplace */ + 0xfff, /* src_mask */ + 0xfff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLSLE_ADD_TPREL_LO12_NC), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSLE_ADD_TPREL_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xfff, /* src_mask */ + 0xfff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLSDESC_LD_PREL19), /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 19, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSDESC_LD_PREL19), /* name */ + FALSE, /* partial_inplace */ + 0x0ffffe0, /* src_mask */ + 0x0ffffe0, /* dst_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLSDESC_ADR_PREL21), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSDESC_ADR_PREL21), /* name */ + FALSE, /* partial_inplace */ + 0x1fffff, /* src_mask */ + 0x1fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* Get to the page for the GOT entry for the symbol + (G(S) - P) using an ADRP instruction. */ + HOWTO (AARCH64_R (TLSDESC_ADR_PAGE21), /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSDESC_ADR_PAGE21), /* name */ + FALSE, /* partial_inplace */ + 0x1fffff, /* src_mask */ + 0x1fffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* LD64: GOT offset G(S) & 0xff8. */ + HOWTO64 (AARCH64_R (TLSDESC_LD64_LO12_NC), /* type */ + 3, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSDESC_LD64_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xff8, /* src_mask */ + 0xff8, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* LD32: GOT offset G(S) & 0xffc. */ + HOWTO32 (AARCH64_R (TLSDESC_LD32_LO12_NC), /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSDESC_LD32_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xffc, /* src_mask */ + 0xffc, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* ADD: GOT offset G(S) & 0xfff. */ + HOWTO (AARCH64_R (TLSDESC_ADD_LO12_NC), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSDESC_ADD_LO12_NC), /* name */ + FALSE, /* partial_inplace */ + 0xfff, /* src_mask */ + 0xfff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO64 (AARCH64_R (TLSDESC_OFF_G1), /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSDESC_OFF_G1), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO64 (AARCH64_R (TLSDESC_OFF_G0_NC), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSDESC_OFF_G0_NC), /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO64 (AARCH64_R (TLSDESC_LDR), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSDESC_LDR), /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0x0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO64 (AARCH64_R (TLSDESC_ADD), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSDESC_ADD), /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0x0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLSDESC_CALL), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSDESC_CALL), /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0x0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (COPY), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (COPY), /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (GLOB_DAT), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (GLOB_DAT), /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (JUMP_SLOT), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (JUMP_SLOT), /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (RELATIVE), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (RELATIVE), /* name */ + TRUE, /* partial_inplace */ + ALL_ONES, /* src_mask */ + ALL_ONES, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLS_DTPMOD), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ +#if ARCH_SIZE == 64 + AARCH64_R_STR (TLS_DTPMOD64), /* name */ +#else + AARCH64_R_STR (TLS_DTPMOD), /* name */ +#endif + FALSE, /* partial_inplace */ + 0, /* src_mask */ + ALL_ONES, /* dst_mask */ + FALSE), /* pc_reloffset */ + + HOWTO (AARCH64_R (TLS_DTPREL), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ +#if ARCH_SIZE == 64 + AARCH64_R_STR (TLS_DTPREL64), /* name */ +#else + AARCH64_R_STR (TLS_DTPREL), /* name */ +#endif + FALSE, /* partial_inplace */ + 0, /* src_mask */ + ALL_ONES, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLS_TPREL), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ +#if ARCH_SIZE == 64 + AARCH64_R_STR (TLS_TPREL64), /* name */ +#else + AARCH64_R_STR (TLS_TPREL), /* name */ +#endif + FALSE, /* partial_inplace */ + 0, /* src_mask */ + ALL_ONES, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (TLSDESC), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (TLSDESC), /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + ALL_ONES, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (AARCH64_R (IRELATIVE), /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + AARCH64_R_STR (IRELATIVE), /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + ALL_ONES, /* dst_mask */ + FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (0), +}; + +static reloc_howto_type elfNN_aarch64_howto_none = + HOWTO (R_AARCH64_NONE, /* type */ + 0, /* rightshift */ + 3, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_AARCH64_NONE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE); /* pcrel_offset */ + +/* Given HOWTO, return the bfd internal relocation enumerator. */ + +static bfd_reloc_code_real_type +elfNN_aarch64_bfd_reloc_from_howto (reloc_howto_type *howto) +{ + const int size + = (int) ARRAY_SIZE (elfNN_aarch64_howto_table); + const ptrdiff_t offset + = howto - elfNN_aarch64_howto_table; + + if (offset > 0 && offset < size - 1) + return BFD_RELOC_AARCH64_RELOC_START + offset; + + if (howto == &elfNN_aarch64_howto_none) + return BFD_RELOC_AARCH64_NONE; + + return BFD_RELOC_AARCH64_RELOC_START; +} + +/* Given R_TYPE, return the bfd internal relocation enumerator. */ + +static bfd_reloc_code_real_type +elfNN_aarch64_bfd_reloc_from_type (unsigned int r_type) +{ + static bfd_boolean initialized_p = FALSE; + /* Indexed by R_TYPE, values are offsets in the howto_table. */ + static unsigned int offsets[R_AARCH64_end]; + + if (initialized_p == FALSE) + { + unsigned int i; + + for (i = 1; i < ARRAY_SIZE (elfNN_aarch64_howto_table) - 1; ++i) + if (elfNN_aarch64_howto_table[i].type != 0) + offsets[elfNN_aarch64_howto_table[i].type] = i; + + initialized_p = TRUE; + } + + if (r_type == R_AARCH64_NONE || r_type == R_AARCH64_NULL) + return BFD_RELOC_AARCH64_NONE; + + /* PR 17512: file: b371e70a. */ + if (r_type >= R_AARCH64_end) + { + _bfd_error_handler (_("Invalid AArch64 reloc number: %d"), r_type); + bfd_set_error (bfd_error_bad_value); + return BFD_RELOC_AARCH64_NONE; + } + + return BFD_RELOC_AARCH64_RELOC_START + offsets[r_type]; +} + +struct elf_aarch64_reloc_map +{ + bfd_reloc_code_real_type from; + bfd_reloc_code_real_type to; +}; + +/* Map bfd generic reloc to AArch64-specific reloc. */ +static const struct elf_aarch64_reloc_map elf_aarch64_reloc_map[] = +{ + {BFD_RELOC_NONE, BFD_RELOC_AARCH64_NONE}, + + /* Basic data relocations. */ + {BFD_RELOC_CTOR, BFD_RELOC_AARCH64_NN}, + {BFD_RELOC_64, BFD_RELOC_AARCH64_64}, + {BFD_RELOC_32, BFD_RELOC_AARCH64_32}, + {BFD_RELOC_16, BFD_RELOC_AARCH64_16}, + {BFD_RELOC_64_PCREL, BFD_RELOC_AARCH64_64_PCREL}, + {BFD_RELOC_32_PCREL, BFD_RELOC_AARCH64_32_PCREL}, + {BFD_RELOC_16_PCREL, BFD_RELOC_AARCH64_16_PCREL}, +}; + +/* Given the bfd internal relocation enumerator in CODE, return the + corresponding howto entry. */ + +static reloc_howto_type * +elfNN_aarch64_howto_from_bfd_reloc (bfd_reloc_code_real_type code) +{ + unsigned int i; + + /* Convert bfd generic reloc to AArch64-specific reloc. */ + if (code < BFD_RELOC_AARCH64_RELOC_START + || code > BFD_RELOC_AARCH64_RELOC_END) + for (i = 0; i < ARRAY_SIZE (elf_aarch64_reloc_map); i++) + if (elf_aarch64_reloc_map[i].from == code) + { + code = elf_aarch64_reloc_map[i].to; + break; + } + + if (code > BFD_RELOC_AARCH64_RELOC_START + && code < BFD_RELOC_AARCH64_RELOC_END) + if (elfNN_aarch64_howto_table[code - BFD_RELOC_AARCH64_RELOC_START].type) + return &elfNN_aarch64_howto_table[code - BFD_RELOC_AARCH64_RELOC_START]; + + if (code == BFD_RELOC_AARCH64_NONE) + return &elfNN_aarch64_howto_none; + + return NULL; +} + +static reloc_howto_type * +elfNN_aarch64_howto_from_type (unsigned int r_type) +{ + bfd_reloc_code_real_type val; + reloc_howto_type *howto; + +#if ARCH_SIZE == 32 + if (r_type > 256) + { + bfd_set_error (bfd_error_bad_value); + return NULL; + } +#endif + + if (r_type == R_AARCH64_NONE) + return &elfNN_aarch64_howto_none; + + val = elfNN_aarch64_bfd_reloc_from_type (r_type); + howto = elfNN_aarch64_howto_from_bfd_reloc (val); + + if (howto != NULL) + return howto; + + bfd_set_error (bfd_error_bad_value); + return NULL; +} + +static void +elfNN_aarch64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc, + Elf_Internal_Rela *elf_reloc) +{ + unsigned int r_type; + + r_type = ELFNN_R_TYPE (elf_reloc->r_info); + bfd_reloc->howto = elfNN_aarch64_howto_from_type (r_type); +} + +static reloc_howto_type * +elfNN_aarch64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) +{ + reloc_howto_type *howto = elfNN_aarch64_howto_from_bfd_reloc (code); + + if (howto != NULL) + return howto; + + bfd_set_error (bfd_error_bad_value); + return NULL; +} + +static reloc_howto_type * +elfNN_aarch64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 1; i < ARRAY_SIZE (elfNN_aarch64_howto_table) - 1; ++i) + if (elfNN_aarch64_howto_table[i].name != NULL + && strcasecmp (elfNN_aarch64_howto_table[i].name, r_name) == 0) + return &elfNN_aarch64_howto_table[i]; + + return NULL; +} + +#define TARGET_LITTLE_SYM aarch64_elfNN_le_vec +#define TARGET_LITTLE_NAME "elfNN-littleaarch64" +#define TARGET_BIG_SYM aarch64_elfNN_be_vec +#define TARGET_BIG_NAME "elfNN-bigaarch64" + +/* The linker script knows the section names for placement. + The entry_names are used to do simple name mangling on the stubs. + Given a function name, and its type, the stub can be found. The + name can be changed. The only requirement is the %s be present. */ +#define STUB_ENTRY_NAME "__%s_veneer" + +/* The name of the dynamic interpreter. This is put in the .interp + section. */ +#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1" + +#define AARCH64_MAX_FWD_BRANCH_OFFSET \ + (((1 << 25) - 1) << 2) +#define AARCH64_MAX_BWD_BRANCH_OFFSET \ + (-((1 << 25) << 2)) + +#define AARCH64_MAX_ADRP_IMM ((1 << 20) - 1) +#define AARCH64_MIN_ADRP_IMM (-(1 << 20)) + +static int +aarch64_valid_for_adrp_p (bfd_vma value, bfd_vma place) +{ + bfd_signed_vma offset = (bfd_signed_vma) (PG (value) - PG (place)) >> 12; + return offset <= AARCH64_MAX_ADRP_IMM && offset >= AARCH64_MIN_ADRP_IMM; +} + +static int +aarch64_valid_branch_p (bfd_vma value, bfd_vma place) +{ + bfd_signed_vma offset = (bfd_signed_vma) (value - place); + return (offset <= AARCH64_MAX_FWD_BRANCH_OFFSET + && offset >= AARCH64_MAX_BWD_BRANCH_OFFSET); +} + +static const uint32_t aarch64_adrp_branch_stub [] = +{ + 0x90000010, /* adrp ip0, X */ + /* R_AARCH64_ADR_HI21_PCREL(X) */ + 0x91000210, /* add ip0, ip0, :lo12:X */ + /* R_AARCH64_ADD_ABS_LO12_NC(X) */ + 0xd61f0200, /* br ip0 */ +}; + +static const uint32_t aarch64_long_branch_stub[] = +{ +#if ARCH_SIZE == 64 + 0x58000090, /* ldr ip0, 1f */ +#else + 0x18000090, /* ldr wip0, 1f */ +#endif + 0x10000011, /* adr ip1, #0 */ + 0x8b110210, /* add ip0, ip0, ip1 */ + 0xd61f0200, /* br ip0 */ + 0x00000000, /* 1: .xword or .word + R_AARCH64_PRELNN(X) + 12 + */ + 0x00000000, +}; + +static const uint32_t aarch64_erratum_835769_stub[] = +{ + 0x00000000, /* Placeholder for multiply accumulate. */ + 0x14000000, /* b